IT七剑客 IT七剑客
首页
wresource
郭霖
孤寒者
IT邦德
沉默王二
老麦
stackoverflow
GitHub (opens new window)
首页
wresource
郭霖
孤寒者
IT邦德
沉默王二
老麦
stackoverflow
GitHub (opens new window)
  • 基础安卓文章

  • Android数据库

  • Android权限管理

    • 原来在 Android 中请求权限也可以有这么棒的用户体验
      • 支持DialogFragment
      • 最棒的用户体验
      • 自定义TintColor
      • 如何升级
    • PermissionX 1.5发布,支持申请Android特殊权限啦
    • 为什么说在 Android 中请求权限从来都不是一件简单的事情?
    • PermissionX 重磅更新,支持自定义权限提醒对话框
    • PermissionX 现在支持 Java 了!还有 Android 11 权限变更讲解
    • Android 运行时权限终极方案,用 PermissionX 吧
    • PermissionX 1_7发布,全面支持Android 13运行时权限
  • Android精华教程

  • Kotlin Flow响应式编程三部曲

  • 郭霖 安卓
  • Android权限管理
郭霖
2022-08-20
目录

原来在 Android 中请求权限也可以有这么棒的用户体验

PermissionX 这个开源项目起源于我今年出版的新书《第一行代码 第 3 版》 (opens new window),本来的主要目的只是为了带领读者朋友们学习如何开发并发布一个开源库。然而随着我发现这个项目不仅有学习的价值,还可以真正投入到实际项目的使用当中,于是后面又对 PermissionX 进行了多个版本的迭代,目前已经成为了一个非常稳定和方便的权限请求库。

在 1.3.0 版本当中,PermissionX 支持了自定义权限提醒对话框的功能,解决了长期以来被大家吐槽的对话框界面过丑的问题。现在大家可以自由发挥,定制出任意符合你们项目 UI 风格的对话框。具体过程可以参考这篇文章 PermissionX 重磅更新,支持自定义权限提醒对话框 (opens new window) 。

今天很高兴地告诉大家,PermissionX 又推出了最新的 1.4.0 版本,这次的更新将会让整个权限请求的流程拥有更棒的用户体验。而更棒的用户体验通常又会带来更高的权限请求通过率,所以这是相当重要的一次版本更新。

那么接下来我们就看一看 PermissionX 1.4.0 到底带来了哪些新东西吧。

# 支持DialogFragment

刚才已经提到了,在上一个版本当中,PermissionX 引入了自定义权限提醒对话框的功能,使得开发者可以自由地定制你想要的对话框样式。比如我在上篇文章中给出了如下的效果图示例:

img

这种权限提醒对话框是基于 Dialog 类来进行实现的,开发者在自定义对话框的时候需要继承 PermissionX 提供的 RationaleDialog,并对必要的几个方法进行实现。

我个人认为这种实现方案是没有问题的,PermissionX 控制整个权限的请求流程,而开发者可以自由控制 UI 的展示,非常完美。

然而,有朋友在 GitHub 上对这种方案提出了疑问,因为他想要使用 DialogFragment 来自定义权限提醒对话框,PermissionX 的限制导致他只能使用 Dialog 了。

img

DialogFragment 也是 Google 推荐使用的一种对话框实现方案,虽然我认为 DialogFragment 能实现的功能用 Dialog 也都能实现,但是强制使用 Dialog 确实显得有那么一些不友好。

于是我就开始思索着要不要完全重写自定义对话框这部分的实现,不再强制要求使用某一种固定的实现方式,而是只提供接口标准,具体怎么实现完全由开发者自己控制。

相信我,我确实这样做了。当时我的想法是,PermissionX 只定义显示对话框,关闭对话框等必要的接口,至于实现方面不做任何限制,你可以用 Dialog,也可以用 DialogFragment,甚至可以用 PopupWindow,或者是完全自定义的控件都行。

然而真正用了这种方案之后,我发现这并不是一个好的选择。因为 PermissionX 本来是内部自己控制着整个权限请求流程的,开发者完全不需要关心内部的逻辑,只需要自定义界面就行了。但是放开对话框的实现方式之后,开发者需要对自己实现的对话框负责,你需要考虑用户点击确定按钮后重新请求权限,需要考虑用户点击取消按钮后回调请求结果,需要考虑对话框取消的时候如何防止权限请求事件丢失,需要考虑横竖屏旋转时怎样防止 window leak 等等一大堆问题。

我不禁思考,这样的 PermissionX 真的还算好用吗?

所以,最终我把编写的这些代码全部 Rollback,否定掉了这个方案,因为我不想为了这种不知何时才能用得到的灵活性,去给开发者增加额外的负担。

