Initial commit
This commit is contained in:
366
ak/PermissionManager.uts
Normal file
366
ak/PermissionManager.uts
Normal file
@@ -0,0 +1,366 @@
|
||||
/**
|
||||
* PermissionManager.uts
|
||||
*
|
||||
* Utility class for managing Android permissions throughout the app
|
||||
* Handles requesting permissions, checking status, and directing users to settings
|
||||
*/
|
||||
|
||||
/**
|
||||
* Common permission types that can be requested
|
||||
*/
|
||||
export enum PermissionType {
|
||||
BLUETOOTH = 'bluetooth',
|
||||
LOCATION = 'location',
|
||||
STORAGE = 'storage',
|
||||
CAMERA = 'camera',
|
||||
MICROPHONE = 'microphone',
|
||||
NOTIFICATIONS = 'notifications',
|
||||
CALENDAR = 'calendar',
|
||||
CONTACTS = 'contacts',
|
||||
SENSORS = 'sensors'
|
||||
}
|
||||
|
||||
/**
|
||||
* Result of a permission request
|
||||
*/
|
||||
type PermissionResult = {
|
||||
granted: boolean;
|
||||
grantedPermissions: string[];
|
||||
deniedPermissions: string[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Manages permission requests and checks throughout the app
|
||||
*/
|
||||
export class PermissionManager {
|
||||
/**
|
||||
* Maps permission types to the actual Android permission strings
|
||||
*/
|
||||
private static getPermissionsForType(type: PermissionType): string[] {
|
||||
switch (type) {
|
||||
case PermissionType.BLUETOOTH:
|
||||
return [
|
||||
'android.permission.BLUETOOTH_SCAN',
|
||||
'android.permission.BLUETOOTH_CONNECT',
|
||||
'android.permission.BLUETOOTH_ADVERTISE'
|
||||
];
|
||||
case PermissionType.LOCATION:
|
||||
return [
|
||||
'android.permission.ACCESS_FINE_LOCATION',
|
||||
'android.permission.ACCESS_COARSE_LOCATION'
|
||||
];
|
||||
case PermissionType.STORAGE:
|
||||
return [
|
||||
'android.permission.READ_EXTERNAL_STORAGE',
|
||||
'android.permission.WRITE_EXTERNAL_STORAGE'
|
||||
];
|
||||
case PermissionType.CAMERA:
|
||||
return ['android.permission.CAMERA'];
|
||||
case PermissionType.MICROPHONE:
|
||||
return ['android.permission.RECORD_AUDIO'];
|
||||
case PermissionType.NOTIFICATIONS:
|
||||
return ['android.permission.POST_NOTIFICATIONS'];
|
||||
case PermissionType.CALENDAR:
|
||||
return [
|
||||
'android.permission.READ_CALENDAR',
|
||||
'android.permission.WRITE_CALENDAR'
|
||||
];
|
||||
case PermissionType.CONTACTS:
|
||||
return [
|
||||
'android.permission.READ_CONTACTS',
|
||||
'android.permission.WRITE_CONTACTS'
|
||||
];
|
||||
case PermissionType.SENSORS:
|
||||
return ['android.permission.BODY_SENSORS'];
|
||||
default:
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get appropriate display name for a permission type
|
||||
*/
|
||||
private static getPermissionDisplayName(type: PermissionType): string {
|
||||
switch (type) {
|
||||
case PermissionType.BLUETOOTH:
|
||||
return '蓝牙';
|
||||
case PermissionType.LOCATION:
|
||||
return '位置';
|
||||
case PermissionType.STORAGE:
|
||||
return '存储';
|
||||
case PermissionType.CAMERA:
|
||||
return '相机';
|
||||
case PermissionType.MICROPHONE:
|
||||
return '麦克风';
|
||||
case PermissionType.NOTIFICATIONS:
|
||||
return '通知';
|
||||
case PermissionType.CALENDAR:
|
||||
return '日历';
|
||||
case PermissionType.CONTACTS:
|
||||
return '联系人';
|
||||
case PermissionType.SENSORS:
|
||||
return '身体传感器';
|
||||
default:
|
||||
return '未知权限';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a permission is granted
|
||||
* @param type The permission type to check
|
||||
* @returns True if the permission is granted, false otherwise
|
||||
*/
|
||||
static isPermissionGranted(type: PermissionType): boolean {
|
||||
// #ifdef APP-ANDROID
|
||||
try {
|
||||
const permissions = this.getPermissionsForType(type);
|
||||
const activity = UTSAndroid.getUniActivity();
|
||||
|
||||
if (activity == null || permissions.length === 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check each permission in the group
|
||||
for (const permission of permissions) {
|
||||
if (!UTSAndroid.checkSystemPermissionGranted(activity, [permission])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
} catch (e) {
|
||||
console.error(`Error checking ${type} permission:`, e);
|
||||
return false;
|
||||
}
|
||||
// #endif
|
||||
|
||||
// #ifndef APP-ANDROID
|
||||
return true; // Non-Android platforms don't need explicit permission checks
|
||||
// #endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Request a permission from the user
|
||||
* @param type The permission type to request
|
||||
* @param callback Function to call with the result of the permission request
|
||||
* @param showRationale Whether to show a rationale dialog if permission was previously denied
|
||||
*/
|
||||
static requestPermission(
|
||||
type: PermissionType,
|
||||
callback: (result: PermissionResult) => void,
|
||||
showRationale: boolean = true
|
||||
): void {
|
||||
// #ifdef APP-ANDROID
|
||||
try {
|
||||
const permissions = this.getPermissionsForType(type);
|
||||
const activity = UTSAndroid.getUniActivity();
|
||||
|
||||
if (activity == null || permissions.length === 0) {
|
||||
callback({
|
||||
granted: false,
|
||||
grantedPermissions: [],
|
||||
deniedPermissions: permissions
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if already granted
|
||||
let allGranted = true;
|
||||
for (const permission of permissions) {
|
||||
if (!UTSAndroid.checkSystemPermissionGranted(activity, [permission])) {
|
||||
allGranted = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (allGranted) {
|
||||
callback({
|
||||
granted: true,
|
||||
grantedPermissions: permissions,
|
||||
deniedPermissions: []
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// Request the permissions
|
||||
UTSAndroid.requestSystemPermission(
|
||||
activity,
|
||||
permissions,
|
||||
(granted: boolean, grantedPermissions: string[]) => {
|
||||
if (granted) {
|
||||
callback({
|
||||
granted: true,
|
||||
grantedPermissions: grantedPermissions,
|
||||
deniedPermissions: []
|
||||
});
|
||||
} else if (showRationale) {
|
||||
// Show rationale dialog
|
||||
this.showPermissionRationale(type, callback);
|
||||
} else {
|
||||
// Just report the denial
|
||||
callback({
|
||||
granted: false,
|
||||
grantedPermissions: grantedPermissions,
|
||||
deniedPermissions: this.getDeniedPermissions(permissions, grantedPermissions)
|
||||
});
|
||||
}
|
||||
},
|
||||
(denied: boolean, deniedPermissions: string[]) => {
|
||||
callback({
|
||||
granted: false,
|
||||
grantedPermissions: this.getGrantedPermissions(permissions, deniedPermissions),
|
||||
deniedPermissions: deniedPermissions
|
||||
});
|
||||
}
|
||||
);
|
||||
} catch (e) {
|
||||
console.error(`Error requesting ${type} permission:`, e);
|
||||
callback({
|
||||
granted: false,
|
||||
grantedPermissions: [],
|
||||
deniedPermissions: this.getPermissionsForType(type)
|
||||
});
|
||||
}
|
||||
// #endif
|
||||
|
||||
// #ifndef APP-ANDROID
|
||||
// Non-Android platforms don't need explicit permissions
|
||||
callback({
|
||||
granted: true,
|
||||
grantedPermissions: this.getPermissionsForType(type),
|
||||
deniedPermissions: []
|
||||
});
|
||||
// #endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Show a rationale dialog explaining why the permission is needed
|
||||
*/
|
||||
private static showPermissionRationale(
|
||||
type: PermissionType,
|
||||
callback: (result: PermissionResult) => void
|
||||
): void {
|
||||
const permissionName = this.getPermissionDisplayName(type);
|
||||
|
||||
uni.showModal({
|
||||
title: '权限申请',
|
||||
content: `需要${permissionName}权限才能使用相关功能`,
|
||||
confirmText: '去设置',
|
||||
cancelText: '取消',
|
||||
success: (result) => {
|
||||
if (result.confirm) {
|
||||
this.openAppSettings();
|
||||
callback({
|
||||
granted: false,
|
||||
grantedPermissions: [],
|
||||
deniedPermissions: this.getPermissionsForType(type)
|
||||
});
|
||||
} else {
|
||||
callback({
|
||||
granted: false,
|
||||
grantedPermissions: [],
|
||||
deniedPermissions: this.getPermissionsForType(type)
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Open the app settings page
|
||||
*/
|
||||
static openAppSettings(): void {
|
||||
// #ifdef APP-ANDROID
|
||||
try {
|
||||
const context = UTSAndroid.getAppContext();
|
||||
if (context != null) {
|
||||
const intent = new android.content.Intent();
|
||||
intent.setAction("android.settings.APPLICATION_DETAILS_SETTINGS");
|
||||
const uri = android.net.Uri.fromParts("package", context.getPackageName(), null);
|
||||
intent.setData(uri);
|
||||
intent.addFlags(android.content.Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
context.startActivity(intent);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('Failed to open app settings', e);
|
||||
uni.showToast({
|
||||
title: '请手动前往系统设置修改应用权限',
|
||||
icon: 'none',
|
||||
duration: 3000
|
||||
});
|
||||
}
|
||||
// #endif
|
||||
|
||||
// #ifndef APP-ANDROID
|
||||
uni.showToast({
|
||||
title: '请在系统设置中管理应用权限',
|
||||
icon: 'none',
|
||||
duration: 2000
|
||||
});
|
||||
// #endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to get the list of granted permissions
|
||||
*/
|
||||
private static getGrantedPermissions(allPermissions: string[], deniedPermissions: string[]): string[] {
|
||||
return allPermissions.filter(p => !deniedPermissions.includes(p));
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to get the list of denied permissions
|
||||
*/
|
||||
private static getDeniedPermissions(allPermissions: string[], grantedPermissions: string[]): string[] {
|
||||
return allPermissions.filter(p => !grantedPermissions.includes(p));
|
||||
}
|
||||
|
||||
/**
|
||||
* Request multiple permission types at once
|
||||
* @param types Array of permission types to request
|
||||
* @param callback Function to call when all permissions have been processed
|
||||
*/
|
||||
static requestMultiplePermissions(
|
||||
types: PermissionType[],
|
||||
callback: (results: Map<PermissionType, PermissionResult>) => void
|
||||
): void {
|
||||
if (types.length === 0) {
|
||||
callback(new Map());
|
||||
return;
|
||||
}
|
||||
|
||||
const results = new Map<PermissionType, PermissionResult>();
|
||||
let remaining = types.length;
|
||||
|
||||
for (const type of types) {
|
||||
this.requestPermission(
|
||||
type,
|
||||
(result) => {
|
||||
results.set(type, result);
|
||||
remaining--;
|
||||
|
||||
if (remaining === 0) {
|
||||
callback(results);
|
||||
}
|
||||
},
|
||||
true
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method to request Bluetooth permissions
|
||||
* @param callback Function to call after the permission request
|
||||
*/
|
||||
static requestBluetoothPermissions(callback: (granted: boolean) => void): void {
|
||||
this.requestPermission(PermissionType.BLUETOOTH, (result) => {
|
||||
// For Bluetooth, we also need location permissions on Android
|
||||
if (result.granted) {
|
||||
this.requestPermission(PermissionType.LOCATION, (locationResult) => {
|
||||
callback(locationResult.granted);
|
||||
});
|
||||
} else {
|
||||
callback(false);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user