htc328(htc328d删除解锁)

1.什么是动态权限?去年年底,为了加强国内安卓应用的隐私管理,上级部门出台了一系列规定,我们的app也做了相应的修改。主要的修改如下:隐私提示和访问顺序。测试的

1.什么是动态权限?

htc328(htc328d删除解锁)插图

去年年底,为了加强国内安卓应用的隐私管理,上级部门出台了一系列规定,我们的app也做了相应的修改。主要的修改如下:隐私提示和访问顺序。测试的时候发现有同学不了解Android权限的知识和历史,所以在疫情期间休息了一下,整理了一些东西供参考。

首先,本文以一张图开始。

IOS 12位置权利

回到2013年,苹果发布了IOS7系统。让开发者头疼的修改点之一:在隐私中添加相册、录音等权限。如果App需要使用相应权限,需要申请并得到用户同意(IOS7之前可以直接访问相册)。

鉴于此,很多app在刚启动的时候都会弹出来,申请各种权限。后来苹果为了改善用户体验,要求App Store在使用前才申请权限,有效改善了此类问题。比如一个直播App,当你启动App的时候,不需要摄像和录音权限。开播的时候只需要申请这两个权限。这个场景其实和今天说的Android动态授权差不多。

谷歌在2015年推出了Android 6.0棉花糖,其中一个主要特色就是加入了危险权限管理。这里的“危险权限管理”带来了“运行时权限”的新特性。

“危险权限管理”是指在进行一些涉及用户隐私的操作时,需要用户授权才能使用。比如通讯录、短信、摄像头、位置等隐私权利。获取用户权限,Google主张在应用运行时授权,简称运行时权限(也称“动态权限/动态授权”,以下简称“动态权限”)。

那么,在此之前,Android权限管理是什么样的呢?我发明了大概四个阶段的国产安卓权限管理经验。

Android权限管理简史第一阶段:无盖。

早期的安卓系统(安卓6.0之前),在安装app之前,会列出App应用的所有权限。如果继续安装,将被视为用户同意授予该应用程序所需的权限。

比如:索尼L36h安卓4.2.2系统。尝试安装应用程序时,弹出窗口会列出该应用程序应用的所有权限。只能查看需要的权限,不能拒绝授权。您可以选择取消安装或继续安装。

索尼L36h安装技巧

这样,对开发者来说是极其友好的。只需要在Manifest中配置App需要的权限,代码就可以直接调用了。但是对于用户来说,这种方式有很大的安全隐患。

举例:获取手机IMEI,需要PHONE_STATE权限;要访问网络,您需要INIERNET的许可。您只能在清单文件中添加权限。

<!-- PHONE_STATE权限--> <uses-permission android:name="android.permission.READ_PHONE_STATE" /> <!-- 网络权限--> <uses-permission android:name="android.permission.INTERNET" />第二阶段:第三方安全App

基于上述背景,国内一些公司的安全app为了解决一些敏感权限的不合理使用,开始对应用进行监控,获取手机敏感权限并进行提示。比如360手机卫士、腾讯手机管家等产品,当检测到某个App试图使用短信权限、定位等敏感权限时,会告知用户,并可以拒绝授予权限。起初,一切都很顺利。但随着手机厂商逐渐开始修改ROM,第三方安全app的兼容性和性能问题逐渐爆发。

例如:HTC T328 Android 4.0.2系统。当浏览器扫码功能触发相机调用时,360手机卫士会弹出权限提示窗口,用户可以允许或拒绝授权。注意这个窗口是第三方安全软件弹出的,不是系统级的弹出,和后面要说的两个弹出是不一样的。

30手机卫士弹出窗口

第三阶段:手机厂商的介入

随着时间的推移,手机厂商开始发力,他们把第三方软件的权限提示功能直接做成ROM。

例子:基于Android 4.4.4的小米4、MIUI 7;基于Android 5.1的ColorOS 3.0的Oppo R9,在浏览器扫码功能触发相机调用时,会弹出权限提示窗口。这个窗口,ROM弹出的,也就是系统本身,是系统级权限的弹出窗口。

4小米授权

OPPO R9授权

第四阶段:Google升级权限管理。

以上三个时期,App在申请权限时不需要更改,只需要配置Manifest即可。2015年推出的Android 6.0增加了危险权限管理。由于手机厂商对ROM的修改,部分6.0以上的机器不支持该功能。

第四阶段,App需要修改权限代码,才能正常使用相应的权限。简单理解为三步走:1。确定其是否被授权;2.未经授权需要申请权限的,根据授权结果继续执行;3.授权继续经营。

