android 6.0 权限管理的学习资料和使用例子

来源:互联网 发布:呼和浩特软件招聘信息 编辑:程序博客网 时间:2024/06/11 01:05

2015-11-18: 
去官网看了一下,之前的资料,发现官网更新了文档。对比了一下,在自己的文章加入一些新的内容(对一些知识点:完善说明,怎么测试权限管理



别人翻译的资料(很详细的)

http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2015/0830/3387.html

一个开源的权限管理框架:封装好的。
https://github.com/hotchemi/PermissionsDispatcher


最后分享一下:自己封装的权限管理和一些相关资料
http://yunpan.cn/cLEkFS2yYM2FR  访问密码 ccc8

里面包含了:PermissionsDispatcher(能运行的);自己封装的权限管理的源码和图解流程说明。


官网资料:

https://developer.android.com/preview/features/runtime-permissions.html
https://developer.android.com/preview/features/runtime-permissions.html#support-lib
https://developer.android.com/preview/features/runtime-permissions.html#normal
https://developer.android.com/reference/android/content/pm/PermissionInfo.html#PROTECTION_NORMAL


一些知识点:
1.这个新的运行时权限仅当我们设置targetSdkVersion to 23(这意味着你已经在23上测试通过了)才起作用,当然还要是M系统的手机。app在6.0之前的设备依然使用旧的权限系统。

如果app的targetSdkVersion 低于 23,那将被认为app没有用23新权限测试过,那将被继续使用旧有规则:用户在安装的时候不得不接受所有权限,安装后app就有了那些权限咯!然后app像以前一样奔跑!注意,此时用户依然可以取消已经同意的授权!用户取消授权时,android 6.0系统会警告,但这不妨碍用户取消授权。
问题又来了,这时候你的app崩溃吗?

善意的主把这事也告诉了android小组,当我们在targetSdkVersion 低于23的app调用一个需要权限的函数时,这个权限如果被用户取消授权了的话,不抛出异常。但是他将啥都不干,结果导致函数返回值是null或者0.

2.代码没有成功改为支持最新运行时权限的app,不要设置targetSdkVersion 23 发布,否则你就有麻烦了。只有当你测试过了,再改为targetSdkVersion 23 。
警告:现在你在android studio新建项目,targetSdkVersion 会自动设置为 23。如果你还没支持新运行时权限,我建议你首先把targetSdkVersion 降级到22


3.权限组:
同一组的任何一个权限被授权了,其他权限也自动被授权。例如,一旦WRITE_CONTACTS被授权了,app也有READ_CONTACTS和GET_ACCOUNTS了。

参考:https://developer.android.com/reference/android/Manifest.permission_group.html
https://developer.android.com/guide/topics/security/permissions.html#normal-dangerous
dangerous permissions 被分入到 9 个权限组

Table 1. Permissions and permission groups.

Permission GroupPermissionsandroid.permission-group.CALENDAR
  • android.permission.READ_CALENDAR
  • android.permission.WRITE_CALENDAR
android.permission-group.CAMERA
  • android.permission.CAMERA
android.permission-group.CONTACTS
  • android.permission.READ_CONTACTS
  • android.permission.WRITE_CONTACTS
  • android.permission.GET_ACCOUNTS
android.permission-group.LOCATION
  • android.permission.ACCESS_FINE_LOCATION
  • android.permission.ACCESS_COARSE_LOCATION
android.permission-group.MICROPHONE
  • android.permission.RECORD_AUDIO
android.permission-group.PHONE
  • android.permission.READ_PHONE_STATE
  • android.permission.CALL_PHONE
  • android.permission.READ_CALL_LOG
  • android.permission.WRITE_CALL_LOG
  • com.android.voicemail.permission.ADD_VOICEMAIL
  • android.permission.USE_SIP
  • android.permission.PROCESS_OUTGOING_CALLS
android.permission-group.SENSORS
  • android.permission.BODY_SENSORS
android.permission-group.SMS
  • android.permission.SEND_SMS
  • android.permission.RECEIVE_SMS
  • android.permission.READ_SMS
  • android.permission.RECEIVE_WAP_PUSH
  • android.permission.RECEIVE_MMS
  • android.permission.READ_CELL_BROADCASTS
android.permission-group.STORAGE
  • android.permission.READ_EXTERNAL_STORAGE
  • android.permission.WRITE_EXTERNAL_STORAGE


.....等等




新的权限管理的一些建议,使用注意点:
参考:https://developer.android.com/training/permissions/best-practices.html

1.只请求你需要的权限:减少请求的次数,或用intent来代替,让其他的应用来处理。
防止一次请求太多的权限或请求次数太多,用户可能对你的应用感到厌烦。

2.在应用启动的时候,最好先请求应用必须的一些权限,不是必须的,在使用的时候,才请求(如一些附带权限)
 
需要自己整理,管理一下自己应用的权限分类:

   2.1 普通权限(normal permissions):只需要在androidmanifest.xml中声明相应的权限,在安装应用时,会默认获得许可。
                           并且用户不能修改权限许可。只需要在AndroidManifest.xml中简单声明这些权限就好,安装时就授权。不需要每次使用                                                                  时都检查权限,而且用户不能取消以上授权。
    参考:https://developer.android.com/preview/features/runtime-permissions.html#normal

   2.2 需要申请的权限(dangerous permissions):
        2.2.1 必要权限:最好在应用启动的时候,进行请求许可的一些权限(主要是应用中主要功能需要的权限)
        2.2.2 附带权限:不是应用主要功能需要的权限(如:分享图片时,需要读取应用的通讯录等等)

3.解释你的应用为什么需要这些权限:在请求之前requestPermissions().,提示用户,让用户不会感到困惑

4.使用兼容库support-v4中的方法

ContextCompat.checkSelfPermission()
ActivityCompat.requestPermissions()
ActivityCompat.OnRequestPermissionsResultCallback
ActivityCompat.shouldShowRequestPermissionRationale()
The v4 support library also contains the PermissionChecker class, which provides several static utility methods for apps that use IPC to provide services for other apps. For example,PermissionChecker.checkCallingPermission() checks whether an IPC made by a particular package has a specified permission.

FragmentCompat.requestPermissions()
FragmentCompat.shouldShowRequestPermissionRationale()


 requestPermissions() 的一些说明:

Note: When your app calls the framework's requestPermissions() method, the system shows a standard dialog box to the user.
 Your app cannot configure or alter that dialog box. If you need to provide any information or explanation to the user, 
you should do that before you call requestPermissions(), as described in Explain why the app needs permissions.

当调用 requestPermissions() 时,系统会显示一个获取权限的提示对话框,当前应用不能配置和修改这个对话框,
如果需要提示用户一些这个权限相关的信息或说明,需要在调用 requestPermissions() 之前处理。


shouldShowRequestPermissionRationale() 的一些说明:

To help find the situations where you need to provide extra explanation, the system provides theshouldShowRequestPermissionRationale() method. 

This method returns true if the app has requested this permission previously and the user denied the request. 

That indicates that you should probably explain to the user why you need the permission.


If the user turned down the permission request in the past and chose the Don't ask again option in the permission request system dialog, this method returns false

The method also returns false if the device policy prohibits the app from having that permission.


1. 第一次请求权限时,用户拒绝了,下一次:shouldShowRequestPermissionRationale()  返回 true,应该显示一些为什么需要这个权限的说明

2.第二次请求权限时,用户拒绝了,并选择了“不在提醒”的选项时:shouldShowRequestPermissionRationale()  返回 false

3. 设备的策略禁止当前应用获取这个权限的授权:shouldShowRequestPermissionRationale()  返回 false 


注意:上面的:第二次请求权限时,才会有“不在提醒”的选项,如果用户一直拒绝,并没有选择“不在提醒”的选项,下次请求权限时,会继续有“不在提醒”的选项



shouldShowRequestPermissionRationale() 的方法说明:


Gets whether you should show UI with rationale for requesting a permission.

 You should do this only if you do not have the permission and the context in which the permission is requested does not clearly communicate to the user what would be the benefit from granting this permission.


For example, if you write a camera app, requesting the camera permission would be expected by the user and no rationale for why it is requested is needed. If however, the app needs location for tagging photos then a non-tech savvy user may wonder how location is related to taking photos. In this case you may choose to show UI with rationale of requesting this permission.


根据方法说明:

显示权限说明:是根据你的应用中使用的权限分类来的:

1.用户容易知道应用需要获取的权限:如一个拍照应用,需要摄像头的权限,是很正常,不用提示。

2.一些用户感觉困惑的一些权限:如:分享图片,还需要获取位置的权限,这个需要提示用户:为什么需要这个权限。

参考:

处理 “不再提醒”

如果用户拒绝某授权。下一次弹框,用户会有一个“不再提醒”的选项的来防止app以后继续请求授权。

如果这个选项在拒绝授权前被用户勾选了。下次为这个权限请求requestPermissions时,对话框就不弹出来了,结果就是,app啥都不干。
这将是很差的用户体验,用户做了操作却得不到响应。这种情况需要好好处理一下。在请求requestPermissions前,

我们需要检查是否需要展示请求权限的提示通过activity的shouldShowRequestPermissionRationale,代码如下:

final private int REQUEST_CODE_ASK_PERMISSIONS = 123;
  
private void insertDummyContactWrapper() {
    int hasWriteContactsPermission = checkSelfPermission(Manifest.permission.WRITE_CONTACTS);
    if (hasWriteContactsPermission != PackageManager.PERMISSION_GRANTED) {
//TODO
            if (!shouldShowRequestPermissionRationale(Manifest.permission.WRITE_CONTACTS)) {
                showMessageOKCancel("You need to allow access to Contacts",
                        new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialog, int which) {
                                requestPermissions(new String[] {Manifest.permission.WRITE_CONTACTS},
                                        REQUEST_CODE_ASK_PERMISSIONS);
                            }
                        });
                return;
            }
        requestPermissions(new String[] {Manifest.permission.WRITE_CONTACTS},
                REQUEST_CODE_ASK_PERMISSIONS);
        return;
//TODO
    }
    insertDummyContact();
}
  
