Android申请地理位置时的流程及源代码分析

来源:互联网 发布:苹果mac怎么压缩文件 编辑:程序博客网 时间:2024/05/18 19:19

1.首先看一下在android应用中是如何获取Location的

      LocationManager locationManager;       String serviceName = Context.LOCATION_SERVICE;       locationManager = (LocationManager) this.getSystemService(serviceName);    // 查找到服务信息       Criteria criteria = new Criteria();  //定义标准       criteria.setAccuracy(Criteria.ACCURACY_FINE); // 高精度       criteria.setAltitudeRequired(false);       criteria.setBearingRequired(false);       criteria.setCostAllowed(true);       criteria.setPowerRequirement(Criteria.POWER_LOW); // 低功耗       String provider = locationManager.getBestProvider(criteria, true); // 获取最好的provider,就是在此时检测权限的       Location location = locationManager.getLastKnownLocation(provider); // 通过GPS获取位置       updateToNewLocation(location);       // 设置监听器,自动更新的最小时间为间隔N秒(1秒为1*1000,这样写主要为了方便)或最小位移变化超过N米       locationManager.requestLocationUpdates(provider, 100 * 1000, 500,               locationListener);

首先通过getSystemService找到LocationManager服务,然后设定需要的地理位置的一些标准。然后通过LocationManager中的getBestProvider函数调用LocationManagerService.java中的getBestProvider函数来找到最好的Provider,其中Provider有四种:
1)NETWORK_PROVIDER:通过信号塔和wifi接入点来定位
2)GPS_PROVIDER:需要ACCESS_FINE_LOCATION权限,是通过卫星定位
3)PASSIVE_PROVIDER:需要ACCESS_FINE_LOCATION权限
4)FUSED_PROVIDER:融合所有的位置信息提供最佳的地理位置

2.下面来看一下getBestProvider函数

    public String getBestProvider(Criteria criteria, boolean enabledOnly) {        String result = null;        List<String> providers = getProviders(criteria, enabledOnly);        if (!providers.isEmpty()) {            result = pickBest(providers);            if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);            return result;        }            providers = getProviders(null, enabledOnly);        if (!providers.isEmpty()) {            result = pickBest(providers);            if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);            return result;        }            if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);        return null;    }    

首先通过根据标准Criteria通过getProviders()方法查找所有的符合的providers,如果providers不为空,那么通过pickBest函数,在providers列表中选择一个最好的provider,pickBest函数如下:

    private String pickBest(List<String> providers) {        if (providers.contains(LocationManager.GPS_PROVIDER)) {            return LocationManager.GPS_PROVIDER;        } else if (providers.contains(LocationManager.NETWORK_PROVIDER)) {            return LocationManager.NETWORK_PROVIDER;        } else {            return providers.get(0);        }        }    

意思就是如果providers列表中存在GPS则首先选择GPS,如果没有GPS,则首先选择NET_PROVIDER,如果两个都么有,那么就选择providers中的第一个。(接上一段)如果providers列表为空,那么则通过getProviders(null, enabledOnly)来获取无标准的providers,接着做上面同样的事情。如果此时providers列表还是为空,那么返回null。

3.getProviders函数

    public List<String> getProviders(Criteria criteria, boolean enabledOnly) {        int allowedResolutionLevel = getCallerAllowedResolutionLevel();        ArrayList<String> out;        int uid = Binder.getCallingUid();;        long identity = Binder.clearCallingIdentity();        try {            synchronized (mLock) {                out = new ArrayList<String>(mProviders.size());                for (LocationProviderInterface provider : mProviders) {                    String name = provider.getName();                    if (LocationManager.FUSED_PROVIDER.equals(name)) {                        continue;                    }                    if (allowedResolutionLevel >= getMinimumResolutionLevelForProviderUse(name)) {                        if (enabledOnly && !isAllowedByUserSettingsLocked(name, uid)) {                            continue;                        }                        if (criteria != null && !LocationProvider.propertiesMeetCriteria(                                name, provider.getProperties(), criteria)) {                            continue;                        }                        out.add(name);                    }                }            }        } finally {            Binder.restoreCallingIdentity(identity);        }        if (D) Log.d(TAG, "getProviders()=" + out);        return out;    }

该函数首先通过getCallerAllowedResolutionLevel()函数来获取应用允许的位置信息分辨率(即权限审查)。getCallerAllowedResolutionLevel()函数如下:

    private int getCallerAllowedResolutionLevel() {        return getAllowedResolutionLevel(Binder.getCallingPid(), Binder.getCallingUid());    }

该函数简单的调用了getAllowedResolutionLevel(),函数如下:

    private int getAllowedResolutionLevel(int pid, int uid) {        if (mContext.checkPermission(android.Manifest.permission.ACCESS_FINE_LOCATION,                pid, uid) == PackageManager.PERMISSION_GRANTED) {            return RESOLUTION_LEVEL_FINE;        } else if (mContext.checkPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION,                pid, uid) == PackageManager.PERMISSION_GRANTED) {            return RESOLUTION_LEVEL_COARSE;        } else {            return RESOLUTION_LEVEL_NONE;        }    }

分析以下这张图:
这里写图片描述
图中ContextImpl类和ContextWrapper类中checkPermission函数如下:
ContextImpl类中的checkPermission函数如下:经分析可知最终调用的还是ActivityManagerService类中的checkPermission()。

    public int checkPermission(String permission, int pid, int uid) {        if (permission == null) {            throw new IllegalArgumentException("permission is null");        }        try {            return ActivityManagerNative.getDefault().checkPermission(                    permission, pid, uid);        } catch (RemoteException e) {            return PackageManager.PERMISSION_DENIED;        }    }

ContextWrapper类中checkPermission函数如下:其中mBase是Context的实例,其实调用的是ContextImpl类中的checkPermission函数。

    public int checkPermission(String permission, int pid, int uid) {        return mBase.checkPermission(permission, pid, uid);    }

所以,最终调用checkPermission函数为PackageManagerService.java中的checkPermission函数。getAllowedResolutionLevel()进行权限检查后回去应用申请的权限,如果应用细粒度和粗粒度的权限都申请了,那么返回细粒度的分辨率即可。
对权限就分析到这吧

0 0
原创粉丝点击