权限申请
关于权限检测可参考官方文档: @ohos.abilityAccessCtrl (程序访问控制管理)
简单封装如下:
js
import { abilityAccessCtrl, Permissions, bundleManager, common } from '@kit.AbilityKit';
import { BusinessError } from '@kit.BasicServicesKit';
import { ToastUtil } from '@pura/harmony-utils';
/**
* 用于检测授权、申请授权
* API 文档: https://developer.huawei.com/consumer/cn/doc/harmonyos-references-V5/js-apis-abilityaccessctrl-V5#checkaccesstokensync10 */export class PermissionManager {
/**
* 判断授权,没有授权申请授权
* * @param permissions * @param callback */ static checkAndRequestPermission(permissions: Permissions, callback: (result: boolean) => void) {
if (PermissionManager.checkPermissions(permissions)) {
callback(true)
return
}
PermissionManager.requestPermission(permissions, callback)
}
static jumpToAppSetting() {
// 获取上下文
const context = getContext() as common.UIAbilityContext
// 获取包信息
const bundleInfo = bundleManager.getBundleInfoForSelfSync(bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_APPLICATION)
// 打开系统设置页
context.startAbility({
bundleName: 'com.huawei.hmos.settings',
abilityName: 'com.huawei.hmos.settings.MainAbility',
uri: 'application_info_entry',
parameters: {
// 按照包名打开对应设置页
pushParams: bundleInfo.name
}
})
}
/**
* 检查应用已经获取到权限
* @param permissions * @returns 如果应用已经获取到权限,返回true; 如果应用没获取过授权,或者用户拒绝了授权,返回false;
*/ static checkPermissions(permissions: Permissions): boolean {
// 程序访问控制管理
const atManager = abilityAccessCtrl.createAtManager();
// 获取 bundle 信息
const bundleInfo = bundleManager.getBundleInfoForSelfSync(bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_APPLICATION)
const tokenID: number = bundleInfo.appInfo.accessTokenId
// 校验应用是否被授予权限,同步返回结果
const authResult = atManager.checkAccessTokenSync(tokenID, permissions)
return authResult === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED;
}
/**
* 针对某个权限进行申请授权。弹窗授权只会弹出一次。如果已经授权过,会直接返回成功 或 失败
* * @param permissions * @param callback */ static requestPermission(permissions: Permissions, callback: (result: boolean) => void) {
// 程序访问控制管理
const atManager = abilityAccessCtrl.createAtManager();
// 拉起弹框请求用户授权
atManager.requestPermissionsFromUser(getContext(), [permissions]).then(data => {
const result = data.authResults.every(item => item === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED)
callback(result)
}).catch((e: BusinessError) => {
ToastUtil.showShort("申请权限失败:" + e.code)
})
}
}
import { abilityAccessCtrl, Permissions, bundleManager, common } from '@kit.AbilityKit';
import { BusinessError } from '@kit.BasicServicesKit';
import { ToastUtil } from '@pura/harmony-utils';
/**
* 用于检测授权、申请授权
* API 文档: https://developer.huawei.com/consumer/cn/doc/harmonyos-references-V5/js-apis-abilityaccessctrl-V5#checkaccesstokensync10 */export class PermissionManager {
/**
* 判断授权,没有授权申请授权
* * @param permissions * @param callback */ static checkAndRequestPermission(permissions: Permissions, callback: (result: boolean) => void) {
if (PermissionManager.checkPermissions(permissions)) {
callback(true)
return
}
PermissionManager.requestPermission(permissions, callback)
}
static jumpToAppSetting() {
// 获取上下文
const context = getContext() as common.UIAbilityContext
// 获取包信息
const bundleInfo = bundleManager.getBundleInfoForSelfSync(bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_APPLICATION)
// 打开系统设置页
context.startAbility({
bundleName: 'com.huawei.hmos.settings',
abilityName: 'com.huawei.hmos.settings.MainAbility',
uri: 'application_info_entry',
parameters: {
// 按照包名打开对应设置页
pushParams: bundleInfo.name
}
})
}
/**
* 检查应用已经获取到权限
* @param permissions * @returns 如果应用已经获取到权限,返回true; 如果应用没获取过授权,或者用户拒绝了授权,返回false;
*/ static checkPermissions(permissions: Permissions): boolean {
// 程序访问控制管理
const atManager = abilityAccessCtrl.createAtManager();
// 获取 bundle 信息
const bundleInfo = bundleManager.getBundleInfoForSelfSync(bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_APPLICATION)
const tokenID: number = bundleInfo.appInfo.accessTokenId
// 校验应用是否被授予权限,同步返回结果
const authResult = atManager.checkAccessTokenSync(tokenID, permissions)
return authResult === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED;
}
/**
* 针对某个权限进行申请授权。弹窗授权只会弹出一次。如果已经授权过,会直接返回成功 或 失败
* * @param permissions * @param callback */ static requestPermission(permissions: Permissions, callback: (result: boolean) => void) {
// 程序访问控制管理
const atManager = abilityAccessCtrl.createAtManager();
// 拉起弹框请求用户授权
atManager.requestPermissionsFromUser(getContext(), [permissions]).then(data => {
const result = data.authResults.every(item => item === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED)
callback(result)
}).catch((e: BusinessError) => {
ToastUtil.showShort("申请权限失败:" + e.code)
})
}
}
使用:
js
PermissionManager.checkAndRequestPermission('ohos.permission.READ_IMAGEVIDEO', result => {
if (!result) {
AlertDialog.show({
title: '温馨提示',
message: '无权限,是否前往设置中开启?\n',
buttons: [
{
value: '取消',
action: () => {
}
},
{
value: '前往设置',
enabled: true,
defaultFocus: true,
style: DialogButtonStyle.HIGHLIGHT,
action: () => {
PermissionManager.jumpToAppSetting()
}
}
],
cancel: () => {
}
})
}
})
PermissionManager.checkAndRequestPermission('ohos.permission.READ_IMAGEVIDEO', result => {
if (!result) {
AlertDialog.show({
title: '温馨提示',
message: '无权限,是否前往设置中开启?\n',
buttons: [
{
value: '取消',
action: () => {
}
},
{
value: '前往设置',
enabled: true,
defaultFocus: true,
style: DialogButtonStyle.HIGHLIGHT,
action: () => {
PermissionManager.jumpToAppSetting()
}
}
],
cancel: () => {
}
})
}
})
图片选择
需要注意:
- 先判断授权情况,用户拒绝的时候,适当给与提醒,让用户去设置中开启
- 图片选择后,需要复制到沙盒中进行读取
图片选择的简易封装示例:
js
import { photoAccessHelper } from '@kit.MediaLibraryKit';
import { PermissionManager } from './PermissionManager';
import { BusinessError } from '@kit.BasicServicesKit';
import { ToastUtil } from '@pura/harmony-utils';
import fs from '@ohos.file.fs'; // 导入文件管理模块
export enum PhotoPickerImageViaEnum {
//CAMERA = 'CAMERA',
PHOTO_LIBRARY = 'PHOTO_LIBRARY',
CAMERA_OR_PHOTO_LIBRARY = 'CAMERA_OR_PHOTO_LIBRARY'
}
export interface FileBuffer {
buffer: ArrayBuffer;
fileName: string;
}
export class PhotoPicker {
phAccessHelper: photoAccessHelper.PhotoAccessHelper;
constructor() {
let context = getContext(this);
this.phAccessHelper = photoAccessHelper.getPhotoAccessHelper(context);
}
// TODO: 图片压缩
selectImage(type: PhotoPickerImageViaEnum, count: number, callback: (photoUris: string[]) => void) {
PermissionManager.checkAndRequestPermission('ohos.permission.READ_IMAGEVIDEO', result => {
if (!result) {
AlertDialog.show({
title: '温馨提示',
message: '您没有相册访问权限,请到"设置-应用和元服务"中开启\n',
buttons: [
{
value: '取消',
action: () => {
}
},
{
value: '去设置',
enabled: true,
defaultFocus: true,
style: DialogButtonStyle.HIGHLIGHT,
action: () => {
// TODO: 可以改成 toAppSetting 这个方案
PermissionManager.jumpToAppSetting()
}
}
],
cancel: () => {
}
})
} else {
this.loadImage(type, count, callback)
}
})
}
/**
* 文件路径转为buffer (最好try catch起来) 。参考: https://ohpm.openharmony.cn/#/cn/detail/@ohos%2Faxios
*
* @param filePath
* @returns
*/
static fileToBuffer(filePath: string): FileBuffer {
// 上传图片必须将文件拷贝到沙盒
const file = fs.openSync(filePath, fs.OpenMode.READ_ONLY)
const fileName = file.name;
const newPath = getContext().cacheDir + '/' + fileName;
fs.copyFileSync(file.fd, newPath)
let file2 = fs.openSync(newPath, 0o2);
let stat = fs.lstatSync(newPath);
let buf2 = new ArrayBuffer(stat.size);
fs.readSync(file2.fd, buf2); // 以同步方法从流文件读取数据。
fs.fsyncSync(file2.fd);
fs.closeSync(file2.fd);
return { fileName, buffer: buf2 }
}
private loadImage(type: PhotoPickerImageViaEnum, count: number, callback: (photoUris: string[]) => void) {
try {
let photoPicker = new photoAccessHelper.PhotoViewPicker();
// 是否仅支持图片
const isPhotoTakingSupported = type != PhotoPickerImageViaEnum.PHOTO_LIBRARY
photoPicker.select({
isEditSupported: false,
isOriginalSupported: true,
maxSelectNumber: count,
isPhotoTakingSupported: isPhotoTakingSupported,
MIMEType: photoAccessHelper.PhotoViewMIMETypes.IMAGE_TYPE
}, (err: BusinessError, result: photoAccessHelper.PhotoSelectResult) => {
if (err) {
console.error(`PhotoViewPicker.select failed with err: ${err.code}, ${err.message}`);
ToastUtil.showShort("选择图片失败:" + err.code)
return;
}
callback(result.photoUris)
})
} catch (error) {
let err: BusinessError = error as BusinessError;
console.error(`PhotoViewPicker failed with err: ${err.code}, ${err.message}`);
}
}
}
import { photoAccessHelper } from '@kit.MediaLibraryKit';
import { PermissionManager } from './PermissionManager';
import { BusinessError } from '@kit.BasicServicesKit';
import { ToastUtil } from '@pura/harmony-utils';
import fs from '@ohos.file.fs'; // 导入文件管理模块
export enum PhotoPickerImageViaEnum {
//CAMERA = 'CAMERA',
PHOTO_LIBRARY = 'PHOTO_LIBRARY',
CAMERA_OR_PHOTO_LIBRARY = 'CAMERA_OR_PHOTO_LIBRARY'
}
export interface FileBuffer {
buffer: ArrayBuffer;
fileName: string;
}
export class PhotoPicker {
phAccessHelper: photoAccessHelper.PhotoAccessHelper;
constructor() {
let context = getContext(this);
this.phAccessHelper = photoAccessHelper.getPhotoAccessHelper(context);
}
// TODO: 图片压缩
selectImage(type: PhotoPickerImageViaEnum, count: number, callback: (photoUris: string[]) => void) {
PermissionManager.checkAndRequestPermission('ohos.permission.READ_IMAGEVIDEO', result => {
if (!result) {
AlertDialog.show({
title: '温馨提示',
message: '您没有相册访问权限,请到"设置-应用和元服务"中开启\n',
buttons: [
{
value: '取消',
action: () => {
}
},
{
value: '去设置',
enabled: true,
defaultFocus: true,
style: DialogButtonStyle.HIGHLIGHT,
action: () => {
// TODO: 可以改成 toAppSetting 这个方案
PermissionManager.jumpToAppSetting()
}
}
],
cancel: () => {
}
})
} else {
this.loadImage(type, count, callback)
}
})
}
/**
* 文件路径转为buffer (最好try catch起来) 。参考: https://ohpm.openharmony.cn/#/cn/detail/@ohos%2Faxios
*
* @param filePath
* @returns
*/
static fileToBuffer(filePath: string): FileBuffer {
// 上传图片必须将文件拷贝到沙盒
const file = fs.openSync(filePath, fs.OpenMode.READ_ONLY)
const fileName = file.name;
const newPath = getContext().cacheDir + '/' + fileName;
fs.copyFileSync(file.fd, newPath)
let file2 = fs.openSync(newPath, 0o2);
let stat = fs.lstatSync(newPath);
let buf2 = new ArrayBuffer(stat.size);
fs.readSync(file2.fd, buf2); // 以同步方法从流文件读取数据。
fs.fsyncSync(file2.fd);
fs.closeSync(file2.fd);
return { fileName, buffer: buf2 }
}
private loadImage(type: PhotoPickerImageViaEnum, count: number, callback: (photoUris: string[]) => void) {
try {
let photoPicker = new photoAccessHelper.PhotoViewPicker();
// 是否仅支持图片
const isPhotoTakingSupported = type != PhotoPickerImageViaEnum.PHOTO_LIBRARY
photoPicker.select({
isEditSupported: false,
isOriginalSupported: true,
maxSelectNumber: count,
isPhotoTakingSupported: isPhotoTakingSupported,
MIMEType: photoAccessHelper.PhotoViewMIMETypes.IMAGE_TYPE
}, (err: BusinessError, result: photoAccessHelper.PhotoSelectResult) => {
if (err) {
console.error(`PhotoViewPicker.select failed with err: ${err.code}, ${err.message}`);
ToastUtil.showShort("选择图片失败:" + err.code)
return;
}
callback(result.photoUris)
})
} catch (error) {
let err: BusinessError = error as BusinessError;
console.error(`PhotoViewPicker failed with err: ${err.code}, ${err.message}`);
}
}
}
文件上传(axios版)
js
static selectPictures(filePath: string, tag: string, webComponent: WebComponent | null) {
const pk = new PhotoPicker();
pk.selectImage(PhotoPickerImageViaEnum.CAMERA_OR_PHOTO_LIBRARY, 1, images => {
if (!images || images.length === 0) {
return
}
let formData = new FormData();
let imgBase64 = ''
const path = images[0];
try {
const bufferModel = PhotoPicker.fileToBuffer(path)
formData.append('file', bufferModel.buffer, { filename: bufferModel.fileName });
// https://developer.huawei.com/consumer/cn/doc/harmonyos-references-V2/js-apis-buffer-0000001478181693-V2#ZH-CN_TOPIC_0000001523488722__bufferfrom-1
const bf = buffer.from(bufferModel.buffer);
imgBase64 = bf.toString('base64')
} catch (error) {
ToastUtil.showShort('图片处理失败,' + error)
}
// TODO: 调用接口进行上传
})
}
static selectPictures(filePath: string, tag: string, webComponent: WebComponent | null) {
const pk = new PhotoPicker();
pk.selectImage(PhotoPickerImageViaEnum.CAMERA_OR_PHOTO_LIBRARY, 1, images => {
if (!images || images.length === 0) {
return
}
let formData = new FormData();
let imgBase64 = ''
const path = images[0];
try {
const bufferModel = PhotoPicker.fileToBuffer(path)
formData.append('file', bufferModel.buffer, { filename: bufferModel.fileName });
// https://developer.huawei.com/consumer/cn/doc/harmonyos-references-V2/js-apis-buffer-0000001478181693-V2#ZH-CN_TOPIC_0000001523488722__bufferfrom-1
const bf = buffer.from(bufferModel.buffer);
imgBase64 = bf.toString('base64')
} catch (error) {
ToastUtil.showShort('图片处理失败,' + error)
}
// TODO: 调用接口进行上传
})
}
调用接口,参考axois的文档,需要传入context:
js
/**
* 用于图片上传
* @param url
* @param formData
* @param baseURL
*/
export function upload(url: string, formData: FormData, baseURL: string = HttpConstant.BASE_URL) {
return http({
url: url,
data: formData,
method: 'post',
context: getContext(),
baseURL: baseURL,
timeout: 1000 * 15,
headers: {
'Content-Type': 'multipart/form-data'
},
})
}
/**
* 用于图片上传
* @param url
* @param formData
* @param baseURL
*/
export function upload(url: string, formData: FormData, baseURL: string = HttpConstant.BASE_URL) {
return http({
url: url,
data: formData,
method: 'post',
context: getContext(),
baseURL: baseURL,
timeout: 1000 * 15,
headers: {
'Content-Type': 'multipart/form-data'
},
})
}
参考文档
参考文档:
https://juejin.cn/post/7373681115746648103
https://developer.huawei.com/consumer/cn/doc/harmonyos-references-V5/js-apis-photoaccesshelper-V5#photoaccesshelper