private void showMessageOKCancel(String message, DialogInterface.OnClickListener okListener) {
    new AlertDialog.Builder(MainActivity.this)
            .setMessage(message)
            .setPositiveButton("OK", okListener)
            .setNegativeButton("Cancel"null)
            .create()
            .show();
}

            

  


5.保存一份普通权限的清单(用来查询,对比)
下面是一份普通权限的清单:
https://developer.android.com/guide/topics/security/normal-permissions.html
(34个普通权限(新文档))
(下面是37个权限(老文档))

If an app declares in its manifest that it needs a normal permission, the system automatically grants the app that permission at install time. 
The system does not prompt the user to grant normal permissions, and users cannot revoke these permissions.
安装app时,系统自动许可普通权限(app自动拥有普通权限的许可),系统不会提示用户去许可普通权限,且用户不能撤销普通权限的许可。

Currently, the following permissions are classified as PROTECTION_NORMAL:

  • 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_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

6.权限组:
同一组的任何一个权限被授权了,其他权限也自动被授权。例如,一旦WRITE_CONTACTS被授权了,app也有READ_CONTACTS和GET_ACCOUNTS了。
参考:https://developer.android.com/reference/android/Manifest.permission_group.html
https://developer.android.com/guide/topics/security/permissions.html#normal-dangerous
dangerous permissions 被分入到 9 个权限组

