uniapp_05_权限检测和跳转到设置

关于 uniapp 权限申请和跳转系统页面

  • 测试环境
  • 查询权限
  • 跳转到应用详情
  • 跳转到系统设置
  • 参考

测试环境

  • Android 测试环境1:雷电模拟器 HUAWEI LIO-AN00 系统版本 9
  • Android 测试环境2:1+ace2 系统版本 13

查询权限

uni.authorize 获取权限只支持微信小程序不支持app,只能用 Native.js 来实现

  1. android 查询权限

    • 安卓

      太多不想写

    • uniapp

      plus.android.requestPermissions(permissions, successCb, errorCB)

      • permissions: 需要查询的权限数组 ps 此文中只封装了一次查询一个权限,需要的自己改
      • successCb:成功回调 有三个参数
        • granted - Array[String]字符串数组,已获取权限列表
        • deniedPresent - Array[String]字符串数据,已拒绝(临时)的权限列表
        • deniedAlways - Array[String]字符串数据,永久拒绝的权限列表
      • errorCB: 失败回调
        // permissionID:传入对应的权限常量
        // 1: 授权 -1:永久拒绝 0:暂时拒绝
        requestAndroidPermission(permissionID) {
            return new Promise((resolve, reject)=>{
                plus.android.requestPermissions(
                    [permissionID],
                    (res)=>{
                        const { granted, deniedPresent, deniedAlways } = res;
                        if(granted.length) resolve(1);
                        if(deniedPresent.length) resolve(0);
                        if(deniedAlways.length) resolve(-1);
                    },
                    (err)=>{ resolve({...err})}
                )
            })
        }
    
  2. android 只验证权限

    • 安卓

      网上讲验证的 api 是 android.support.v4.content.ContextCompat 下面的 checkSelfPermission 方法,但是我导入后,使用时报错提示没有这个方法。查找文档之后发现在 android.core.app.ActivityCompat 下存在 checkSelfPermission 方法但是导入后使用,依旧报错。仔细看包之后发现 content,ActivityCompat 有些方法好像被 Native.js 整合进入 plus.android.runtimeMainActivity() 里面了,这样的话等下我想下我以前是不是导入了很多不需要导入的包emmm

    • uniapp

      plus.android.runtimeMainActivity().checkSelfPermission('权限')
      返回: 0: 无授权 1: 以授权

          // 验证是否存在定位权限
          const main = plus.android.runtimeMainActivity();
          main.checkSelfPermission('android.permission.ACCESS_FINE_LOCATION')
      
  3. ios 查询权限

    看最后的代码,很烦要导入不同的包