例子:Pixel2,原生Android 10;基于Android 8.0的华为mate8,EMUI8。当浏览器扫码功能触发相机调用时,会弹出权限提示窗口。这个由App通知系统弹出的窗口,是系统级权限的弹出窗口。

2像素2授权弹出窗口

华为mate8授权弹窗

第三阶段和第四阶段与系统弹出授权弹出相同。两者有什么区别?

首先,从UI上很难判断授权窗口是第三阶段还是第四阶段。三级弹的系统授权窗口大多有倒计时自动拒绝逻辑;四级弹的系统授权窗口基本没有自动拒绝逻辑。这一点可以大致判断出系统采用的是哪种机制。

其次,原则上。第三阶段,当系统检测到App正在使用危险权限时,自动弹出窗口。第四阶段的弹窗是App发现自己没有权限,让系统弹出的弹窗。庸俗的理解,第三阶段,你去朋友家做客,看到门开着就直接上门,触发红外报警器,通知你朋友;第四阶段,你去朋友家做客,发现门关着,就按门铃,叫朋友给你开门。

目前中国主要处于第三阶段(覆盖Android4.0~7.1)和第四阶段(覆盖Android6.0~10),后面会用到。

如何处理动态权限特征选项1:逃跑

因为动态权限特性只有Android 6.0才有,所以不需要升级目标SDK (Target SDK)就可以简单粗暴的通过

TargetSDK18通常会获取IMEI

只需将targetSDK升级到26,直接运行崩溃即可。

如果不改任何代码,直接把targetSDK升级到26,然后运行App。当你这样做的时候,就会出现异常甚至崩溃。崩溃的例子如下:

没有PHONE_STATE来获取IMEI崩溃

这个崩溃的原因是在Android 6.0及以上版本中,需要权限的操作在没有获得权限的情况下直接执行。所以怎么解决就涉及到真正的改装方案了。

选项2:实现动态权限。1.使用权限之前,请检查权限。

首先需要判断自己是否有权限。该时间点是在执行相应的需要许可的操作之前。例如,在获取IMEI之前,我们需要确定我们是否拥有PHONE_STATE权限。

我们可以称之为contextCompat。CheckSelfpermission()方法来检测授权状态,返回的结果是PackageManager中的两个常量:PERMISSION_GRANTED(授权)和PERMISSION_DENIED(未授权)。

2.如果获得授权,请执行您原来的操作。

获得授权后,您可以执行原来的操作。代码如下:

// 检测PHONE_STATE 如果已授权 if (ContextCompat.checkSelfPermission(this,Manifest.permission.READ_PHONE_STATE) == PackageManager.PERMISSION_GRANTED) { //做你想做的 }

没授权又怎样?

3.未经授权,申请许可。

如果App没有授权,我们需要向用户申请授权。您可以调用requestPermissions()方法来请求授权。代码如下:

// 检测PHONE_STATE 如果未授权 if (ContextCompat.checkSelfPermission(this,Manifest.permission.READ_PHONE_STATE) != PackageManager.PERMISSION_GRANTED) { //申请权限 ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.READ_PHONE_STATE), PERMISSIONS_REQUEST_PHONE_STATE) }

requestPermissions()中的第三个参数是int请求代码,便于回调处理。

调用授权方法后,ROM会调出一个系统级的弹出窗口(如下图)。您不能自定义此对话框。当用户点击“同意”时,系统会记录下来,下次判断权限时会返回授权状态。当应用被卸载时,记录将被清除。

Android 10授权弹窗

以上,完成了授权逻辑的最简单版本。整体代码如下:

// 检测PHONE_STATE 如果未授权 if (ContextCompat.checkSelfPermission(this,Manifest.permission.READ_PHONE_STATE) != PackageManager.PERMISSION_GRANTED) { //申请权限 ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.READ_PHONE_STATE), PERMISSIONS_REQUEST_PHONE_STATE) }else { //如果已授权做你想做的 }

弹出应用程序弹出窗口后呢?上面说了,弹出对话框是系统化的,我们不能给对话框添加代码,但是当弹出窗口被用户点击时,会触发回调,所以我们可以在指定的函数中处理回调。

4.重写函数来处理授权弹出窗口的点击结果。

直接在活动或片段中重写onRequestPermissionsResult()函数,以处理权限申请结果。这里将使用requestPermissions()的第三个参数。代码如下:

// 处理授权弹窗回调 override fun onRequestPermissionsResult( requestCode: Int, permissions: Array<out String>, grantResults: IntArray ) { when(requestCode){ // 识别刚刚用到的请求码,根据请求码识别不同弹窗回调并处理 PERMISSIONS_REQUEST_PHONE_STATE ->{ // 如果用户点击“允许” if (grantResults.size > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED){ Toast.makeText(this, "用户允许权限!",Toast.LENGTH_SHORT).show() // 可以继续执行你原来想做的事情了 }else{ Toast.makeText(this, "用户拒绝权限!",Toast.LENGTH_SHORT).show() // 用户拒绝了,你想咋办? } return; } // 可以识别其他请求码并处理 } }

这样授权过程就完成了。然后为了提高授权的概率,对流程进行了优化。

5.优化授权流程,增加授权概率。

首先,我们不能自定义系统授权窗口,但是我们可以在此之前做一个指南。在触发系统弹窗之前,会弹出一个引导UI,告知用户将要申请权限,并说明所需权限能带来什么更好的体验。尤其是当你申请的权限看起来和主体功能无关的时候,比如某个相机app需要申请定位权限的时候。

其次,Google官方还提供了一个函数shouldshowrequestpermission(),可以用来判断用户上次是否拒绝,没有选择,所以不会再问。在授权之前,可以通过该判断来决定向用户显示第一授权引导或非第一授权引导。

最后,当用户仍然选择拒绝授权时,如果是必要权限(比如导航软件申请定位权限),我们可以处理授权回调,当用户点击拒绝时,会弹出一个向导通知用户该功能不可用,引导用户在设置中重新授权或手动开启权限。

以上三个部分的大致流程如下:

授权过程

综上所述,动态权限的主要实现步骤

在AndroidManifest明确我们需要哪些权限。(非动态权限也需要此步)在执行操作前检是否获得对应授权 -> checkSelfPermission()。如果已授权可以继续操作;如果未授权,判断之前是否授权被拒 -> shouldShowRequestPermissionRationale() (非必须操作)a) 判断如果没有被拒过,弹出首次授权引导。b) 判断如果被据过,弹出非首次授权引导。引导后,申请权限-> requestPermissions()。处理申请的结果信息-> 回调函数onRequestPermissionsResult()。

系统提供以下四个功能来完成动态权限相关操作。

/** * 检查指定的权限是否授权(Context对象调用) */ public static int checkSelfPermission (Context context, String permission) /** * 在没有授权的情况下,有些时候可能需要提示给用户为什么需要改权限,就通过该函数来实现。 * 关于shouldShowRequestPermissionRationale的返回值问题,我们分三种情况 * 1. 第一次打开App时 -> false * 2. 上次弹出权限点击了禁止(但没有勾选“下次不在询问”) -> true * 3. 上次选择禁止并勾选:下次不在询问 -> false */ public static boolean shouldShowRequestPermissionRationale (Activity activity, String permission) /** * 申请指定的权限(Activity或者Fragment对象调用) * @param permissions 权限列表,可以同时申请多个权限 * @param requestCode 该次权限申请对应的requestCode。和 onRequestPermissionsResult()回调函数里面的requestCode对应 */ public static void requestPermissions (Activity activity, String[] permissions, int requestCode) /** * 处理请求权限的响应,当用户对请求权限的dialog做出响应之后,系统会回调该函数(Activity或者Fragment中重写) * @param requestCode 申请权限对应的requestCode * @param permissions 权限列表 * @param grantResults 权限列表对应的返回值,判断permissions里面的每个权限是否申请成功 */ public abstract void onRequestPermissionsResult (int requestCode, String[] permissions, int[] grantResults)

至此,动态授权实现的演示部分已经完成,实际的业务场景肯定比上面的流程复杂得多。

系统版本兼容性

动态权限是Android 6.0的新特性。6.0以下系统的适配代码怎么写?

首先想到的是判断系统版本,6.0及以上用动态权限码,低版本用旧码。

fun test(){ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) // 走动态授权 return else // 走非动态授权 return }

其实你不用这么麻烦。对于低配版,没必要单独写代码适配。在不支持动态授权的系统上,Manifest中应用的权限checkSelfPermission()方法将直接返回PERMISSION_GRANTED。

另外,根据系统版本来区分是否支持动态权限,其实也不靠谱。如前所述,部分手机厂商在ROM升级到Android 6.0后阉割了动态权限功能。目前还没有找到准确的API来确定当前系统是否支持动态权限。这会带来什么问题?

