探索新的android6.0权限模型

原稿地址:

https://medium.com/ribot-labs/exploring-the-new-android-permissions-model-ba1d5d6c0610#.6pt87hg6t


探索新的android权限模型

在Android M中,对于用户和开发人员的权限方面有了一些变化,这里我们看一看他们是如何改变的,又是如何影响用户体验的,我们需要做些什么来实现这样的新模型。

2015年Google I/O大会上发布了新的Android公告,让我们对新的Android设计支持库有了一个大概的了解;也让我们看到了关于Android权限的一些新方案,这些新方案影响了他们在开发首批android-M应用时的工作。在ribot出现之后,我们一直都在尽可能地秉持最新的开发方式,而这一次我决定,要先尝试打破新的权限模型来做开发,接下来给大家看看我的新尝试带来了什么。

                                                                                    ···

Android中的权限问题一直都是开发app时需要考虑到的一个重要领域。从目前的状况来看,用户已经认识到了这些权限,但并没能真正去控制它们,更重要的是,开发人员在研发过程中,可能会遇到类似于能不能在已经存在的权限上添加新权限的问题,而在更新过程中,这样的问题也可能会导致一些矛盾的出现,并对数据的更新造成一些影响。

以现有的权限模型来看,用户在安装app时就不得不去授予应用各种各样的权限,而这个app甚至都还没有被使用过。这也就意味着用户必须在使用某个app之前,就对它持有某种程度的信任,而对于很多用户来说,这可能会直接影响到他们决定是否要安装这个应用程序。

就我个人而言,在安装app的时候这种情况我已经见过太多次,最近的一个例子发生在我参加一个音乐节的时候,他们有一个可以查看演出阶段时间的配套app,我觉得这个应用很棒,所以我马上打开了Google Play商店来下载它,而在点击了安装之后,我的界面弹出了这个让人想要退缩的对话框(左)。我不明白为什么这个应用(唯一的功能是显示演出阶段的时间和内容细节)需要我的联系人信息、我的位置、我的文件、日历等等,所以最终的结果是,我放弃了这次安装。如果在我安装一款app的时候它要从我这里获取的内容太多,而我甚至都不知道它有什么样的目的,或者能让我相信它的原因的话,我绝不可能安装它。这样的经历在我使用下载各种app之前出现的次数多不胜数,我的放弃安装也不是第一次发生。


                                                           应用的权限请求可能会铺天盖地


有的时候我们作为用户,在碰到了前面说的情况之后,可能会有种被强制安装某个app的感觉。以Facebook的app为例,很多用户都知道而且喜欢用Facebook,虽然它的app权限请求列表堪称巨大,但是Facebook已经和它的用户们建立了良好的信任关系,所以用户在安装的时候,会忽略那一大串的权限请求。

虽然这些权限请求当中有一部分是Facebook主要功能所真正需要的,但也许还是有些东西你可能不希望授权许可。

 

                     在Android-M中,权限请求列表会大大缩减,而且只会出现在当它们是必需之时。

 

比如,当用户点击了拍照功能键的时候请求相机权限就是有意义的,这样的话,如果用户在使用Facebook app的时候从来不用那个功能,也就不需要在安装的时候就去授予许可权限了。


权限组:


                                        权限现在被整理成了8个不同的权限组


在Android-M中,如果是同属于一类的权限,就会被整理到一个组别之下,这个组别将会在用户发出确切请求时来申请获得具体的权限,所以举例来说,如果要获得“读取日历”(READ_CALENDAR)的权限,那用户就会被提示是否授予“日历”权限。

这些权限组别中,很多都包含了好几个具体权限,可表现为以下分组:


                             每个权限组包含很多具体权限


你可能会注意到,这里不再有互联网权限——太棒了!这样的话有个好处,就是你不需要再次被请求获取这个权限,也就是说你可以让网络请求去掉提示用户,询问是否可以授予。这是因为这个权限(以及其他权限)现在被指定为PROTECTION_NORMAL权限,这类权限都会在自动授予应用程序清单中声明。


运行时权限:

应用商店里的用户安装量总感觉是有些虚的,点击了安装按钮实际上却不会去安装这个程序,就是因为你在安装程序之前首先需要接受一大串的权限许可。值得庆幸的是,最新的权限授予将不再做这样的要求,所以,当你在Google Play商店里打算安装某个app的时候,点击安装按钮就会是真的安装应用程序,而不是让你先去授予这样那样的权限。

在应用运行过程中,有些点击会触发提示获取权限来使用某些具体的功能,在这一点上,你需要检查你自己的系统来确认你是不是拥有这样的权限,如下所示,系统将会在授予你或者用户一个可以继续运行下去的路径之前,做好一系列的检查。


                                          系统需要做一系列检查来允许你或者用户继续操作

 

  • 首先,步骤(1)中,我们需要检查是否有权限来执行某个操作。
  • 接下来,步骤(2),检查系统有没有我们所需要的权限,这个操作会通过调用checkSelfPermission()方法来完成。
  • 在这之后,如果所需权限确定,我们就可以继续运行并处理结果,否则系统将继续下一项检查,也就是确认用户是否已经请求权限授予。见步骤(3)。
  • 否则,如果用户不是再次被询问,而是没有主动请求权限,如步骤(5),那么提示对话框就会仍然出现在用户的界面上,而这一次将会有一个额外的复选框来设置这个标记。
  • 然而,如果在这一步的时候标记已经设定好,那么会通过onRequestPermissionsResult()返回结果,结果在代码中处理。

当我们请求权限的时候,用户界面会弹出一个简单的对话框,提示他们来授予权限或者拒绝使用某项功能。


                                     隶属第一组的权限对话框

 

这个对话框是用户在第一次请求权限时会出现在用户屏幕上的,如果他们接受请求,就会授予权限来执行所需的任务,然而,正如这样简单的对话框所显示的,拒绝和接受会导致两种不同的请求结果。

如果选择拒绝,用户在第一次拒绝请求权限的时候,你需要想办法用某种方式来解决这个问题。比如,如果你为了要显示用户的联系人而发请求获取联系人信息,但是用户拒绝授予权限,那么可以设置显示一个错误的占位符放在本来应该显示出来的联系人列表上,就可能会让用户来清除之前的拒绝授权选择。

注意:请求权限第一次被拒绝是不会有什么后果的,所以也不需要以任何形式进行双重提示。

如果有必要的话,你可以使用shouldShowRequestPermissionRationale()方法来检查应用程序是否曾经请求某些必要的权限而被拒绝了,这样的话就可以让报错的状态在再次请求权限之前准确地显示在屏幕上,从而就可以解释为什么一定需要这样的权限。

如果第一次请求权限被拒绝,等下一次你再请求相同权限的时候,直接允许授权的情况不会再发生。


                 权限请求对话框在随后的显示中会附带一个可选择的复选框

 

如果用户勾选了该选项并拒绝,那么你就不能为了当前的安装再次发送获取该权限的请求了。出现这种情况的话,你作为开发者也就没什么可以做的了,所以如果这是你的app一个至关重要的权限需求,那么你就需要在第一次被拒绝的时候,将你为什么需要这个权限的原因解释的更清楚。

关于为什么要解释清楚需要某个权限对于你app的重要性,这里还有另一个原因。我们可以通过提供某种形式的简介或欢迎界面,来概述该应用的功能,而这样的界面是可以真正帮助用户认识到为什么我们需要获取那些权限,同时也希望用户能给予我们更多的信任来授予我们这样的权限。

我们也可以在相同的请求中,同时发送多个权限请求。除非是在必要的时候,否则在大多数情况下,我们都不应该使用这样的发送请求方式。对于这样的情况,有一种好的处理办法是,在该应用程序启动某个功能时,不能没有必要的权限,否则无法使用该功能。比如,一个短信应用程序需要访问联系人才能使用它的功能,我们就可以在加载这个app的时候,同时请求短信和联系人权限。


                同时请求多个权限会在同一个对话框内一个接一个地显示

 

除了附加的授权数量以外,这种同时请求多个权限的对话框在外观上看起来和请求单个权限的对话框几乎一模一样。而这个附加的数字也正是避免用户被一大堆权限请求淹没的一个重要因素,但是如果这个数字比较大的话,可能就会带来负面的用户体验,也会让权限请求铺天盖地。