虽然上述方案是否定了,但是对于 DialogFragment 的需求却是实实在在存在的。所以最终我采取了和之前一样的方式,增加了一个 RationaleDialogFragment 的类,该类是继承自 DialogFragment 的,里面也定义了 PermissionX 所要求的几个必要的方法,开发者在使用 DialogFragment 自定义对话框时同样将这几个必要的方法进行实现即可。整体实现过程和 1.3.0 版本是一模一样的。

虽然看上去这种方案略微有点笨拙,但是请相信我,这可能是最好的方法了。不然你的 PermissionX 会变得非常不稳定,比如频繁在崩溃和权限事件丢失之中挣扎。

关于对 DialogFragment 的支持就到这里。但,这不是本文的重点。

# 最棒的用户体验

为什么那么多人想要自定义权限提醒对话框?因为 PermissionX 默认的权限提醒对话框实在是太丑了。

例如我们调用如下代码来申请权限:

PermissionX.init(this)
    .permissions(Manifest.permission.CAMERA, Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.RECORD_AUDIO)
    .onExplainRequestReason { scope, deniedList ->
        val message = "PermissionX需要您同意以下权限才能正常使用"
        scope.showRequestReasonDialog(deniedList, message, "确定", "取消")
    }
    .request { allGranted, grantedList, deniedList ->
        if (allGranted) {
            Toast.makeText(activity, "所有申请的权限都已通过", Toast.LENGTH_SHORT).show()
        } else {
            Toast.makeText(activity, "您拒绝了如下权限:$deniedList", Toast.LENGTH_SHORT).show()
        }
    }

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

在请求的权限被用户拒绝时,PermissionX 将会弹出下图所示的权限提醒对话框。

img

这种对话框在我们的测试程序中用用还可以,在线上项目中使用肯定是不行的,因为用户体验不够友好。

那么为了能让权限提醒对话框变得更加好看,PermissionX 在 1.3.0 版本中引入了自定义对话框样式的功能,并且当时我还给大家演示了一种自定义对话框的实现过程,最终的对话框效果图如下:

img

可以看到,使用了自定义对话框的方式之后,我们可以自由地控制界面上的元素和内容,用户体验也得到了明显的改善。

不过,即使这样,还是有朋友在评论区里留言,嫌这个对话框太丑了(1 人嫌丑,42 人点赞)。

img

不过这个丑我是不背锅的,我只是为了演示自定义对话框的实现过程而已,具体对话框的丑和美还是掌握在你自己手里的。

那么看上去该支持的功能都已经支持了,PermissionX 1.4.0 版本里又优化了什么内容呢?

最重要的一点就是,1.4.0 版本中我对默认的权限提醒对话框进行了大幅的优化。

看上去好像并不是什么重磅功能,但恰恰相反,优化默认权限提醒对话框相当重要,这大大提升了 PermissionX 的用户体验,同时大大降低了 PermissionX 的使用成本,因为自定义对话框总体来说还是比较麻烦的。

现在,只要你升级了 1.4.0 版本,使用和上面完全相同的代码进行权限请求,你将会得到完全不同的权限提醒对话框界面,效果如下图所示:

img

可以看到,现在的对话框在用户体验方面无疑是完胜了之前的对话框,用户看到这样的界面也会更加赏心悦目。

那么 PermissionX 是如何做到的呢?

首先 PermissionX 会根据开发者在 showRequestReasonDialog() 方法中传入的 deniedList 来获取这些权限分别属于哪些权限组。因为在界面上其实并不需要将 deniedList 中的权限全部显示出来,而是只显示要申请的权限组名即可,这样可以让界面更精简。

需要注意的是,在 Android 9 及以下系统,我们可以通过系统 API 来自动获取某个权限属于哪个权限组,代码如下所示:

context.packageManager.getPermissionInfo(permission, 0).group

复制代码
1
2
3

从 Android 10 开始 Google 禁用了这个功能,所以在之后的版本中需要手动设置每个运行时权限对应了什么权限组。这个工作是相当繁琐的,但是好在 PermissionX 在内部已经处理了这个功能。

另外,为了让界面元素更加丰富,我们在每个权限组名的前面还加上了该组所对应的图标,图标的获取可以通过如下代码实现:

context.packageManager.getPermissionGroupInfo(permissionGroup, 0).icon

复制代码
1
2
3

如此一来,一个内容丰富,赏心悦目的权限提醒对话框也就诞生了。

然而,PermissionX 做到的还远不止这些。我们都知道,从 Android 10 系统开始,Google 引用了深色主题功能,一个出色的 App 在用户开启了深色主题模式之后,应该自动将界面也切换成深色模式。

而 PermissionX 同样对此功能进行了适配,在手机启用了深色主题模式之后,权限提醒对话框的效果如下图所示:

img

对话框上的颜色都是我精心调整过的,不管是深色主题还是浅色主题,看起来都会非常舒适。

除此之外,如果你的 App 要做海外版本,PermissionX 也进行了原生的支持。你只需要保证传递给 PermissionX 的文字内容都是经过翻译的即可,其他部分 PermissionX 会根据当前手机系统的语言进行展示。

