安卓6.0权限处理在项目中的实践
2016-01-31 00:09
363 查看
前言
相关开源项目
使用eclipse和grant开源库权限管理
更新api到23
获得v4包
项目实战开发
默认许可权限无需授权
总结和建议
由于公司是使用eclipse开发的也是醉了,然后呢网上对安卓6.0的权限有了还几个开源框架
使用标注的方式,动态生成类处理运行时权限,目前还不支持嵌套Fragment。
RxPermissions
基于RxJava的运行时权限检测框架
Grant
简化运行时权限的处理,比较灵活
android-RuntimePermissions
Google官方的例子
当然我们选择23.1.1下面的android-support-v4.jar,放入你项目的libs下面:
哈哈为什么要这样干呢?因为在里面我们会用到
这样做的话,代码会比较复杂,而在support library v4中,已经为我们准备好了更简单的方法,我们只需要采用library包中的方法来替换上面的方法即可:
- ContextCompat.checkSelfPermission()
不管当前运行的Android版本是多少,该方法都可以正确的方法权限的许可情况,允许或者拒绝.
- ActivityCompat.requestPermissions()
当该方法在6.0之前被调用时,onRequestPermissionsResult回调方法会立即被调用,并返回给你正确的PERMISSION_GRANTED 或者
PERMISSION_DENIED结果.
ActivityCompat.shouldShowRequestPermissionRationale()
在6.0之前调用该方法,将总会返回false.
切记,你应该总是使用这些方法来取代Activity自身的checkSelfPermission,requestPermissions和shouldShowRequestPermissionsRationale方法.这样,在不同的Android版本中,你的代码将总会完美的运行.
ContextCompat.checkSelfPermission();
ActivityCompat.requestPermissions();
上面的方法是v4包下的方法,然后呢低版本的v4包还不具有这样的方法,所以as的项目放在eclipse也是相当的蛋疼。
接下我们就实战项目了,
上面呢就 是权限的类型了,简单翻译下注释就是 用枚举对应3种状态:
已授权,授权失败,未发现的权限。
再看下我们的PermissionsManager.java
接下来我们来看PermissionsResultAction.java
好了,最后我们就来使用权限管理:
// 先对app获取所有需要的授权(6.0需要去获取权限)
grantPermissions();
上面呢 我们在程序一开始呢就去授权所有的清单里面的权限,你会看到和ios一样的权限dialog提示,这里呢我们直接来图片展示下。
如下图所示:
接下来我们要去通知权限授权的改变
这里呢我们以百度定位的例子来使用:
我们先来判断定位权限是否已授权成功:
接下来我们根据是否授权成功来进行相关的操作:
根据定位需要的权限去授权
当然还有一些权限你无须去判断:
android.permission.ACCESS_LOCATION_EXTRA_COMMANDS
android.permission.ACCESS_NETWORK_STATE
android.permission.ACCESS_NOTIFICATION_POLICY
android.permission.ACCESS_WIFI_STATE
android.permission.ACCESS_WIMAX_STATE
android.permission.BLUETOOTH
android.permission.BLUETOOTH_ADMIN
android.permission.BROADCAST_STICKY
android.permission.CHANGE_NETWORK_STATE
android.permission.CHANGE_WIFI_MULTICAST_STATE
android.permission.CHANGE_WIFI_STATE
android.permission.CHANGE_WIMAX_STATE
android.permission.DISABLE_KEYGUARD
android.permission.EXPAND_STATUS_BAR
android.permission.FLASHLIGHT
android.permission.GET_ACCOUNTS
android.permission.GET_PACKAGE_SIZE
android.permission.INTERNET
android.permission.KILL_BACKGROUND_PROCESSES
android.permission.MODIFY_AUDIO_SETTINGS
android.permission.NFC
android.permission.READ_SYNC_SETTINGS
android.permission.READ_SYNC_STATS
android.permission.RECEIVE_BOOT_COMPLETED
android.permission.REORDER_TASKS
android.permission.REQUEST_INSTALL_PACKAGES
android.permission.SET_TIME_ZONE
android.permission.SET_WALLPAPER
android.permission.SET_WALLPAPER_HINTS
android.permission.SUBSCRIBED_FEEDS_READ
android.permission.TRANSMIT_IR
android.permission.USE_FINGERPRINT
android.permission.VIBRATE
android.permission.WAKE_LOCK
android.permission.WRITE_SYNC_SETTINGS
com.android.alarm.permission.SET_ALARM
com.android.launcher.permission.INSTALL_SHORTCUT
com.android.launcher.permission.UNINSTALL_SHORTCUT
这些权限和以前一样使用,你无需检查它们是否被撤销了
好消息是需要进行动态申请的权限是少量的,大部分常用的权限是默认获得许可,并不需要你处理的.总而言之,你只需要修改一小部分代码来完成适配工作.
在这里给出两个建议:
1.优先对重要的部分进行适配,确保不会出现崩溃问题.
2.在完成适配工作前,不要将应用的targetSdkVersion设为23,尤其是在使用AndroidStudio创建新工程的时候,记得手动修改一下工程的targetSdkVersion,因为AndroidStudio会默认使用最新的SDK版本.
说到修改代码,我必须承认工作量很大.如果之前的架构设计不合理的话,你可能需要花费一些时间来重新设计了,就像之前说的,我们别无选择,除了去做好它.
我建议你列出应用的功能所依赖的所有的权限,然后考虑如果权限被拒绝,怎样使你的应用的功能尽可能可用,并考虑好如果部分权限被拒绝的情况下,你应该怎么做.恩,这也很复杂,最好能记录好各种情况.
对于安卓6.0的权限运行问题,你可移步Android 6.0 运行时权限处理
好累啊,一不小心到12点,睡觉,加油吧。第一次使用markDown感觉好辛苦,写个东西都
相关开源项目
使用eclipse和grant开源库权限管理
更新api到23
获得v4包
项目实战开发
默认许可权限无需授权
总结和建议
前言
最近公司的app说装在安卓6.0的系统上程序直接崩溃了,然后呢crash日 志也没有捕获到,感觉好烦人因为公司压根就没有安卓6.0的测试机,最后呢我还是用genymotion来搞,由于用到了so库以前下载的那个jar也不知怎的5.0就运行不通过了,然后今天那到处弄Genymotion-ARM-Translation.zip,最后终于还是可以了。由于公司是使用eclipse开发的也是醉了,然后呢网上对安卓6.0的权限有了还几个开源框架
相关开源项目
PermissionsDispatcher使用标注的方式,动态生成类处理运行时权限,目前还不支持嵌套Fragment。
RxPermissions
基于RxJava的运行时权限检测框架
Grant
简化运行时权限的处理,比较灵活
android-RuntimePermissions
Google官方的例子
使用eclipse和grant开源库权限管理
1. 更新api到23
这里我们选择使用grant来进行项目的演示,因为是使用eclipse来开发,所以还是和android studio里面的还是有很多的区别,我们genymotion的6.0打开 ,因为是6.0系统的开发,所以呢我们的api的target 必须是23,如果不是呢那就麻烦你去update下。2. 获得v4包
不多扯了,去你的sdk目录下拷贝出v4包放在你工程目录的libs下,不要问为什么因为在接下来的 项目里面需要用到。如下图目录图:当然我们选择23.1.1下面的android-support-v4.jar,放入你项目的libs下面:
哈哈为什么要这样干呢?因为在里面我们会用到
这样做的话,代码会比较复杂,而在support library v4中,已经为我们准备好了更简单的方法,我们只需要采用library包中的方法来替换上面的方法即可:
- ContextCompat.checkSelfPermission()
不管当前运行的Android版本是多少,该方法都可以正确的方法权限的许可情况,允许或者拒绝.
- ActivityCompat.requestPermissions()
当该方法在6.0之前被调用时,onRequestPermissionsResult回调方法会立即被调用,并返回给你正确的PERMISSION_GRANTED 或者
PERMISSION_DENIED结果.
ActivityCompat.shouldShowRequestPermissionRationale()
在6.0之前调用该方法,将总会返回false.
切记,你应该总是使用这些方法来取代Activity自身的checkSelfPermission,requestPermissions和shouldShowRequestPermissionsRationale方法.这样,在不同的Android版本中,你的代码将总会完美的运行.
ContextCompat.checkSelfPermission();
ActivityCompat.requestPermissions();
上面的方法是v4包下的方法,然后呢低版本的v4包还不具有这样的方法,所以as的项目放在eclipse也是相当的蛋疼。
接下我们就实战项目了,
3. 项目实战开发
不多扯,来看代码:[code]package com.richerpay.ryshop.permissions; /** * Enum class to handle the different states * of permissions since the PackageManager only * has a granted and denied state. */ enum Permissions { GRANTED, DENIED, NOT_FOUND }
上面呢就 是权限的类型了,简单翻译下注释就是 用枚举对应3种状态:
已授权,授权失败,未发现的权限。
再看下我们的PermissionsManager.java
[code]package com.richerpay.ryshop.permissions; import android.Manifest; import android.app.Activity; import android.content.Context; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.os.Build; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.v4.app.ActivityCompat; import android.support.v4.app.Fragment; import android.util.Log; import java.lang.ref.WeakReference; import java.lang.reflect.Field; import java.util.ArrayList; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Set; /** * 权限管理类 */ public class PermissionsManager { private static final String TAG = PermissionsManager.class.getSimpleName(); private final Set<String> mPendingRequests = new HashSet<String>(1); private final Set<String> mPermissions = new HashSet<String>(1); private final List<WeakReference<PermissionsResultAction>> mPendingActions = new ArrayList<WeakReference<PermissionsResultAction>>(1); private static PermissionsManager mInstance = null; public static PermissionsManager getInstance() { if (mInstance == null) { mInstance = new PermissionsManager(); } return mInstance; } private PermissionsManager() { initializePermissionsMap(); } /** * 此方法使用反射来读取清单类中的所有权限。 *因为一些权限不存在于旧版本的安卓系统中, *因为他们不存在,他们将被拒绝时,你检查是否有权限 *因为一个新的权限,往往是补充,那里没有以前的 *所需的许可。我们初始化一组可用的权限,并检查组 *检查是否有权限,当我们被拒绝时权限仍然不存在 * */ private synchronized void initializePermissionsMap() { Field[] fields = Manifest.permission.class.getFields(); for (Field field : fields) { String name = null; try { name = (String) field.get(""); } catch (IllegalAccessException e) { Log.e(TAG, "Could not access field", e); } mPermissions.add(name); } } /** * 此方法检索在应用程序清单中声明的所有权限。 * 它返回一个非空数组,可以声明的权限。 * * @param 检查我们需要哪些权限 * @return 返回在应用程序清单中声明的非空数组 */ @NonNull private synchronized String[] getManifestPermissions(@NonNull final Activity activity) { PackageInfo packageInfo = null; List<String> list = new ArrayList<String>(1); try { Log.d(TAG, activity.getPackageName()); packageInfo = activity.getPackageManager().getPackageInfo(activity.getPackageName(), PackageManager.GET_PERMISSIONS); } catch (PackageManager.NameNotFoundException e) { Log.e(TAG, "A problem occurred when retrieving permissions", e); } if (packageInfo != null) { String[] permissions = packageInfo.requestedPermissions; if (permissions != null) { for (String perm : permissions) { Log.d(TAG, "Manifest contained permission: " + perm); list.add(perm); } } } return list.toArray(new String[list.size()]); } /** * 在permissionsresultaction对象,它将变更通知这些权限 * @param 权限所需的操作的权限。 * @param 将 动作添加到当前正在执行的动作列表中。 */ private synchronized void addPendingAction(@NonNull String[] permissions, @Nullable PermissionsResultAction action) { if (action == null) { return; } action.registerPermissions(permissions); mPendingActions.add(new WeakReference<PermissionsResultAction>(action)); } /** * 删除从队列中等待的动作和执行该动作 * @param 移除动作 */ private synchronized void removePendingAction(@Nullable PermissionsResultAction action) { for (Iterator<WeakReference<PermissionsResultAction>> iterator = mPendingActions.iterator(); iterator.hasNext(); ) { WeakReference<PermissionsResultAction> weakRef = iterator.next(); if (weakRef.get() == action || weakRef.get() == null) { iterator.remove(); } } } /** *这个静态方法可以用来检查你是否有一个特定的权限。 * * @param 检查权限的上下文对象 * @param 要检查的权限 * @return 返回是否授权了此权限 */ public synchronized boolean hasPermission(@Nullable Context context, @NonNull String permission) { return context != null && (ActivityCompat.checkSelfPermission(context, permission) == PackageManager.PERMISSION_GRANTED || !mPermissions.contains(permission)); } /** * 这个静态方法可以用来检查你是否有几个特定的权限。 * 为每一个权限,并将简单地返回一个布尔值是否你有所有的权限 * @param 需要检查 权限的上下文 * @param 权限 数组 * @return 返回你是否有所有的权限 */ public synchronized boolean hasAllPermissions(@Nullable Context context, @NonNull String[] permissions) { if (context == null) { return false; } boolean hasAllPermissions = true; for (String perm : permissions) { hasAllPermissions &= hasPermission(context, perm); } return hasAllPermissions; } /** *这种方法的是获取清单里面的所有权限。permissionsresultaction 用于通知允许用户允许或拒绝每一个权限。 * * @param 需要检查权限的activity * @param permissionsresultaction用于权限接受通知你 */ public synchronized void requestAllManifestPermissionsIfNecessary(final @Nullable Activity activity, final @Nullable PermissionsResultAction action) { if (activity == null) { return; } String[] perms = getManifestPermissions(activity); requestPermissionsIfNecessaryForResult(activity, perms, action); } /** *该方法将请求的权限,如果 *他们需要被要求(即我们没有许可),并会增加 * permissionsresultaction到队列被通知的权限被授予或 *否认。在预Android棉花糖的情况下,将立即授予权限。 *活动变量为空,但如果它是无效的,不能执行的方法。 *这是唯一可作为一种礼貌片段,getactivity()可能产量空 *如果该片段没有添加到其父活动中 * @param 请求权限的活动 * @param 权限列表 * @param permissionsresultaction通知当权限授予或拒绝。 */ public synchronized void requestPermissionsIfNecessaryForResult(@Nullable Activity activity, @NonNull String[] permissions, @Nullable PermissionsResultAction action) { if (activity == null) { return; } addPendingAction(permissions, action); if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { doPermissionWorkBeforeAndroidM(activity, permissions, action); } else { List<String> permList = getPermissionsListToRequest(activity, permissions, action); if (permList.isEmpty()) { //if there is no permission to request, there is no reason to keep the action int the list removePendingAction(action); } else { String[] permsToRequest = permList.toArray(new String[permList.size()]); mPendingRequests.addAll(permList); ActivityCompat.requestPermissions(activity, permsToRequest, 1); } } } /** * 该方法将请求的权限,如果 *他们需要被要求(即我们没有许可),并会增加 * permissionsresultaction到队列被通知的权限被授予或 *否认。在预Android棉花糖(6.0)的情况下,将立即授予权限。 *但如果 getactivity()返回null,这方法 *将无法工作作为活动引用,必须检查权限。 * @param 需要检查 权限的fragmnet * @param 需要请求的权限列表 * @param permissionsresultaction通知当权限授予或拒绝。 */ public synchronized void requestPermissionsIfNecessaryForResult(@NonNull Fragment fragment,@NonNull String[] permissions, @Nullable PermissionsResultAction action) { Activity activity = fragment.getActivity(); if (activity == null) { return; } addPendingAction(permissions, action); if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { doPermissionWorkBeforeAndroidM(activity, permissions, action); } else { List<String> permList = getPermissionsListToRequest(activity, permissions, action); if (permList.isEmpty()) { //if there is no permission to request, there is no reason to keep the action int the list removePendingAction(action); } else { String[] permsToRequest = permList.toArray(new String[permList.size()]); mPendingRequests.addAll(permList); fragment.requestPermissions(permsToRequest, 1); } } } /** * 这个方法通知permissionsmanager,权限已经改变。如果你正在做 *使用活动的权限请求,则应调用此方法,将通知所有悬而未决 的,permissionsresultaction当前对象 *在队列中,并将从挂起的请求列表中删除权限请求。 * @param 已更改的权限。 * @param 每个权限的值 */ public synchronized void notifyPermissionsChange(@NonNull String[] permissions, @NonNull int[] results) { int size = permissions.length; if (results.length < size) { size = results.length; } Iterator<WeakReference<PermissionsResultAction>> iterator = mPendingActions.iterator(); while (iterator.hasNext()) { PermissionsResultAction action = iterator.next().get(); for (int n = 0; n < size; n++) { if (action == null || action.onResult(permissions , results )) { iterator.remove(); break; } } } for (int n = 0; n < size; n++) { mPendingRequests.remove(permissions ); } } /** * 在安卓设备前要求权限(安卓6,api23),根据权限状态,直接进行或拒绝工作 * @param 检测权限的activity * @param 权限数组 * @param 我们执行某项操作后权限检查 */ private void doPermissionWorkBeforeAndroidM(@NonNull Activity activity, @NonNull String[] permissions, @Nullable PermissionsResultAction action) { for (String perm : permissions) { if (action != null) { if (!mPermissions.contains(perm)) { action.onResult(perm, Permissions.NOT_FOUND); } else if (ActivityCompat.checkSelfPermission(activity, perm) != PackageManager.PERMISSION_GRANTED) { action.onResult(perm, Permissions.DENIED); } else { action.onResult(perm, Permissions.GRANTED); } } } } /** * @param 检查权限的activity * @param 所有权限的名字 * @param 我们执行某项操作后权限检查 * @return 尚未授予的权限名称列表 */ @NonNull private List<String> getPermissionsListToRequest(@NonNull Activity activity, @NonNull String[] permissions,@Nullable PermissionsResultAction action) { List<String> permList = new ArrayList<String>(permissions.length); for (String perm : permissions) { if (!mPermissions.contains(perm)) { if (action != null) { action.onResult(perm, Permissions.NOT_FOUND); } } else if (ActivityCompat.checkSelfPermission(activity, perm) != PackageManager.PERMISSION_GRANTED) { if (!mPendingRequests.contains(perm)) { permList.add(perm); } } else { if (action != null) { action.onResult(perm,Permissions.GRANTED); } } } return permList; } }
接下来我们来看PermissionsResultAction.java
[code]package com.xxxx.xxxx.permissions; import android.content.pm.PackageManager; import android.os.Handler; import android.os.Looper; import android.support.annotation.CallSuper; import android.support.annotation.NonNull; import android.util.Log; import java.util.Collections; import java.util.HashSet; import java.util.Set; /** *将实例传递给 requestpermissionsifnecessaryforresult方法。结 *果将被送回你无论是ongranted(所有的权限已被授予),或ondenied(所需*的权限被拒绝)。 *你把你的ongranted方法和通知功能,用户什么都在ondenied方法不工作。 */ public abstract class PermissionsResultAction { private static final String TAG = PermissionsResultAction.class.getSimpleName(); private final Set<String> mPermissions = new HashSet<String>(1); private Looper mLooper = Looper.getMainLooper(); /** * Default Constructor */ public PermissionsResultAction() {} /** *如果您是在后台线程中使用权限请求,则希望 *回调是在UI线程中,通过looper刷新ui */ public PermissionsResultAction(@NonNull Looper looper) {mLooper = looper;} /** *当所有权限已被用户授予,把所有你的权限敏感的代码,可以只需执行所 需权限 */ public abstract void onGranted(); /** *当一个权限被拒绝的时候调用 * * @param 被拒绝的权限 */ public abstract void onDenied(String permission); /** * 忽视未发现的权限 */ @SuppressWarnings({}) public synchronized boolean shouldIgnorePermissionNotFound(String permission) { Log.d(TAG, "Permission not found: " + permission); return true; } /* *返回授权 结果 */ @CallSuper protected synchronized final boolean onResult(final @NonNull String permission, int result) { if (result == PackageManager.PERMISSION_GRANTED) { return onResult(permission, Permissions.GRANTED); } else { return onResult(permission, Permissions.DENIED); } } /** *当一个特定的权限已更改。 *此方法将调用所有权限,所以该方法确定 *如果授权影响到该状态,是否可以继续进行 */ @CallSuper protected synchronized final boolean onResult(final @NonNull String permission, Permissions result) { //先从权限列表里移除当前权限 mPermissions.remove(permission); if (result == Permissions.GRANTED) { if (mPermissions.isEmpty()) { new Handler(mLooper).post(new Runnable() { @Override public void run() { onGranted(); } }); return true; } } else if (result == Permissions.DENIED) {//权限被拒 new Handler(mLooper).post(new Runnable() { @Override public void run() { onDenied(permission); } }); return true; } else if (result == Permissions.NOT_FOUND) { if (shouldIgnorePermissionNotFound(permission)) { if (mPermissions.isEmpty()) {//权限为空 new Handler(mLooper).post(new Runnable() { @Override public void run() { onGranted();//去授权 } }); return true; } } else { new Handler(mLooper).post(new Runnable() { @Override public void run() { //拒绝权限 onDenied(permission); } }); return true; } } return false; } /** *注册指定的权限对象的permissionsresultaction *让它知道哪些权限来查找更改。 * * @param permissions名单 */ @CallSuper protected synchronized final void registerPermissions(@NonNull String[] perms) { //把名单加到权限集合里 Collections.addAll(mPermissions, perms); } }
好了,最后我们就来使用权限管理:
// 先对app获取所有需要的授权(6.0需要去获取权限)
grantPermissions();
[code]/*** * 获取清单文件中的所有权限 */ private void grantPermissions() { @Override public void onGranted() { Toast.makeText(MainActivity.this, Toast.LENGTH_SHORT).show(); } @Override public void onDenied(String permission) { String message = String.format( Locale.getDefault(),"Permission \"%1$s\" has been denied", permission); Toast.makeText(MainActivity.this, message, Toast.LENGTH_SHORT).show(); }}); }
上面呢 我们在程序一开始呢就去授权所有的清单里面的权限,你会看到和ios一样的权限dialog提示,这里呢我们直接来图片展示下。
如下图所示:
接下来我们要去通知权限授权的改变
[code]@Override public void onRequestPermissionsResult(intrequestCode,@NonNull String[] permissions, @NonNull int[] grantResults) { PermissionsManager.getInstance().notifyPermissionsChange(permissions,grantResults); }
这里呢我们以百度定位的例子来使用:
[code] /** * 定位信息 */ private void initLocation() { LocationClientOption option = new LocationClientOption(); // 可选,默认高精度,设置定位模式,高精度(LocationMode.Hight_Accuracy), // 低功耗(LocationMode.Battery_Saving), // 仅设备(LocationMode.Device_Sensors) option.setLocationMode(LocationMode.Hight_Accuracy); option.setCoorType("bd09ll");// 可选,默认gcj02,设置返回的定位结果坐标系, // tempcoor="gcj02";//国家测绘局标准"bd09"//百度墨卡托标准"bd09ll"//百度经纬度标准 // int span=1000; option.setScanSpan(0);// 可选,默认0,即仅定位一次,设置发起定位请求的间隔需要大于等于1000ms才是有效的 option.setIsNeedAddress(true);// 可选,设置是否需要地址信息,默认不需要 option.setOpenGps(true);// 可选,默认false,设置是否使用gps option.setLocationNotify(true);// 可选,默认false,设置是否当gps有效时按照1S1次频率输出GPS结果 option.setIgnoreKillProcess(false);// 可选,默认true,定位SDK内部是一个SERVICE,并放到了独立进程,设置是否在stop的时候杀死这个进程,默认不杀死 mLocationClient.setLocOption(option); } /** *页面 停止状态下关闭定位 */ @Override protected void onStop() { if (mLocationClient != null) { mLocationClient.stop();// 界面消失后取消定位 mLocationClient = null; } super.onStop(); }
我们先来判断定位权限是否已授权成功:
[code]// 判断是否授权定位权限 boolean hasPermission = PermissionsManager.getInstance().hasPermission( this, Manifest.permission.ACCESS_FINE_LOCATION);
接下来我们根据是否授权成功来进行相关的操作:
[code] if (hasPermission == false) {//没有授权成功 grantLoactionPermissons();//去授权 }else{//授权成功去定位 mLocationClient = ((RYApplication) getApplication()).mLocationClient; initLocation();// 定位 mLocationClient.start();// 定位SDK // start之后会默认发起一次定位请求,开发者无须判断isstart并主动调用request mLocationClient.requestLocation(); }
根据定位需要的权限去授权
[code]/** * 授权定位权限 */ private void grantLoactionPermissons() { PermissionsManager.getInstance().requestPermissionsIfNeces saryForResult(this,new String[] { Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.WRITE_EXTERNAL_STORAGE },new PermissionsResultAction() { @Override public void onGranted() { mLocationClient = ((RYApplication) getApplication()).mLocationClient; initLocation();// 定位 mLocationClient.start();// 定位SDK // start之后会默认发起一次定位请求,开发者无须判断isstart并主动调用 requestmLocationClient.requestLocation(); } @Override public void onDenied(String permission) { } }); }
当然还有一些权限你无须去判断:
默认许可权限(无需授权)
还有一些权限是在安装的时候默认许可并且不可撤销的,我们把它们叫做普通权限,这些权限如下:android.permission.ACCESS_LOCATION_EXTRA_COMMANDS
android.permission.ACCESS_NETWORK_STATE
android.permission.ACCESS_NOTIFICATION_POLICY
android.permission.ACCESS_WIFI_STATE
android.permission.ACCESS_WIMAX_STATE
android.permission.BLUETOOTH
android.permission.BLUETOOTH_ADMIN
android.permission.BROADCAST_STICKY
android.permission.CHANGE_NETWORK_STATE
android.permission.CHANGE_WIFI_MULTICAST_STATE
android.permission.CHANGE_WIFI_STATE
android.permission.CHANGE_WIMAX_STATE
android.permission.DISABLE_KEYGUARD
android.permission.EXPAND_STATUS_BAR
android.permission.FLASHLIGHT
android.permission.GET_ACCOUNTS
android.permission.GET_PACKAGE_SIZE
android.permission.INTERNET
android.permission.KILL_BACKGROUND_PROCESSES
android.permission.MODIFY_AUDIO_SETTINGS
android.permission.NFC
android.permission.READ_SYNC_SETTINGS
android.permission.READ_SYNC_STATS
android.permission.RECEIVE_BOOT_COMPLETED
android.permission.REORDER_TASKS
android.permission.REQUEST_INSTALL_PACKAGES
android.permission.SET_TIME_ZONE
android.permission.SET_WALLPAPER
android.permission.SET_WALLPAPER_HINTS
android.permission.SUBSCRIBED_FEEDS_READ
android.permission.TRANSMIT_IR
android.permission.USE_FINGERPRINT
android.permission.VIBRATE
android.permission.WAKE_LOCK
android.permission.WRITE_SYNC_SETTINGS
com.android.alarm.permission.SET_ALARM
com.android.launcher.permission.INSTALL_SHORTCUT
com.android.launcher.permission.UNINSTALL_SHORTCUT
这些权限和以前一样使用,你无需检查它们是否被撤销了
总结和建议
现在你应该很清楚整个新的权限系统了,同时你也应该知道我们面临的问题了.在Android6.0中动态权限系统已经取代了原有的权限系统,我们别无选择,退无可退,唯一能做的就是去做好适配工作.好消息是需要进行动态申请的权限是少量的,大部分常用的权限是默认获得许可,并不需要你处理的.总而言之,你只需要修改一小部分代码来完成适配工作.
在这里给出两个建议:
1.优先对重要的部分进行适配,确保不会出现崩溃问题.
2.在完成适配工作前,不要将应用的targetSdkVersion设为23,尤其是在使用AndroidStudio创建新工程的时候,记得手动修改一下工程的targetSdkVersion,因为AndroidStudio会默认使用最新的SDK版本.
说到修改代码,我必须承认工作量很大.如果之前的架构设计不合理的话,你可能需要花费一些时间来重新设计了,就像之前说的,我们别无选择,除了去做好它.
我建议你列出应用的功能所依赖的所有的权限,然后考虑如果权限被拒绝,怎样使你的应用的功能尽可能可用,并考虑好如果部分权限被拒绝的情况下,你应该怎么做.恩,这也很复杂,最好能记录好各种情况.
对于安卓6.0的权限运行问题,你可移步Android 6.0 运行时权限处理
好累啊,一不小心到12点,睡觉,加油吧。第一次使用markDown感觉好辛苦,写个东西都
相关文章推荐
- python(2)-字符串(2)
- HDU 5616 Jam's balance(01背包)
- 【JS】【笔记】JavaScript入门经典(第5版)第7章 面向对象编程
- 第四套荧光钞大全介绍
- 关于shrio的那点事
- git 命令整理
- 【JS】【笔记】JavaScript入门经典(第5版)第6章 脚本
- LeetCode Excel Sheet Column Number
- java垃圾回收机制详解
- 【JS】【笔记】JavaScript入门经典(第5版)第5章 数据类型
- 【NYOJ】[463]九九乘法表
- jquery dropdownlist.js
- php 基础知识
- #学习笔记#(30)牛客网JS测试题1~20题
- 【JS】【笔记】JavaScript入门经典(第5版)第4章 DOM对象和内置对象
- Codeforces Round #316 (Div. 2) E. Pig and Palindromes、HDU 5617 Jam's maze(dp)
- Spring的JDBC框架
- 玩转Python让人讨厌的编码问题
- 神经网络及卷积神经网络的训练——反向传播算法
- jquery extend 多个扩展方法