在确认这些权限之前,我们首先需要检查我们的app运行版本号,如果目前的版本号是Android M(“MNC”),那么我们就可以继续调用相关的权限方法。

请求单个权限:

如果要请求单个权限,我们可以调用checkSelfPermission()方法来确认我们的app是不是已经有了所需要的权限,如下面代码案例所示。如果我们没有获取权限,那么我们就需要使用requestPermissions()方法来发送权限获取请求——所传递的数组中包含我们所请求的权限。

当requestPermissions()方法被调用的时候,将会有一个对话框弹出来提示用户回应我们的请求,一旦用户做出回应,onRequestPermissionResult()方法就会被调用——我们可以通过这个方法来确认用户是否收到了请求对话框并做出响应。

在这个案例中,我们对发出的权限请求列表做了权限等级检测,访问到的第一个列表元素就是一个单个的权限请求,如果授权许可,我们就会回馈给用户在获取了相应权限之后app应有的反应,因为现在我们有权限完成这样的反应。

另一方面,如果我们被拒绝授权许可,我们应该通过某种形式来提示用户,我们无法继续执行某些必要的动作。

请求多个权限:

如果是请求多个权限,我们要做的事情就会略有不同。比如下面的例子中,我首先检查所需的权限是否已经被授予,如果没有,我就会把它们添加到我的权限请求列表,然后,我将我的权限请求列表作为参数传给requestPermissions()方法。

声明只针对M的权限:

至于运行在Android-M设备上的应用,如果需要请求单个权限,我们可以声明只针对M的权限。我们可以这样写:

<uses-permission-sdk-m  android:name="android.permission.ACCESS_FINE_LOCATION"/>

这种写法表现得就像是一个一般的权限声明,而它却是只针对于M版本的,这意味着你可以添加新的权限来更新应用的版本,而不需要去担心老版本项目。这样的权限声明只适用于M项目,否则永远不会用到。

切换权限设置:

在手机设置里面,用户能够查看并编辑给定权限的应用程序列表,如下所示的权限分组类别(左)。选择其中一个将会带用户进入对应给定权限的app列表(右)。


                                            用户进入系统设置可以查看和编辑权限

 

用户还可以访问单个应用程序权限,通过设置-->应用程序-->选定某个应用程序查看,这里会显示出单个应用程序的权限状态列表,我们可以操作其中的权限。

无论在任何时候,用户都可以访问这些设置,并点击权限的开关按钮,这也可能会导致一个问题出现,就是你有可能会让你的app获取到所有权限。所以,在开启某个权限之前你需要检查这个权限是不是在你每次使用某个功能的时候都会用到。

如果某个权限以前被开启过,那么你的应用可以再检查一遍,但条件是,“Don’t ask again”的复选框没有勾选。

在老版本SDK研发的app中,用户仍然可以从这些设置界面撤销权限,但这里的问题在于,如果这些权限被撤销,那么我们就不能从应用程序中再次请求这些权限了,因为这个功能只有android M搭建的项目才可以做到。当然了,如果用户试图关闭老版本app的某项权限,他们就会看到一个对话框(下图),提示他们这可能带来的影响。


                            如果权限被撤销,老版本的app就会出现这样的对话框

 

老版本应用程序:

老版本SDK研发的应用程序会表现的和以前看上去没什么两样,但是还是会有一些问题的。

老版本app在安装的时候,请求权限的行为和以前完全一致,为了在设备上安装这个app,用户还是得查看并接受屏幕上弹出的权限请求对话框,而一旦安装,所有的权限都会被授予许可。老版本app不会在运行中去授予权限,而都是在安装的时候授予,更新app版本时也是一样,有任何新的权限,都会在用户更新完点击安装时直接请求添加。

正如我们前面所提到的,用户仍然能够进入系统设置来禁用这些权限。在这种情况下,用户界面将会提示相同的错误信息,如果他们依然决定拒绝授予,那么在应用运行时也就不能再发送权限请求。目前如果出现这种状况,那么任何关于这些权限的请求就只能作为空状态数据来处理。比如下面的情况:

  • 请求的联系人列表返回“无联系人”的响应。
  • 请求用户当前位置将返回“当前位置不可用”。
  • 试图保存一个联系人的时候返回“已保存”,而实际上这个联系人可能还没有真正被保存上。