举一个最近遇到的例子。App的功能之一就是向别人展示我所在的城市(地理位置是敏感数据)。用户反馈关闭系统定位权限后,仍会显示其所在城市。我们需要考虑如何解决用户的问题,所以我们加了一个要求,如果用户关闭了位置权限,城市就不会被获取。那么问题来了。如何判断用户是否关闭了位置权限?为了避免不支持动态权限的ROM,只能退一步需求。6.0及以上系统做上述逻辑,6.0及以下不直接获取地理位置。但是根据测试经验,6.0以上的系统还是不一定支持动态权限,7.0以上的系统,大部分rom都支持动态权限。所以折中的决定是7.0以下的设备都不会被获取,用7.0以上的checkSelfPermission()来判断是否被授权。少数不支持动态权限的设备会被误认为授权设备,需要增加设置项关闭功能。(升级到Android8.0应该是绝对安全的,但是覆盖面太小)

以下是目前国内主流厂商对动态权限的支持。(测试方法:新安装未授权时,使用checkSelfPermission()检查PHONE_STATE、location和camera权限,返回如果是PERMISSION_GRANTED,则认为不支持动态权限)

基于Android6.0的ROM基于Android7.0的ROM小米支持华为,OPPO,VIVO,7.1.1,7.1.2,部分权限,魅族,锤子,360,中兴。

关于权限弹出窗口1.授权弹出元素

Android 8.0授权弹出窗口

权限组iconApp名称申请的权限允许、拒绝 操作不再询问选项多弹窗索引2.有没有不要再问的选项?

关于权限弹出,对于同一个App的同一个权限,有时候弹出没有“拒绝&不再询问”选项,有时候有。下面是谷歌原生系统和小米MIUI系统的两个弹窗对比。这是什么原因呢?Android原生实现:App新安装后第一次申请权限,弹窗没有这个选项,也就是图片左边的效果。当用户拒绝授权时,App下次申请该权限时会采取该选项,也就是图右边的效果。而国内部分手机厂商并不遵循这个标准,比如华为基于Android 10的系统,OPPO/VIVO的部分权限。不管是不是第一次,授权弹窗都采取这个选项。这是系统行为,App决定不了。

Pixel2不再问

MIUI不再问了

3.App设置中弹出选项和权限选项的对应关系

系统的授权弹窗其实有3项(允许、拒绝、拒绝不再问)。但是,一些系统在设置中有两个(允许、拒绝)和三个(允许、询问、拒绝)应用权限选项。授权弹出选项与设置中选项的对应关系如下。

以原生Android 10系统为例:

弹窗 允许 -> 设置 允许;弹窗 拒绝 -> 设置 拒绝;弹窗 拒绝&不再询问 -> 设置 拒绝 (跟上一项UI一致,本质有区别)。

Pixel2弹出窗口对应设置

以基于Android 9.0的MIUI10.4.8为例:

弹窗 允许 -> 设置 允许;弹窗 拒绝 -> 设置 询问;弹窗 拒绝&不再询问 -> 设置 拒绝。

MIUI弹出窗口对应设置

4.弹出选项对四个功能的影响。

弹出窗口,用户操作指定选项后,下一次调用四个函数时,会出现以下现象:

UI选项和函数调用结果

分类

Android 6.0系统初期,权限分为普通权限、签名权限和危险权限,其中签名权限是超类的,只介绍普通权限和危险权限。

其中,常用权限使用方式与低版本相同,只需在Manifest中申请即可使用。大多数低风险权限不需要以确认框的形式显示用户的同意。比如接入网络,检查WiFi状态等。

另一种危险权限,即本文介绍的对象,主要是为了保护用户的隐私而产生的。换句话说,一些涉及用户隐私的权限属于危险权限。比如:相机权限、定位权限、PHONE_STATE权限等。

危险和权限组。(不同的系统可能有不同的危险许可)

危险的权威

关于权限,还有权限组的概念。例如,读取外部存储权限(READ_EXTERNAL_STORAGE)和写入外部存储权限(WRITE_EXTERNAL_STORAGE)属于存储权限组(STORAGE)。

权限的作用是什么?在Android O之前,同一个权限组的权限,只要用户授权一个,就授权了整个权限组。

例如:

步骤1:将读取外部存储和写入外部存储添加到清单中

步骤2:在程序中只应用READ_EXTERNAL_STORAGE权限。在用户同意后

第三步:程序中不申请WRITE_EXTERNAL_STORAGE权限,尝试直接使用。

结果:可以直接使用,不需要申请同组权限。