跳转到应用详情

  1. android 跳转

    setData : 传入的是uri,用于数据的过滤。setData可以被系统用来寻找匹配目标组件。
    putExtra: 只是用来设定各种不同类型的附加数据。不被系统用来寻找匹配目标组件。
    直接跳转应用详情里的权限页需要适配不同品牌的手机 (用雷电模拟器试了华为的发现没用)

    • 安卓
          Intent intent = new Intent();
          intent.setAction(android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
          intent.setData(Uri.parse("package:" + this.getPackageName()));
          startActivity(intent);
      
    • uniapp
          // 跳转到应用详情
          const main = plus.android.runtimeMainActivity();
          const Intent = plus.android.newObject("android.content.Intent");
          // const Settings = plus.android.importClass("android.provider.Settings");
          const pkName = main.getPackageName();                
          const uri = plus.android.invoke("android.net.Uri", 'fromParts', 'package', pkName, null);
          // plus.android.invoke(Intent, 'setAction', Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
          // 直接用 android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTING 不行 我也不知道为啥
          plus.android.invoke(Intent, 'setAction', 'android.settings.APPLICATION_DETAILS_SETTINGS');
          plus.android.invoke(Intent, 'setData', uri);
          plus.android.invoke(main, 'startActivity', Intent);
      
      
          // 跳转到应用详情对应权限设置
          // 华为 (不生效)
          const main = plus.android.runtimeMainActivity();
          const Intent = plus.android.importClass('android.content.Intent');
          let _intent = new Intent();
          _intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
          const pkName = main.getPackageName();
          _intent.putExtra("packageName", pkName);
          const ComponentName = plus.android.importClass('android.content.ComponentName');
          const _comp = new ComponentName("com.huawei.systemmanager", "com.huawei.permissionmanager.ui.MainActivity");
          _intent.setComponent(_comp);
          main.startActivity(_intent);
      
  2. IOS 跳转

        // 跳转应用详情
        const app = plus.ios.invoke('UIApplication', 'sharedApplication');
        const setting = plus.ios.invoke('NSURL', 'URLWithString:', 'app-settings:');  
        plus.ios.invoke(app, 'openURL:', setting);  
        plus.ios.deleteObject(setting);  
        plus.ios.deleteObject(app); 
    

跳转到系统设置

  1. android 跳转系统设置页面

        const main = plus.android.runtimeMainActivity(),
        Settings = plus.android.importClass("android.provider.Settings");
        const Intent = plus.android.newObject('android.content.Intent', Settings.ACTION_SETTINGS);
        main.startActivity(Intent);
    
  2. android 跳转具体服务设置页面

        // 跳转到 打开系统定位服务页面
        const main = plus.android.runtimeMainActivity(),
        Intent = plus.android.importClass('android.content.Intent');
        const Settings = plus.android.importClass('android.provider.Settings');
        // let _intent = new Intent('android.settings.LOCATION_SOURCE_SETTINGS'); // 也可不需要Settings  直接这么写
        let _intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
        main.startActivity(_intent); // 打开系统设置GPS服务页面
    
  3. IOS 跳转系统设置页面

    看跳转应用

// 权限js
// #ifdef APP

// 判断推送权限是否开启
function judgeIosPermissionPush() {
	var result = false;
	var UIApplication = plus.ios.import("UIApplication");
	var app = UIApplication.sharedApplication();
	var enabledTypes = 0;
	if (app.currentUserNotificationSettings) {
		var settings = app.currentUserNotificationSettings();
		enabledTypes = settings.plusGetAttribute("types");
		if (enabledTypes == 0) {
		} else {
			result = true;
		}
		plus.ios.deleteObject(settings);
	} else {
		enabledTypes = app.enabledRemoteNotificationTypes();
		if (enabledTypes == 0) {
		} else {
			result = true;
		}
	}
	plus.ios.deleteObject(app);
	plus.ios.deleteObject(UIApplication);
	return result;
}

// 判断定位权限是否开启
function judgeIosPermissionLocation() {
	var result = false;
	var cllocationManger = plus.ios.import("CLLocationManager");
	var status = cllocationManger.authorizationStatus();
	if (status == 0 || status == 3) {
		result = true;
	} else {
		if (status == 2) {
			// gotoAppSetting('我们需要访问您的位置,方便更加迅速的给您解决问题')
		}
	}
	plus.ios.deleteObject(cllocationManger);
	return result;
}

// 判断麦克风权限是否开启
function judgeIosPermissionRecord() {
	var result = false;
	var avaudiosession = plus.ios.import("AVAudioSession");
	var avaudio = avaudiosession.sharedInstance();
	var permissionStatus = avaudio.recordPermission();
	if (permissionStatus == 1684369017 || permissionStatus == 1970168948) {
	} else {
		result = true;
	}
	plus.ios.deleteObject(avaudiosession);
	return result;
}

// 判断相机权限是否开启
function judgeIosPermissionCamera() {
	var result = false;
	var AVCaptureDevice = plus.ios.import("AVCaptureDevice");
	var authStatus = AVCaptureDevice.authorizationStatusForMediaType('vide');
	if (authStatus == 0 || authStatus == 3) {
		result = true
	} else {
		if (authStatus == 2) {
			// gotoAppSetting('请先允许使用相机权限')
		}
	}
	plus.ios.deleteObject(AVCaptureDevice);
	return result;
}

// 判断相册权限是否开启
function judgeIosPermissionPhotoLibrary() {
	var result = false;
	var PHPhotoLibrary = plus.ios.import("PHPhotoLibrary");
	var authStatus = PHPhotoLibrary.authorizationStatus();
	if (authStatus == 0 || authStatus == 3) {
		result = true;
	} else {
		if (authStatus == 2) {
			// gotoAppSetting('请先允许访问相册权限')
		}
	}
	plus.ios.deleteObject(PHPhotoLibrary);
	return result;
}

// 判断通讯录权限是否开启
function judgeIosPermissionContact() {
	var result = false;
	var CNContactStore = plus.ios.import("CNContactStore");
	var cnAuthStatus = CNContactStore.authorizationStatusForEntityType(0);
	if (cnAuthStatus == 0 || cnAuthStatus == 3) {
		result = true;
	} else {
	}
	plus.ios.deleteObject(CNContactStore);
	return result;
}

// 判断日历权限是否开启
function judgeIosPermissionCalendar() {
	var result = false;
	var EKEventStore = plus.ios.import("EKEventStore");
	var ekAuthStatus = EKEventStore.authorizationStatusForEntityType(0);
	if (ekAuthStatus == 0 || ekAuthStatus == 3) {
		result = true;
	} else {
	}
	plus.ios.deleteObject(EKEventStore);
	return result;
}

// 判断备忘录权限是否开启
function judgeIosPermissionMemo() {
	var result = false;
	var EKEventStore = plus.ios.import("EKEventStore");
	var ekAuthStatus = EKEventStore.authorizationStatusForEntityType(1);
	if (ekAuthStatus == 0 || ekAuthStatus == 3) {
		result = true;
	} else {
	}
	plus.ios.deleteObject(EKEventStore);
	return result;
}

class Permission {
    #_permissonList: {
        'contact': { // 通讯录
           'android': 'android.permission.WRITE_CONTACTS',
           'ios': 'CNContactStore'
        },
        'calendar': { // 日历-写
            'android': 'android.permission.WRITE_CALENDAR',
            'ios': 'CNContactStore'
        },
        'location': { // 定位
            'android': 'android.permission.ACCESS_FINE_LOCATION',
            'ios': 'CLLocationManager'
        },
        'sms': { // 发-信息
            'android': 'android.permission.SEND_SMS',
            'ios': ''
        },
        'storage': { // 外部存储和相册-写
            'android': 'android.permission.WRITE_EXTERNAL_STORAGE',
            'ios': 'PHPhotoLibrary'
        },
        'camera': { // 摄像头
            'android': 'android.permission.CAMERA',
            'ios': 'AVCaptureDevice'
        },
        'record': { // 麦克风
            'android': 'android.permission.RECORD_AUDIO',
            'ios': 'AVAudioSession'
        },
    },
    #_androidAppActionList: { // 跳转应用的
        'push': 'android.settings.APP_NOTIFICATION_SETTINGS', // app的通知权限开关页面
        
    },
    #_systemActionList: { // 跳转系统设置页面
        'location': { // gps开关页面
            'android': 'android.settings.LOCATION_SOURCE_SETTINGS',
            'ios': ''
        }
    },
    
    constructor () {
        // 判断手机系统和系统版本
        let os = plus.os.name; // 系统名称
        this.isIos = os == 'iOS'; // 是否是ios系统
        if(this.isIos) {
            this.version = plus.os.version; // 版本
        } else {
            const Build = plus.android.importClass("android.os.Build");
            this.version = Build?.VERSION?.SDK_INT ?? 0;
        }
    }
    
    /**
     * @method requestAndroidPermission
     * @param {String} permissionID 安卓的权限
     * @description android 动态申请权限
     * @return {Number | Object} -1: 拒绝权限(永久) 0: 拒绝权限(临时)1:授权 || { code:'错误码', message:"错误描述" }
     */
    requestAndroidPermission (permissionID) {
        return new Promise((resolve, reject)=>{
            // TODO 需要添加验证权限的函数 
            // FIXME ContextCompat.checkSelfPermission() 可以验证是否存某权限
            plus.android.requestPermissions(
                [permissionID],
                (res)=>{
                    const { granted, deniedPresent, deniedAlways } = res;
                    if(granted.length) resolve(1);       // 以获取到权限
                    if(deniedPresent.length) resolve(0); // 已拒绝权限(临时)
                    if(deniedAlways.length) resolve(-1); // 已拒绝权限(永久)
                },
                (err)=>{
                	// message: 错误信息描述 code   : 错误编码
                	resolve({...err});
                }
            )
        })
    }
    
    /**
     * @method verifyNotification
     * @return {Boolean} true: 存在权限 false: 无权限
     * @description 获取**app**推送授权状态
     */
    verifyNotification() {
        if (this.isIos) {
            let types = 0;
            const app = plus.ios.invoke('UIApplication', 'sharedApplication');
            const settings = plus.ios.invoke(app, 'currentUserNotificationSettings');
            if(settings) {
            	types = settings.plusGetAttribute('types');
            } else {
            	types = plus.ios.invoke(app, 'enabledRemoteNotificationTypes');  
            }
            plus.ios.deleteObject(settings);
            plus.ios.deleteObject(app);
            return types != 0;
        } else {
            const main = plus.android.runtimeMainActivity();
            let NotificationManagerCompat = plus.android.importClass("android.support.v4.app.NotificationManagerCompat");
            if (NotificationManagerCompat == null) { 
            	NotificationManagerCompat = plus.android.importClass("androidx.core.app.NotificationManagerCompat"); 
            }  
            const areNotificationsEnabled = NotificationManagerCompat.from(main).areNotificationsEnabled();
            return areNotificationsEnabled;
        }
    },
    
    
    /**
     * @method verifyPermission
     * @param {String} name 权限名称
     * @description 验证是否存在授权
     * @return {boolean} false: 拒绝 true:授权
     */
    verifyPermission (name='') {
        if(this.isIos) {
            // 需要单独处理 去调用上面方法
        } else {
            const main = plus.android.runtimeMainActivity();
            const state = main.checkSelfPermission(this.#_permissonList[name]['android']);
            return state == 1;
        }
    }
    
    /**
     * @method jumpAppDataPage
     * @description 跳转到**应用**的信息页面
     */
    jumpAppInfoPage () {
        if (this.isIos) {
            const app = plus.ios.invoke('UIApplication', 'sharedApplication');
            const setting = plus.ios.invoke('NSURL', 'URLWithString:', 'app-settings:');  
            plus.ios.invoke(app, 'openURL:', setting);  
            plus.ios.deleteObject(setting);  
            plus.ios.deleteObject(app); 
        } else {
            const main = plus.android.runtimeMainActivity();
            const Intent = plus.android.newObject("android.content.Intent");
            // const Settings = plus.android.importClass("android.provider.Settings");              
            const uri = plus.android.invoke("android.net.Uri", 'fromParts', 'package', main.getPackageName(), null);
            // plus.android.invoke(Intent, 'setAction', Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
            plus.android.invoke(Intent, 'setAction', `android.settings.APPLICATION_DETAILS_SETTINGS`);
            plus.android.invoke(Intent, 'setData', uri);
            plus.android.invoke(main, 'startActivity', Intent);
        }
    }
    
    /**
     * @method JumpAppPermissionPage
     * @description 跳转到**应用**的授权开关页面 (ps: 这里也可以用来到设置页面啥的毕竟核心代码一样,但是懒得改了 )
     */
    JumpAppPermissionPage (action='push') {
        if(this.isIos) {
            this.jumpAppInfoPage();
        } else {
            const main = plus.android.runtimeMainActivity();
            const pkName = main.getPackageName();
            const uid = main.getApplicationInfo().plusGetAttribute("uid");
            const Intent = plus.android.newObject('android.content.Intent', this.#_androidActionList[action]); 
            
            if(this.version >= 26) { // 8.0
                Intent.putExtra('android.provider.extra.APP_PACKAGE', pkName);
                Intent.putExtra('android.provider.extra.CHANNEL_ID', uid);
                main.startActivity(Intent);
            } else if(this.version >= 21) { // 5.0-7.1
                Intent.putExtra("app_package", pkName);
                Intent.putExtra("app_uid", uid);  
                main.startActivity(Intent);
            } else {
                this.jumpAppInfoPage();
            }
        }
    },
    
    /**
     * @method verifySystemLocationServe
     * @description 验证**系统**定位服务是否开启
     */
    verifySystemLocationServe () {
        if (this.isIos)  {
            // TODO 需要更具不同服务进行封装
            
            // 验证定位服务是否开启的
            var result = false;
            var cllocationManger = plus.ios.import("CLLocationManager");
            var result = cllocationManger.locationServicesEnabled();
            plus.ios.deleteObject(cllocationManger);
            return result;
        } else {
            const main = plus.android.runtimeMainActivity(),
                  context = plus.android.importClass("android.content.Context"),
                  locationManager = plus.android.importClass("android.location.LocationManager");
            const mainSvr = main.getSystemService(context.LOCATION_SERVICE);
            return mainSvr.isProviderEnabled(locationManager.GPS_PROVIDER)
        }
    },
    
    /**
     * @method jumpSystemAppointPage
     * @description 跳转到指定的**系统**设置页面 (使用之前先确定 页面是可以直接跳转的)
     */
    jumpSystemAppointPage (action="location") {
        if (this.isIos) { 
            
        } else {
            const main = plus.android.runtimeMainActivity();
            const Intent = plus.android.newObject('android.content.Intent', this.#_systemActionList[action]['android']);
            main.startActivity(Intent); // 打开系统设置GPS服务页面
        }
    }
    
    /**
     * @method jumpSystemPage
     * @description 跳转到系统设置页面
     */
    jumpSystemPage () {
        if (this.isIos) {
            this.jumpAppInfoPage();
        } else {
            const main = plus.android.runtimeMainActivity();
            // const Settings = plus.android.importClass("android.provider.Settings");
            // const Intent = plus.android.newObject('android.content.Intent', Settings.ACTION_SETTINGS);
            const Intent = plus.android.newObject('android.content.Intent',`android.settings.SETTINGS`);
            main.startActivity(Intent);
        }
    }
}

// #endif

参考

  1. Android跳转系统界面_大全集

  2. Android之APP跳转到权限设置界面适配华为、小米、vivo等

  3. Android跳转具体应用权限管理,三种方式

  4. iOS调用系统功能与跳转到系统设置

  5. iOS 从应用中跳转至系统设置页面里的多种设置页面

  6. UIApplication方法和OpenUrl的基本用法

  7. 5+ App开发Native.js入门指南

  8. IOS10 打开系统设置

  9. iOS开发中的各种权限获取和检查

  10. android如何从应用程序进入设置的各个页面

  11. Android系统设置— android.provider.Settings

  12. Android中action启动方法大全

  13. Native.js示例汇总

posted @ 2023-10-19 16:25  tsuru  阅读(509)  评论(0编辑  收藏  举报