比如我们将手机系统的语言切换成英文,然后使用如下代码进行权限请求:

PermissionX.init(this)
    .permissions(Manifest.permission.CAMERA, Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.RECORD_AUDIO)
    .onExplainRequestReason { scope, deniedList ->
        val message = "PermissionX needs following permissions to continue"
        scope.showRequestReasonDialog(deniedList, message, "Allow", "Deny")
    }
    .request { allGranted, grantedList, deniedList ->
        ...
    }

复制代码
1
2
3
4
5
6
7
8
9
10
11

最终权限提醒对话框的效果如下图所示:

img

再来看一张日文版的效果图:

img

到这里为止,PermissionX 基本就做到了面向开发者提供最简单的 API 接口,面向用户提供最棒的用户体验这样的双层标准。

另外我们还可以通过串接一个 explainReasonBeforeRequest() 方法,让权限提醒对话框在开始请求权限之前显示,这样就能实现先解释申请原因,再执行请求权限的功能。通常这样的权限请求方式对于用户来说更加友好,用户同意授权的概率也会更高。

PermissionX.init(this)
    .permissions(Manifest.permission.CAMERA, Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.RECORD_AUDIO)
    .explainReasonBeforeRequest()
    ...

复制代码
1
2
3
4
5
6

最后我们通过一个动画来完整体验一遍整个权限请求的流程吧。

img

# 自定义TintColor

虽说默认权限提醒对话框上面使用的颜色都是我精心调整过的,但是可能却未必适合你们的项目。因为每个项目都会有自己的主题色,设置一个与项目主题相符的颜色或许比使用默认的颜色更加合适一些。

目前,默认的权限提醒对话框上,权限组图标、确定、取消按钮,使用的都是蓝色。而如果你觉得这种颜色和你们项目主题风格不搭的话,也可以设置成任意你想要的颜色。

设置的方式非常简单,就是在 PermissionX 的请求链上再串接一个 setDialogTintColor() 方法即可,如下所示:

PermissionX.init(this)
    .permissions(Manifest.permission.CAMERA, Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.RECORD_AUDIO)
    .setDialogTintColor(Color.parseColor("#008577"), Color.parseColor("#83e8dd"))
    ...

复制代码
1
2
3
4
5
6

这里 setDialogTintColor() 方法接收两个参数,其中第一个参数是设置浅色主题下的颜色值,第二个参数是设置深色主题下的颜色值。既然是要自定义颜色值,那么肯定要把浅色主题和深色主题两种场景都考虑到才行。

现在重新运行程序之后,浅色主题和深色主题下的对话框效果分别如下图所示:

img img

可以看到,对话框上的权限组图标、确定、取消按钮的颜色都得到了修改,使用这种方式就可以让 PermissionX 更好地贴合你们项目的主题风格了。

# 如何升级

关于 PermissionX 新版本的内容变化就介绍到这里,升级的方式非常简单,修改一下 dependencies 当中的版本号即可:

dependencies {
    ...
    implementation 'com.permissionx.guolindev:permissionx:1.4.0'
}

复制代码
1
2
3
4
5
6

另外,如果你的项目还没有升级到 AndroidX,那么可以使用 Permission-Support 这个版本,用法都是一模一样的,只是 dependencies 中的依赖声明需要改成:

dependencies {
    ...
    implementation 'com.permissionx.guolindev:permission-support:1.4.0'
}

复制代码
1
2
3
4
5
6

PermissionX 的项目主页地址是:

github.com/guolindev/P… (opens new window)

另外,本篇文章主要介绍的是 PermissionX 1.4.0 版本的新特性。如果你之前并没有接触过 PermissionX,可以通过我编写的《PermissionX 权限系列专栏》 (opens new window)逐步进行学习,里面有非常详尽的用法讲解。

如果想要学习 Kotlin 和最新的 Android 知识,可以参考我的新书 《第一行代码 第 3 版》,点击此处查看详情 (opens new window)。

作者:郭霖 链接:https://juejin.cn/post/6982846298424623118 来源:稀土掘金 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

编辑 (opens new window)
上次更新: 2023/02/05, 02:48:13
Android数据库高手秘籍(十二)——LitePal的索引功能
PermissionX 1.5发布,支持申请Android特殊权限啦

← Android数据库高手秘籍(十二)——LitePal的索引功能 PermissionX 1.5发布,支持申请Android特殊权限啦→

最近更新
01
Coding 102 Writing code other people can read
02-26
02
Kotlin Flow响应式编程,StateFlow和SharedFlow
02-05
03
Kotlin Flow响应式编程,操作符函数进阶
02-05
更多文章>
Theme by Vdoing | Copyright © 2022-2023 IT七剑客 | MIT License
  • 闽ICP备2021006579号-4
  • 闽公网安备 35012102500470号
    • 跟随系统
    • 浅色模式
    • 深色模式
    • 阅读模式