Table 1. Permissions and permission groups.

Permission GroupPermissionsandroid.permission-group.CALENDAR
  • android.permission.READ_CALENDAR
  • android.permission.WRITE_CALENDAR
android.permission-group.CAMERA
  • android.permission.CAMERA
android.permission-group.CONTACTS
  • android.permission.READ_CONTACTS
  • android.permission.WRITE_CONTACTS
  • android.permission.GET_ACCOUNTS
android.permission-group.LOCATION
  • android.permission.ACCESS_FINE_LOCATION
  • android.permission.ACCESS_COARSE_LOCATION
android.permission-group.MICROPHONE
  • android.permission.RECORD_AUDIO
android.permission-group.PHONE
  • android.permission.READ_PHONE_STATE
  • android.permission.CALL_PHONE
  • android.permission.READ_CALL_LOG
  • android.permission.WRITE_CALL_LOG
  • com.android.voicemail.permission.ADD_VOICEMAIL
  • android.permission.USE_SIP
  • android.permission.PROCESS_OUTGOING_CALLS
android.permission-group.SENSORS
  • android.permission.BODY_SENSORS
android.permission-group.SMS
  • android.permission.SEND_SMS
  • android.permission.RECEIVE_SMS
  • android.permission.READ_SMS
  • android.permission.RECEIVE_WAP_PUSH
  • android.permission.RECEIVE_MMS
  • android.permission.READ_CELL_BROADCASTS
