1 写在前面
话说 6.0 出来已经挺久了,对于权限适配我们也有很多轮子可用。关于如何适配 6.0 权限,网上资料很多也很完善,故并不会展开探讨。
不用第三方框架的话,我们会和这些 api 打交道 (方法太长省略参数):
Context.checkSelfPermission()
Activity.requestPermissions()
Activity.onRequestPermissionsResult()
Activity.shouldShowRequestPermissionRationale()
显然全部分析篇幅过长,根据二八法则,我们只分析主线而忽略掉庞杂的枝干。
本文假设你对 6.0 权限比较熟悉,试图与大家分享从 requestPermissions
到 onRequestPermissionsResult
的背后,究竟经历了什么。
2 场景跟踪
以下是 RxPermissions Demo 中,对相机权限的询问。
2.1 唤起对话框
我们看到 requestPermissions
触发了一个对话框。然而实际上,它是一个透明的 Activity
,而且居然沿用了 startActivityForResult
的逻辑,怪不得也有个 requestCode
。
1 | // Activity |
我们从 buildRequestPermissionsIntent
往里跟,根据隐式 Intent
很快能找到对应的 Activity
—— GrantPermissionsActivity
。
1 | // PackageManager |
2.2 点击事件
找到 Activity
再进一步去找弹框和点击事件。首先看 onCreate()
:
1 | // GrantPermissionsActivity |
一看,原来权限还支持手环和TV,只看我们关心的 handheld
。
1 | // handheld.GrantPermissionsViewHandlerImpl |
到这里,UI部分已经对应上了。有不再询问
的选项框以及允许
和拒绝
两个按钮。只是点击的逻辑实现在外边。
2.3 回调onAcrivityResult()
我们又回到了 GrantPermissionsActivity
,它实现了UI的回调,然后通过 setResult()
,把授权结果返回给我们的app页面。
1 | // GrantPermissionsActivity implements GrantPermissionsViewHandler.ResultListener |
2.4 回调onRequestPermissionsResult()
回到 Activity
,我们发现在 dispatchActivityResult
的同时,穿插了权限的分发。然后,很自然的就走到了我们的目的地。
1 | // Activity |
2.5 权限的允许/拒绝
前面的逻辑基本上是UI层的,大题算是走通了。而细心的你可能发现 2.3 中遗漏了权限的允许/拒绝
未讲。这部分涉及 Binder
和 aidl
调用,不了解的童鞋可以先去补一下。
以权限允许为例,粗略的过一下调用栈:
- GrantPermissionsActivity.onPermissionGrantResult()
- AppPermissionGroup.grantRuntimePermissions()
- PackageManager.grantRuntimePermission()
- IPackageManager.grantRuntimePermission()
- PackageManagerService.grantRuntimePermission()
最后调用到的是系统层的 PMS,大致上是根据应用包名
和权限名
更改 sb.PermissionsState
里的权限列表,最后异步保存进文件里。
PS: 这里的 sb
是 SettingBase
,实例是 PackageSetting
。顾名思义,它保存着应用(package)级别的设置。
结合代码和断点风味更佳:
1 | // PackageManagerService |
3 总结
6.0 权限的主线大概过了一遍,如有纰漏请留言指正,欢迎留言探讨。
另,看源码时切勿陷入一些琐碎的细节,比如最后的写入文件,大体上就一个
FileOutputStream
,有兴趣可以看看。吾生也有涯,而知也无涯,以有涯随无涯,殆已~