Android技术知识Android开发经验谈Android开发

Android M runtime permissions(An

2018-10-28  本文已影响12人  5ef947bf2bd1

官方介绍:
https://developer.android.com/training/permissions/requesting?hl=zh-cn

Google Sample地址:
https://github.com/googlesamples/android-RuntimePermissionsBasic
https://github.com/googlesamples/android-RuntimePermissions

Android M引入了“运行时权限”,targetSdkVersion 23及以上的应用不但需要在AndroidManifest.xml中声明它们需要的权限,还需要在运行时动态申请这些已声明过的危险权限;targetSdkVersion低于23的应用,在安装时用户已经同意了所有权限,并且在运行时所需权限全部可用。如果不同意这些权限,用户将无法安装此应用。

处理过程包括:

  1. 在应用的清单文件中添加使用具体功能需要的相关权限;

  2. 每次在使用需要危险权限的功能之前,检查应用是否具有相关权限(用户有可能在授权之后手动撤销权限);

  1. 申请权限之前,帮助用户了解应用为什么需要某项权限;
  1. 监听申请权限的结果,如果用户同意应用申请的权限后,开始使用具体功能;如果用户拒绝应用申请的权限,提示相关权限申请失败,无法使用具体功能。
    注:当用户授权应用同一组危险权限中的某一项权限后(如果用户不手动撤销此权限),系统将自动授权应用该组的其他权限。后期版本权限组可能会发生变化。

场景:使用相机预览

  1. 在AndroidMinifest的根节点下声明相机权限
<uses-permissionandroid:name="android.permission.CAMERA"/>
  1. 通过点击按钮,触发“开启相机预览”事件

  2. 进行权限验证

if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA)  != PackageManager.PERMISSION_GRANTED) {
   requestCameraPermission();
} else {
   startCamera();// 假装有相机
}
  1. 申请权限
private void requestCameraPermission() {
    // Permission has not been granted and must be requested.
    if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.CAMERA)) {
        //应用之前请求过此权限但用户拒绝了请求
        Snackbar.make(mLayout, R.string.camera_access_required, Snackbar.LENGTH_INDEFINITE)
                .setAction(R.string.ok, new View.OnClickListener() {
            @Override
            public void onClick(View view) {
              // Request the permission
              ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.CAMERA}, PERMISSION_REQUEST_CAMERA);
            }
        }).show();
    } else {
        // 应用未请求过此权限或者用户在过去拒绝了权限请求,并在权限请求系统对话框中选择了“不再提示”选项
        Snackbar.make(mLayout, R.string.camera_unavailable, Snackbar.LENGTH_SHORT).show();
        ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA}, PERMISSION_REQUEST_CAMERA);
    }
}
  1. 监听申请权限结果
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    if (requestCode == PERMISSION_REQUEST_CAMERA) {
        // Request for camera permission.
        if (grantResults.length == 1 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
            // Permission has been granted. Start camera preview Activity.
            Snackbar.make(mLayout, R.string.camera_permission_granted, Snackbar.LENGTH_SHORT).show();
            startCamera();
        } else {
            // Permission request was denied.
            Snackbar.make(mLayout, R.string.camera_permission_denied, Snackbar.LENGTH_SHORT).show();
        }
    }
}
  1. Fragment中验证授权和申请授权操作
  1. 嵌套Fragment中申请权限操作
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    List<Fragment> fragments = getChildFragmentManager().getFragments();
    if (fragments != null) {
        for (Fragmentfragment : fragments) {
            if (fragment != null) {
                fragment.onRequestPermissionsResult(requestCode, permissions,grantResults);
            }
        }
    }
}

应用targetSdkVersion < 23的兼容性处理:

场景:

targetSdkVersion < 23的App安装在Android 6.0及以上设备时,用户已同意App中声明的所有权限,但是在安装完成后,用户手动在设置中关闭了APP的权限。此时调用ContextCompat.checkSelfPermission()检查APP是否拥有指定权限,返回值仍为PackageManager.PERMISSION_GRANTED,如果使用需要此项危险权限的功能,应用将奔溃。

解决:

try {
    PackageInfo info = context.getPackageManager().getPackageInfo(context.getPackageName(), 0);
    int targetSdkVersion = info.applicationInfo.targetSdkVersion;
} catch (PackageManager.NameNotFoundExceptione) {
    e.printStackTrace();
}

a) 如果targetSdkVersion 低于23,使用PermissionChecker兼容库检查APP拥有的权限;
b) 如果targetSdkVersion 不低于23,使用之前的方式检查APP是否拥有指定权限;

  1. 调用PermissionChecker.checkSelfPermission()检查APP是否拥有指定权限,返回值:

a) PERMISSION_GRANTED:已授权
b) PERMISSION_DENIED:用户拒绝授权
c) PERMISSION_DENIED_APP_OP:用户拒绝授权且targetSdkVersion小于23

runtime permissions处理封装库:

鸿洋MPermissions:https://github.com/hongyangAndroid/MPermissions

  1. 引入
buildscript {
    dependencies {
        classpath'com.neenbedankt.gradle.plugins:android-apt:1.4'
    }
}
apply plugin: 'com.neenbedankt.android-apt'

dependencies {
    apt 'com.zhy:mpermission-compiler:1.0.0'
    compile 'com.zhy:mpermission-api:1.0.0'
}
  1. 定义权限请求码
    final int REQUECT_CODE_SDCARD = 1;
  2. 判断是否需要弹出解释
