1.2 Android 6.0新特性
Google I/O 2015大会在2015年5月28日举行,在发布会上推出了Android 6.0 Marshmallow(棉花糖)的新系统。新系统的整体设计风格依然保持扁平化的Material Design风格。Android 6.0在对软件体验与运行性能上进行了大幅度的优化。据测试,Android 6.0可使设备续航时间提升30%。
1.2.1 Android 6.0主要新特性概述
1.应用权限管理
在Android 6.0中,应用许可提示可以自定义了。它允许对应用的权限进行高度管理,比如应用能否使用位置、相机、网络和通信录等,这些都开放给开发者和用户。此前的 Android系统的应用权限管理只能靠第三方应用来实现,在Android 6.0中应用权限管理成为系统级的功能。
2.Android Pay
Android Pay是Android支付统一标准。Android 6.0系统中集成了Android Pay,其特性在于简洁、安全和可选性。它是一个开放性平台,用户可以选择谷歌的服务或者使用银行的App来使用它。Android Pay支持Android 4.4以后的系统设备并且可以使用指纹来进行支付。
3.指纹支持
虽然很多厂商的 Android手机实现了指纹的支持,但是这些手机都使用了非谷歌认证的技术。这一次谷歌提供的指纹识别支持,旨在统一指纹识别的技术方案。
4.Doze电量管理
Android 6.0自带Doze电量管理功能。手机静止不动一段时间后,会进入Doze电量管理模式。谷歌表示,当屏幕处于关闭状态时,平均续航时间可提高30%。
5.App Links
Android 6.0加强了软件间的关联,允许开发者将App和他们的Web域名关联。谷歌大会展示了App Links的应用场景,比如你的手机邮箱里收到一封邮件,内文里有一个Twitter链接,点击该链接可以直接跳转到Twitter应用,而不再是网页。
6.Now on Tap
在桌面或App的任意界面,长按Home键即可激活Now on Tap,它会识别当前屏幕上的内容并创建Now卡片。比如,你和某人聊天时提到一起去一家餐馆吃饭,这时你长按Home键,Now on Tap就会创建Now卡片提供这家餐馆的地址和评价等相关信息。如屏幕中出现电话号码,它就会提供一个拨号的标志,你可以直接拨打;而无须先复制,然后再粘贴到拨号界面。它还可以识别日历、地址、音乐、地标等信息。Now on Tap能够快速便捷地帮助用户,完成用户需求,这在很大程度上解放了用户的嘴和双手。这可以说是自Google Now发布以来最为重大的一次升级。
1.2.2运行时权限机制
在Android 6.0以前,我们安装App时会列出安装的App的访问权限,而且只有安装时会出现一次。一旦我们同意并安装了此App,这个App就可以在用户毫不知晓的情况下访问权限内的所有东西,比如用户的通信信息、用户的位置等,这会侵犯用户的隐私。在Android 6.0时,将不会在安装的时候授予权限;取而代之的是,App不得不在运行时一个一个询问用户来授予权限。对于 Android用户来说这显然是一个好消息;但是对于开发者来说这显然是一场噩梦,因为开发者不能像以前一样随意地调用方法了,你需要在每个需要权限的地方检查权限,否则等待你的就是App崩溃。
1.Android 6.0之前版本的应对之策
Android 6.0系统默认为targetSdkVersion小于23的应用授予了所申请的所有权限,所以如果你以前的App设置的targetSdkVersion低于23,在运行时也不会崩溃。为了验证这个问题,首先要在build.gradle中将targetSdkVersion设置为23以下。需要注意的是当前compileSdkVersion为23,也就是SDK版本为23,如下代码所示:
接下来定义一个按钮,点击按钮时拨打电话。
运行程序会发现仍旧能打电话,这是在我们意料之中的。接下来我们取消授予的电话权限,这时系统会弹出提示框,提醒我们拒绝此权限可能会导致其无法正常运行。我们点击“拒绝”,仍要取消授予的电话权限。如图1-17所示。
图1-17取消授予的电话权限
我们接下来再点击按钮拨打电话时,则发现无法拨打该电话。这样的用户体验显然不好。当然这只是电话权限。目前官方的做法是,如果用户取消该项授权,那么依赖该项授权的方法的返回值为null,你的App可能会报空指针异常,所以我们需要尽快着手修改App支持最新的权限系统。
2.Normal Permissions与Dangerous Permission
Google将权限分为两类:一类是Normal Permissions,这类权限一般不涉及用户隐私,是无须用户进行授权的,比如手机振动、访问网络等,这些权限只需要在AndroidManifest.xml中简单声明就好,安装时就授权,无须每次使用时都检查权限,而且用户不能取消以上授权;另一类是Dangerous Permission,一般会涉及用户隐私,需要用户进行授权,比如读取sdcard、访问通信录等。
Normal Permissions如表1-1所示。
表1-1 Normal Permissions
续表
Dangerous Permission则是以分组的形式给出的,如图1-18所示。
图1-18 Dangerous Permission
同一组的任何一个权限被授权了,其他权限也自动被授权。此外,对于申请时弹出的提示框上面的文本说明也是对整个权限组的说明,而不是单个权限的说明。
3.实现支持运行时权限
下面仍旧通过一个打电话的例子来讲解如何支持运行时权限。首先我们要在build.gradle中将targetSdkVersion设置为23。
接下来是Java代码。因为比较简单,所以这里就不一步一步地讲解了,代码如下所示:
这里定义一个按钮,点击按钮会调用call方法,call方法首先判断当前App是否有permission.CALL_PHONE的权限。如果有,则直接调用 callPhone方法来打电话;如果没有该权限,则弹出提示框进行权限申请,如图1-19所示。onRequestPermissionsResult就是申请权限的回调,如果用户选择“允许”,则调用callPhone方法;如果用户选择“拒绝”,就弹出Toast显示权限被拒绝。需要注意的是,如果我们选择“允许”,下一次就不会弹出权限申请提示框了;如果我们点击“拒绝”,则下一次还会弹出权限申请提示框,只不过这一次会多出一个选项,叫作“不再询问”,如图1-20所示。如果我们勾选了该选项,则下一次就不会弹出权限申请提示框,而直接调用onRequestPermissionsResult,回调结果为最后一次用户的选择,也就会弹出我们定义的Toast:”权限被拒绝”。
图1-19弹出权限申请提示框
图1-20弹出权限申请提示框(带“不再询问”选项)
想要再次打开该权限,则需要在设置→应用→配置应用→应用权限→电话权限中操作,如图1-21所示。
如果这个程序运行在ActivityCompat.checkSelfPermission5.0版本的手机上会怎样呢?如果运行在5.0版本的手机上时,(this,Manifest.permission.CALL_PHONE)=PackageManager.PERMISSION_GRANTED)也就是授权过了,会调用callPhone方法直接拨打电话。
4.处理“不再询问”选项
如果用户选择了“不再询问”,那么每次我们调用需要访问该权限的 API时都会失效,这显然不会带来好的用户体验,所以我们需要做的就是给用户一个友好的提示。这时候需要使用shouldShowRequestPermissionRationale方法,这个方法用来帮助开发者向用户解释权限的情况。如果用户选择了“不再询问”选项,则shouldShowRequestPermissionRationale方法会返回false,这时候我们可以弹出AlertDialog来提醒用户允许访问该权限的重要性,代码如下所示。弹出的AlertDialog效果如图1-22所示。
图1-21电话权限管理
图1-22处理“不再询问”选项
5.PermissionsDispatcher框架的使用
当然,每次在需要判断权限的地方均写如上面所示的一套方法,总是一件麻烦事。我们可以自己封装起来,因为流程都是一样的,变化的只是传进来的我们需要判断的权限就可以了。不过目前已经有很多框架实现了这一点,这里拿PermissionsDispatcher来举个例子。首先,我们要在工程项目的build.gradle中添加如下代码:
在app模块的build.gradle中添加如下代码:
接下来我们需要了解几个注释。
- RuntimePermissions:必需的注释,它用来注册一个 Activity或 Fragment,使它们可以处理权限。
- NeedsPermission:必需的注释,在需要获取权限的地方注释,用来获取权限。
- OnShowRationale:提示用户为何要开启此权限。在用户选择拒绝后,再次需要访问该权限时调用。
- OnPermissionDenied:用户选择拒绝时的提示。
- OnNeverAskAgain:用户选择不再询问后的提示。
好了,我们来编写代码。我们将上面打电话的例子应用在这里,如下所示:
这时我们要重新编译程序,会生成一个辅助类ThirdPartyActivityPermissionsDispatcher,其余的事交给它就可以了。完整代码如下所示:
好了,运行此程序,点击打电话按钮,会弹出开启权限提示框,如图1-23所示。当我们点击“拒绝”时,会调用showDenied方法。当我们再次点击打电话按钮时,会调用showWhy方法,弹出AlertDialog,如图1-24所示。我们点击“知道了”,会调用request.proceed()再次执行权限请求,这时会再次弹出开启权限提示框,只不过这次的提示框带“不再询问”选项。当我们选择“不再询问”后点击“拒绝”时会调用 showNotAsk方法,弹出自定义的 AlertDialog,如图1-25所示。
图1-23弹出开启权限提示框
图1-24提示用户为何要开启此权限
图1-25用户选择“不再询问”后的提示