Android_TRY
Android_TRY
  • 发布:2019-04-20 17:46
  • 更新:2023-03-29 12:15
  • 阅读:24542

Android动态权限申请

分类:Native.js

更新:插件市场已经提供了封装更完善版本:https://ext.dcloud.net.cn/plugin?id=594

从HBuilderX1.9.4及以上版本开始,Android平台默认targetSdkVersion从21(Android5.0)调整为23(Android6.0)。

Android动态权限申请机制

Android6.0(API23)及以后,系统对权限的管理更加严格,放弃了以往manifest中注册所需权限,用户只要安装APP,便获取了所有注册权限的权限管理机制,而是改为除了需manifest中注册,部分危险权限另需在用户使用某项特殊功能时,向用户动态申请的机制。

当用户手机系统为Android6.0及以上,APP的targetSdkVersion>=23时,新的动态权限申请机制将会被触发,其它所有情况(1.系统版本>=6.0,targetSdkVersion<23;2.系统版本<6.0,targetSdkVersion>=23;3.系统版本<6.0,targetSdkVersion<23)都不会触发动态权限申请机制,因此,如果你不想在APP中动态申请权限,可以将targetSdkVersion设置为小于23。如不然,你就需要在使用某些涉及危险权限的功能(如读取通讯录)时通过系统弹窗的形式向用户动态申请该权限。动态申请权限下,如果用户在权限申请弹窗中拒绝了该申请,则用户将不能使用需要该权限的功能,再次申请该权限时依然会弹窗向用户申请;若用户在权限申请弹窗中勾选了“不再提示”并拒绝,那么再次申请该权限的时候将不会弹出系统弹窗向用户申请权限,此时需要APP引导用户打开设置,在设置中给与APP所需权限。
注意:云端打包targetSdkVersion默认值为26

5+APP中动态权限申请机制的实现

5+APP各独立模块中已经集成了功能所需权限的动态申请机制,开发者无需另做处理。但是如果需要使用某些尚未集成的特殊功能,如通过native.js调用原生方法获取手机扫描到的wifi列表,由于android可以通过访问wifi获取位置信息,因此需要在使用原生方法前先动态申请该功能所需的ACCESS_FINE_LOCATION权限。正因为有这样的需求,DCloud在native.js中为Android提供了动态申请权限的功能。

开发者通过调用plus.android.requestPermissions申请权限。参数permissions为所需权限数组;resultCallback为申请结果回调,将会返回已获取的权限、拒绝本次申请的权限、永久拒绝申请的权限3种结果的权限列表,开发者可以读取各权限申请结果并做相应处理;errorCallback为权限参数格式错误时调用,返回错误信息。

代码举例

依然以获取wifi列表为例,使用该功能前需要开发者先申请所需权限ACCESS_FINE_LOCATION:

function requestPermission() {  
    plus.android.requestPermissions(  
    ["android.permission.ACCESS_FINE_LOCATION"],  
    function(resultObj){  
        for (var i = 0; i < resultObj.granted.length; i++) {  
            var grantedPermission = resultObj.granted[i];  
            console.log('已获取的权限:'+ grantedPermission);  
        }  
        for (var i = 0; i < resultObj.deniedPresent.length; i++) {  
            var deniedPresentPermission = resultObj.deniedPresent[i];  
            console.log('拒绝本次申请的权限:'+ deniedPresentPermission );  
        }  
        for (var i = 0; i < resultObj.deniedAlways.length; i++) {  
            var deniedAlwaysPermission = resultObj.deniedAlways[i];  
            console.log('永久拒绝申请的权限:'+ deniedAlwaysPermission);  
        }  
        // 若所需权限被永久拒绝,则打开APP设置界面,可以在APP设置界面打开相应权限  
        if (resultObj.deniedAlways.length > 0) {  
            var Intent = plus.android.importClass("android.content.Intent");  
            var Settings = plus.android.importClass("android.provider.Settings");  
            var Uri = plus.android.importClass("android.net.Uri");  
            var mainActivity = plus.android.runtimeMainActivity();  
            var intent = new Intent();  
            intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);  
            var uri = Uri.fromParts("package", mainActivity.getPackageName(), null);  
            intent.setData(uri);  
            mainActivity.startActivity(intent);  
        }  
    },  
    function(error){  
        console.log('申请权限错误:'+ error.code+ " = "+ error.message);  
    });  
}

引导用户打开所需权限的方法分析

当需要引导用户打开特定权限时,最理想的情况是打开一个只有该权限开关的页面让用户开启权限,但是Android会将应用申请的所有权限集中在一个页面,因此从Android系统提供的功能的角度讲,最好是能引导用户进入应用的权限管理页面,在这个页面中让用户根据提示打开相应权限。然而,国内厂商早在Android未提供动态权限申请功能时就对Android应用的权限申请进行了改造和封装,这就使开发者无法通过统一的入口进入应用权限管理页面,而需要通过各个厂商自己的入口进入,如

