uni-app Android动态权限申请

发布于 1周前 作者 caililin 来自 Uni-App

uni-app Android动态权限申请

更新:插件市场已经提供了封装更完善版本: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时,新的动态权限申请机制将会被触发,其它所有情况都不会触发动态权限申请机制,因此,如果你不想在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);

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

附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权限检查


1 回复

在uni-app中,进行Android动态权限申请可以通过调用原生插件或者自定义原生模块来实现。由于uni-app主要使用Vue.js进行开发,我们需要结合原生Android代码来处理权限请求。以下是一个简要的实现步骤和代码示例。

步骤1:配置manifest.json

首先,在manifest.json中声明需要的权限。例如,如果你需要请求相机和存储权限,可以这样配置:

"mp-weixin": {
  "appid": "your-appid",
  "permission": {
    "scope.userInfo": {
      "desc": "你的用户信息将用于小程序体验优化"
    },
    // 其他微信小程序的权限配置
  }
},
"app-plus": {
  "distribute": {
    "android": {
      "permissions": [
        "android.permission.CAMERA",
        "android.permission.WRITE_EXTERNAL_STORAGE"
      ]
    }
  }
}

步骤2:创建自定义原生模块

nativePlugins目录下创建一个新的原生插件,例如PermissionRequest

Android原生代码

PermissionRequest/android/src/main/java/your/package/name/PermissionRequestModule.java中编写如下代码:

package your.package.name;

import android.Manifest;
import android.content.Context;
import android.content.pm.PackageManager;
import io.dcloud.feature.uniapp.bridge.UniJSCallback;
import io.dcloud.feature.uniapp.common.UniModule;
import io.dcloud.feature.uniapp.annotation.UniJSMethod;

public class PermissionRequestModule extends UniModule {

    @UniJSMethod(uiThread = true)
    public void requestPermissions(UniJSCallback callback) {
        String[] permissions = {Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE};
        if (checkSelfPermission(permissions) != PackageManager.PERMISSION_GRANTED) {
            requestPermissions(permissions, requestCode -> {
                if (requestCode == PackageManager.PERMISSION_GRANTED) {
                    callback.invoke("Permissions granted");
                } else {
                    callback.invoke("Permissions denied");
                }
            });
        } else {
            callback.invoke("Permissions already granted");
        }
    }

    // 省略checkSelfPermission和requestPermissions的实现
}

步骤3:在uni-app中调用原生模块

在Vue组件中,通过plus.android.importClassplus.android.runtimeMainActivity()调用原生模块:

methods: {
    requestPermissions() {
        const PermissionRequest = plus.android.importClass('your.package.name.PermissionRequestModule');
        const main = plus.android.runtimeMainActivity();
        const permissionRequest = new PermissionRequest(main);
        permissionRequest.requestPermissions((result) => {
            console.log(result);
        });
    }
}

总结

以上代码展示了如何在uni-app中实现Android动态权限申请。通过配置manifest.json,创建自定义原生模块,并在Vue组件中调用原生方法,我们可以实现对Android权限的动态申请和处理。注意,这只是一个基础示例,实际项目中可能需要处理更多的权限和更复杂的情况。

回到顶部