Android O对此进行了修改。同一权限组的不同权限都必须动态申请权限。但是如果第一个用户同意,后面申请同一组权限时,不会再弹出窗口,而是直接同意。

例如:

步骤1:将读取外部存储和写入外部存储添加到清单中

步骤2:在程序中只应用READ_EXTERNAL_STORAGE权限。在用户同意后

第三步:程序中不申请WRITE_EXTERNAL_STORAGE权限,尝试直接使用。

结果:崩溃。

第三步:在程序中申请WRITE_EXTERNAL_STORAGE权限。

结果:不会弹出授权弹窗,直接自动授权同一个权限组。

但是,一些ROM修改了这个逻辑。比如华为9.0以下的系统都是遵循Android 8.0之前的逻辑,原生系统。但是华为的后9.0系统和小米的后6.0系统都采用了比原生Android 8.0系统更严格的逻辑。每个权限都需要单独申请,会有单独的弹出窗口要求用户确认。

例如:

步骤1:将读取外部存储和写入外部存储添加到清单中

步骤2:在程序中只应用READ_EXTERNAL_STORAGE权限。在用户同意后

第三步:在程序中申请WRITE_EXTERNAL_STORAGE权限。

结果:将弹出授权弹出窗口,要求用户再次授权。

问题:同一权限组内不同权限的授权弹窗是一样的。这导致用户非常愚蠢。明明刚刚授权了,何必再问我。

不同ROM权限组内的影响

所以在一些手机上,你会发现一些app会弹出两个访问文件存储的弹窗。那是因为我在写App的时候,先后申请了READ_EXTERNAL_STORAGE和WRITE_EXTERNAL_STORAGE的权限。怎么解决?

请看requestPermissions()方法的第二个参数,它是一个数组。也就是说,可以传入一个权限列表。

/** * 申请指定的权限(Activity或者Fragment对象调用) * @param permissions 权限列表,可以同时申请多个权限 * @param requestCode 该次权限申请对应的requestCode。和 onRequestPermissionsResult()回调函数里面的requestCode对应 */ public static void requestPermissions (Activity activity, String[] permissions, int requestCode)

经过测试,如果直接调整方法,同时传入READ_EXTERNAL_STORAGE和WRITE_EXTERNAL_STORAGE,只会弹出一个授权窗口,用户同意后可以同时获得两个权限。如果传入不同的权限组,将依次为每个组弹出一个弹出窗口。此外,当一次导入多组权限时,会在弹出窗口中出现一个m/n号,以标识哪个被退回以及还剩多少。下图分别是MIUI10(基于android9)和EMUI10(基于android10)的弹出风格:

Redmi Note8Pro持续授权窗口

华为Mate20连续授权窗口

写在最后

后期部分权限政策有所变化,仅部分住户感知较大。

IOS 8(2014年),定位权限选项分为“使用期间”(新增项)、“始终允许”、“不允许”。(减少App后台定位)IOS 10(2016年),App访问网络需要授权。Android 8.0(2017年),安装未知来源应用需要申请权限。(App自升级、三方应用市场、广告App安装其他App需申请权限)权限组授权问题修复,上文有提及。Android 10(2019年),定位权限选项分为“使用期间”(新增项)、“始终允许”、“拒绝”。(减少App后台定位)部分电话、蓝牙、WLAN的API,需要申请精确位置权限。无法再获取手机IMEIIOS 13(2019年),定位权限选项分为“使用App时允许”、“允许一次”(新增选项)、“不允许”,去除了“始终允许”。(“允许一次”相当于试用权限或临时权限,重启App后需要重新申请权限)Android 11 预览版(2020年),分区存储强制执行。Download目录、SD卡目录访问受限。对位置、麦克风、相机增加一次性权限许可,见IOS 13定位权限(即,如果用户选了一次性许可,重启App后需要重新申请权限)。自动阻止App重复的权限请求。也就是说如果用户点击2次拒绝授权,那么系统会自动停止询问授权,当然了,用户也可以前往设置中手动调整。

两个平台都在多个版本中对用户隐私进行了优化,只有定位权限的优化被多次提及。

可以看到,在手机逐渐转化为人体器官的今天,IOS和Android在权限和隐私的管理上越来越严格,收敛速度大约越来越快。估计以后安卓App要想接入网络需要申请授权。但是手机厂商自己定制修改ROM,仍然是开发者最头疼的问题。

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。

作者:美站资讯,如若转载,请注明出处:https://www.meizw.com/n/172203.html

发表回复

登录后才能评论