if(!MPermissions.shouldShowRequestPermissionRationale(MainActivity.this,Manifest.permission.WRITE_EXTERNAL_STORAGE, REQUECT_CODE_SDCARD)) {
    MPermissions.requestPermissions(MainActivity.this, REQUECT_CODE_SDCARD, Manifest.permission.WRITE_EXTERNAL_STORAGE);
}
  1. 申请读写SD卡权限
MPermissions.requestPermissions(MainActivity.this, REQUECT_CODE_SDCARD, Manifest.permission.WRITE_EXTERNAL_STORAGE);
  1. 处理申请权限回调
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
    MPermissions.onRequestPermissionsResult(this, requestCode, permissions, grantResults);
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}

@PermissionGrant(REQUECT_CODE_SDCARD)
public voidrequestSdcardSuccess() {
    Toast.makeText(this, "GRANT ACCESS SDCARD!", Toast.LENGTH_SHORT).show();
}

@PermissionDenied(REQUECT_CODE_SDCARD)
public void requestSdcardFailed() {
    Toast.makeText(this, "DENY ACCESS SDCARD!",Toast.LENGTH_SHORT).show();
}
  1. 混淆
-dontwarn com.zhy.m.**
-keep class com.zhy.m.** {*;}
-keep interface com.zhy.m.** { *; }
-keep class **$$PermissionProxy { *; }

PermissionsDispatcher:https://github.com/hotchemi/PermissionsDispatcher

  1. 引入:
dependencies {
   implementation 'com.github.hotchemi:permissionsdispatcher:${latest.version}'
   annotationProcessor 'com.github,hotchemi:permissionsdispatcher-processor:${latest.version}'
}

@NeedsPermission 用户同意授权应用相关权限后的回调;
@OnShowRationale 用户已拒绝过1次授权此权限后,应用再次请求用户授权此权限时的回调。在此方法中解释应用为什么需要此权限。之后调用PermissionRequest的proceed()方法继续申请权限;
@OnPermissionDenied 用户拒绝授权应用相关权限后的回调;
@OnNeverAskAgain 当用户拒绝授权并勾选“不再提示”后的回调

xxActivityPermissionsDispatcher.**WithPermissionCheck(this);//  xx为自动生成的辅助类,**为被@NeedsPermission注解的方法名

常规权限列表:

ACCESS_LOCATION_EXTRA_COMMANDS
ACCESS_NETWORK_STATE
ACCESS_NOTIFICATION_POLICY
ACCESS_WIFI_STATE
BLUETOOTH
BLUETOOTH_ADMIN
BROADCAST_STICKY
CHANGE_NETWORK_STATE
CHANGE_WIFI_MULTICAST_STATE
CHANGE_WIFI_STATE
DISABLE_KEYGUARD
EXPAND_STATUS_BAR
GET_PACKAGE_SIZE
INSTALL_SHORTCUT
INTERNET
KILL_BACKGROUND_PROCESSES
MODIFY_AUDIO_SETTINGS
NFC
READ_SYNC_SETTINGS
READ_SYNC_STATS
RECEIVE_BOOT_COMPLETED
REORDER_TASKS
REQUEST_INSTALL_PACKAGES
SET_ALARM
SET_TIME_ZONE
SET_WALLPAPER
SET_WALLPAPER_HINTS
TRANSMIT_IR
UNINSTALL_SHORTCUT
USE_FINGERPRINT
VIBRATE
WAKE_LOCK
WRITE_SYNC_SETTINGS

危险权限列表:

group:android.permission-group.CONTACTS

permission:android.permission.WRITE_CONTACTS
permission:android.permission.GET_ACCOUNTS
permission:android.permission.READ_CONTACTS

group:android.permission-group.PHONE

permission:android.permission.READ_CALL_LOG
permission:android.permission.READ_PHONE_STATE
permission:android.permission.CALL_PHONE
permission:android.permission.WRITE_CALL_LOG
permission:android.permission.USE_SIP
permission:android.permission.PROCESS_OUTGOING_CALLS
permission:com.android.voicemail.permission.ADD_VOICEMAIL

group:android.permission-group.CALENDAR

permission:android.permission.READ_CALENDAR
permission:android.permission.WRITE_CALENDAR

group:android.permission-group.CAMERA

permission:android.permission.CAMERA

group:android.permission-group.SENSORS

permission:android.permission.BODY_SENSORS

group:android.permission-group.LOCATION

permission:android.permission.ACCESS_FINE_LOCATION
permission:android.permission.ACCESS_COARSE_LOCATION

group:android.permission-group.STORAGE

permission:android.permission.READ_EXTERNAL_STORAGE
permission:android.permission.WRITE_EXTERNAL_STORAGE

group:android.permission-group.MICROPHONE

permission:android.permission.RECORD_AUDIO

group:android.permission-group.SMS

permission:android.permission.READ_SMS
permission:android.permission.RECEIVE_WAP_PUSH
permission:android.permission.RECEIVE_MMS
permission:android.permission.RECEIVE_SMS
permission:android.permission.SEND_SMS
permission:android.permission.READ_CELL_BROADCASTS

导入Google Sample—RuntimePermissions时,build失败解决方案:

这里是《我的Android世界》系列目录

上一篇 下一篇

猜你喜欢

热点阅读