android.permission-group.STORAGE
  • android.permission.READ_EXTERNAL_STORAGE
  • android.permission.WRITE_EXTERNAL_STORAGE


测试权限管理

https://developer.android.com/training/permissions/best-practices.html#testing


1. 编写好权限相关的代码
2.找到需要测试权限(dangerous permissions)的位置
3.开始测试:在许可权限和撤销权限许可的情况下,测试代码是否有问题,是否都做了相关的处理(逻辑完整处理,用户友好提示等等)
在请求多个权限许可,(只许可其中一个,没有完全许可) ,(完全许可),(都不许可),(许可多个,但不是所有权限)等等情况,都要测试到。

下面是实时查看权限的许可情况和实时撤销权限许可的命令(不用每次都去: 设置->应用->xxx应用->应用信息->权限->权限列表,修改权限的许可)

  • Use the adb tool to manage permissions from the command line:
    • List permissions and status by group: 这个只是列出设备的所有的危险权限,并没有命令来显示某个应用的权限的许可情况(这点不好)
      $ adb shell pm list permissions -d -g
    • Grant or revoke one or more permissions:
      $ adb shell pm [grant|revoke] <permission-name> ...
  • Analyze your app for services that use permissions.

下面是一些可以使用的命令:参考:http://blog.csdn.net/commonslok/article/details/8150018

adb -s emulator-5554 shell pm list permissions -d -g :列出设备emulator-5554上所有的分组危险权限(-d:表示危险权限 -g:表示分组)
adb -s emulator-5554 shell pm list permissions -g :列出设备emulator-5554上所有的分组权限(-g:表示分组):包括分组危险权限+没有分组的权限
adb -s emulator-5554 shell pm list permissions :列出设备emulator-5554上所有的权限
adb -s emulator-5554 shell pm list permissions -d -g -f :(-f:表示显示权限的详情)
-s emulator-5554 :表示指定设备名称:emulator-5554(可以通过 adb devices来得到设备的列表)

重置所有应用的危险权限为未许可
adb -s emulator-5554 shell pm reset-permissions
adb -s emulator-5554 shell pm reset-permissions permissions.dispatcher.sample (没有作用)
adb -s emulator-5554 shell pm reset-permissions com.example.android.system.runtimepermissions (没有作用)

实时许可权限撤销权限许可:
adb -s emulator-5554 shell pm grant permissions.dispatcher.sample android.permission.CAMERA : 许可权限
adb -s emulator-5554 shell pm revoke permissions.dispatcher.sample android.permission.CAMERA:撤销权限许可
上面:
permissions.dispatcher.sample:你的应用包名
android.permission.CAMERA:请求许可的权限名称

下面的实时撤销多个权限许可的命令,没有作用:只能一个一个来
adb -s emulator-5554 shell pm grant permissions.dispatcher.sample android.permission.CAMERA android.permission.READ_CONTACTS

adb -s emulator-5554 shell pm revoke permissions.dispatcher.sample android.permission.CAMERA android.permission.READ_CONTACTS


6 0