所以,当出现这样的状况时,我们需要确保在你的老版本应用中,可能影响到app功能的拒绝权限授予操作带来的所有错误状态,你都已经确认过。

你真的需要权限吗?

我记得,有些功能不需要去获取权限也仍然可以通过一个意图对象来执行完成,这种情况会大大地提高你app的用户体验,因为用户在需要执行需要的操作时,不用再看到任何形式的请求权限对话框。

  • ACTION_INSERT:为了满足你的应用需求,这个action可以用来替换两三个权限。设置所需的MIME Type类型和Intent的Extras属性可以让你额外添加日历或联系人事件,这可能会顶替我们对于日历和联系人权限的需求。
  • ACTION_IMAGE_CAPTURE:如果你的app只是简单的需要拍张照(或者录像,见:ACTION_VIDEO_CAPTURE)并返回结果,那么这个action就可以用来完成这样的事情,而图像结果将会被返回到Intent Extras(EXTRA_OUTPUT)中发送的确切位置。如果这个action可以充分利用,那么这个intent意图对象就可以完全代替我们对于相机权限的需求。(见:INTENT_ACTION_STILL_IMAGE_CAMERA)
  • ACTION_PICK:这个action既可以用来从用户联系人列表中选择一个联系人,也可以选择其中某一项具体的数据(比如email,电话号码,地址)。如果你的app使用了这个action来临时访问读取用户联系人列表,也就不再需要请求READ_CONTACTS权限了。
  • ACTION_VIEW:当这个action与ACTION_PICK共同使用时,它可以用来查看所选联系人URI细节而不需要去请求联系人权限,也可以通过一个有效定位数据,来启动一个地图。
  • ACTION_EDIT:当这个action与ACTION_PICK共同使用时,返回的联系人URI可以用来编辑联系人详细信息。
  • ACTION_DIAL:这个action可以用来拨打一个指定的电话号码,虽然它需要用户自己按下呼叫按钮(见ACTION_CALL),但是它不需要使用任何手机相关的权限。
  • ACTION_SENDTO:这个action可以编写一个SMS短信发送到指定的电话号码,如果这符合你app的要求,就可以拿来顶替SMS权限请求,来发送SMS短信。(见ACTION_SENT,ACTION_SEND_MULTIPLE)

最佳实践方案:

实现这个新的权限方案有很多好的方法,你应该按照顺序一个一个来实践,从而确保用户使用你的app是一次愉快的经历,不用去管那些可能需要请求的权限。

  • 帮助用户更确切地理解你为什么需要这些权限,可以有效地提高你的app用户体验。应用程序的启动可以作为一个非常适合介绍app的时间节点,这可以帮助用户来理解为什么他们需要授予权限来执行某些操作。
  • 必要的时候一定要请求权限。当你请求这些权限的时候有很重要的一点,就是你的请求必须要有实际意义。例如,如果你的app在拍照的时候请求相机权限,那么发出这样的请求就是有实际意义的,因为这可以让用户在想拍照的时候完成他们的拍摄(比如点击“照相”按钮的时候发送请求)。
  • 正如我们前面所讨论的,应该避免一次性请求多个权限,因为如果这样请求的话可能会造成很糟糕的用户体验。可能你希望在第一次加载应用的时候请求几个权限,那么条件是,这些权限对你的app功能至关重要,否则,就在必要的时候再请求权限。
  • 在用户授予了你所请求的权限许可时,一定要对用户有所反馈。比如,用户只允许你在跳转到某个地图界面之后,才能获取位置权限,然后获取他们当前的位置显示到地图界面上。
  • 如果你可以通过使用Intent的Actions属性来执行应用的功能而避免请求权限,那你一定要这样做。尽量保持最少的权限请求(在可能的情况下)至关重要,因为这样可以提升app整体的用户体验。

 

到下一次...

到这里就全部说完啦。我们的开发一定要通过这种新的权限模型创造出很棒的用户体验,然后通过你的最佳实验结果来帮助你完成这件事。不要忘了亲自去测试这些新的授权方法,包括手动和自动化测试——android M和老版本app都做这些事情!但最重要的是,玩的开心!

猜你喜欢

转载自blog.csdn.net/u014254481/article/details/50338237
今日推荐