// 华为  
Intent intent = new Intent(packageName);  
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);  
ComponentName comp = new ComponentName("com.huawei.systemmanager", "com.huawei.permissionmanager.ui.MainActivity");  
intent.setComponent(comp);  
mContext.startActivity(intent);  
// 魅族  
Intent intent = new Intent("com.meizu.safe.security.SHOW_APPSEC");  
intent.addCategory(Intent.CATEGORY_DEFAULT);  
intent.putExtra("packageName", packageName);  
mContext.startActivity(intent);

这无疑加大了开发难度。而且各厂商更可能随着版本的升级更改权限管理入口,这就加大了开发的不确定性。因此,我们推荐的最理想的引导用户打开权限的入口是应用设置页面,然后用户通过点击“权限管理”自主进入权限管理页面进行相关权限的设置。
5+APP中利用native.js打开应用设置页面的方法见上方代码举例。

附Android危险权限列表

  • SMS(短信)
    android.permission.SEND_SMS
    android.permission.RECEIVE_SMS
    android.permission.READ_SMS
    android.permission.RECEIVE_WAP_PUSH
    android.permission.RECEIVE_MMS

  • STORAGE(存储卡,包括相册等)
    android.permission.READ_EXTERNAL_STORAGE
    android.permission.WRITE_EXTERNAL_STORAGE

  • CONTACTS(联系人)
    android.permission.READ_CONTACTS
    android.permission.WRITE_CONTACTS
    android.permission.GET_ACCOUNTS

  • PHONE(手机)
    android.permission.READ_PHONE_STATE
    android.permission.CALL_PHONE
    android.permission.READ_CALL_LOG
    android.permission.WRITE_CALL_LOG
    android.permission.ADD_VOICEMAIL
    android.permission.USE_SIP
    android.permission.PROCESS_OUTGOING_CALLS

  • CALENDAR(日历)
    android.permission.READ_CALENDAR
    android.permission.WRITE_CALENDAR

  • CAMERA(相机)
    android.permission.CAMERA

  • LOCATION(位置)
    android.permission.ACCESS_FINE_LOCATION
    android.permission.ACCESS_COARSE_LOCATION

  • SENSORS(传感器)
    android.permission.BODY_SENSORS

  • MICROPHONE(麦克风)
    android.permission.RECORD_AUDIO

Android官方权限概述(需翻墙)
Android官方权限列表(需翻墙)

相关问题

【报Bug】新版本hbuilder不支持安卓WIFI的扫描

iOS权限检查见:https://ask.dcloud.net.cn/article/35915

9 关注 分享
菜鸡 BoredApe vvipLin 小王子888 靓崽 l***@foxmail.com y***@gaosuxing.cn o***@163.com 无所谓001

要回复文章请先登录注册

m***@163.com

m***@163.com

回复 BJ_Q :
层主有没有发现在App.vue里动态申请权限,真机调试的话正常,放到手机上第二次登录才弹窗询问权限?解决方法是不在App.vue里面申请权限,放在登录页或者什么别的地方。
2019-06-28 10:46
BJ_Q

BJ_Q

回复 BJ_Q :
http://www.html5plus.org/doc/zh_cn/android.html#plus.android.requestPermissions
2019-06-10 20:02
BJ_Q

BJ_Q

我需要通过plus.device.uuid获取uuid,第一次安装的时候可以获取到,以后再次获取uuid,就获取不到了,那么我怎么动态权限申请呢("targetSdkVersion" : "26",)
2019-06-10 19:49
Android_TRY

Android_TRY (作者)

回复 Rico大叔 :
"webview调试打开的时候"是什么意思?
2019-06-05 11:01
Rico大叔

Rico大叔

为啥只有webview调试打开的时候才能执行~~
2019-06-04 16:27
comtom1

comtom1

回复 Android_TRY :
谢谢,已经可以正常调出权限了
2019-05-30 13:57
Android_TRY

Android_TRY (作者)

回复 comtom1 :
HBuilder已经不更新了,使用最新的HBuilderX吧。
2019-05-30 12:07
comtom1

comtom1

回复 Android_TRY :
HBuilder

Hbuilder 9.1不能调用plus.android.requestPermissions 吗
2019-05-30 12:02
comtom1

comtom1

回复 半晴雨滴 :
我也是报这个错,请问你解决了吗
2019-05-30 11:59
Android_TRY

Android_TRY (作者)

回复 8***@qq.com :
iOS平台没有封装好的权限相关功能,你可以用NJS的方法试试。
2019-05-20 16:16