由于大陆禁止使用Google定位服务。因此我们需要自己研发一款基于网络与基站的LBS应用。
但是由于Google并没有开放networklocation.apk的源码。因此我们需要自己动手山寨一个
既然是山寨了,那肯定要走反向工程了。
我们先看看LBS服务的基础LocationManagerService是如何启动网络定位服务的
先看LocationManagerService 的构造方法
public LocationManagerService(Context context) { super(); mContext = context; Resources resources = context.getResources(); mNetworkLocationProviderPackageName = resources.getString( com.android.internal.R.string.config_networkLocationProviderPackageName); mGeocodeProviderPackageName = resources.getString( com.android.internal.R.string.config_geocodeProviderPackageName); mPackageMonitor.register(context, null, true); if (LOCAL_LOGV) { Slog.v(TAG, "Constructed LocationManager Service"); } } |
mNetworkLocationProviderPackageName 这个就是网络定位服务APK的name.如果用的是国际版的ROM的话 这个name应该是networklocation
我们继续
其实,LocationManagerService 是一个线程类,除了构造函数以外,在其 run 方法中又完成了另外一部分的初始化工作,主要是调用其 initialize 方法。 在 initialize 方法中调用了 loadProviders 方法,loadProviders 这个方法中完成了 Location Provider 的加载工作。 该方法又经过同步加锁以及异常的包装,最终的实现方法是 _loadProvidersLocked。 _loadProvidersLocked 方法的代码如下所示:
private void _loadProvidersLocked() {
// Attempt to load "real" providers first
if (GpsLocationProvider.isSupported()) {
// Create a gps location provider
GpsLocationProvider gpsProvider =
new GpsLocationProvider(mContext, this);
mGpsStatusProvider = gpsProvider.getGpsStatusProvider();
mNetInitiatedListener = gpsProvider.getNetInitiatedListener();
addProvider(gpsProvider);
mGpsLocationProvider = gpsProvider;
}
// create a passive location provider, which is always enabled
PassiveProvider passiveProvider = new PassiveProvider(this);
addProvider(passiveProvider);
mEnabledProviders.add(passiveProvider.getName());
// initialize external network location and geocoder services.
// The initial value of mNetworkLocationProviderPackageName and
// mGeocodeProviderPackageName is just used to determine what
// signatures future mNetworkLocationProviderPackageName and
// mGeocodeProviderPackageName packages must have. So alternate
// providers can be installed under a different package name
// so long as they have the same signature as the original
// provider packages.
if (mNetworkLocationProviderPackageName != null) {
String packageName = findBestPackage(
LocationProviderProxy.SERVICE_ACTION,
mNetworkLocationProviderPackageName);
if (packageName != null) {
mNetworkLocationProvider = new LocationProviderProxy(
mContext,
LocationManager.NETWORK_PROVIDER,
packageName, mLocationHandler);
mNetworkLocationProviderPackageName = packageName;
addProvider(mNetworkLocationProvider);
}
}
if (mGeocodeProviderPackageName != null) {
String packageName = findBestPackage(
GeocoderProxy.SERVICE_ACTION,
mGeocodeProviderPackageName);
if (packageName != null) {
mGeocodeProvider =
new GeocoderProxy(mContext, packageName);
mGeocodeProviderPackageName = packageName;
}
}
updateProvidersLocked();
}
|
mNetworkLocationProvider 这个就是我们要找的
代码里是根据 mNetworkLocationProviderPackageName 字段创建 LocationProviderProxy 对象。(在创建 LocationProviderProxy 的时候,packageName 参数是依赖于 mNetworkLocationProviderPackageName 的。这个字段是在 LocationManagerService 的构造函数中初始化的。)
既然提到了LocationProviderProxy,那我们就继续跟踪下去。
public LocationProviderProxy(Context context, String name, StringpackageName,
Handler handler) { mContext = context; mName = name; mIntent = new Intent(SERVICE_ACTION); mHandler = handler; reconnect(packageName); } /** Bind to service. Will reconnect if already connected */ public void reconnect(String packageName) { synchronized (mMutex) { if (mServiceConnection != null) { mContext.unbindService(mServiceConnection); } mServiceConnection = new Connection(); mIntent.setPackage(packageName); mContext.bindService(mIntent, mServiceConnection, Context.BIND_AUTO_CREATE | Context.BIND_NOT_FOREGROUND | Context.BIND_ALLOW_OOM_MANAGEMENT); } } |
bindService o(∩∩)o...哈哈 看到这里我们就大概上知道该怎么办了。
我们自己要实现的networklocation首先需要是一个service,并且需要实现onBind接口。
那下面的问题是IBinder在那里呢
我们继续看LocationProviderProxy
private class Connection implements ServiceConnection, Runnable {
private ILocationProvider mProvider;
// for caching requiresNetwork, requiresSatellite, etc.
private DummyLocationProvider mCachedAttributes; // synchronized by mMutex
public void onServiceConnected(ComponentName className, IBinder service) {
synchronized (this) {
mProvider = ILocationProvider.Stub.asInterface(service);
if (mProvider != null) {
mHandler.post(this);
}
}
}
|
LocationManagerService通信的接口类
但是我们不能直接使用ILocationProvider。我们为了编码方便可以使用android提供给我们的gift
frameworks/base/location/lib/java/com/android/location/provider/LocationProvider.java
现在我们可以开始架构我们自己的networklocation.apk了。权且叫它NewLBSLocation.apk吧
我们需要以下几个类(以下只是简单实现)
NewLBSLocationService------------继承自android service,这个是整个APK的入口类,实现onBind接口
NewLBSLocationProvider------------继承自LocationProvider,这个主要是实现与
LocationManagerService的通信接口
NewLBSLocationUtil--------------通过handler与NewLBSLocationProvider通信,在这个类中监听基站与WIFI热点的变化,然后将相关信息发送给定位服务器获取相关位置location,然后通过一系列算法优化location.