React-Native开发鸿蒙NEXT-权限处理
.markdown-body h1, .markdown-body h2, .markdown-body h3, .markdown-body h4, .markdown-body h5, .markdown-body h6 { line-height: 1.5; margin-top: 35px; margin-bottom: 10px; padding-bottom: 5px }
.markdown-body h1 { font-size: 24px; line-height: 38px; margin-bottom: 5px }
.markdown-body h2 { font-size: 22px; line-height: 34px; padding-bottom: 12px; border-bottom: 1px solid rgba(236, 236, 236, 1) }
.markdown-body h3 { font-size: 20px; line-height: 28px }
.markdown-body h4 { font-size: 18px; line-height: 26px }
.markdown-body h5 { font-size: 17px; line-height: 24px }
.markdown-body h6 { font-size: 16px; line-height: 24px }
.markdown-body p { line-height: inherit; margin-top: 22px; margin-bottom: 22px }
.markdown-body img { max-width: 100% }
.markdown-body hr { border-top: 1px solid rgba(221, 221, 221, 1); border-right: none; border-bottom: none; border-left: none; margin-top: 32px; margin-bottom: 32px }
.markdown-body code { border-radius: 2px; overflow-x: auto; background-color: rgba(255, 245, 245, 1); color: rgba(255, 80, 44, 1); font-size: 0.87em; padding: 0.065em 0.4em }
.markdown-body code, .markdown-body pre { font-family: Menlo, Monaco, Consolas, Courier New, monospace }
.markdown-body pre { overflow: auto; position: relative; line-height: 1.75 }
.markdown-body pre>code { font-size: 12px; padding: 15px 12px; margin: 0; word-break: normal; display: block; overflow-x: auto; color: rgba(51, 51, 51, 1); background: rgba(248, 248, 248, 1) }
.markdown-body a { text-decoration: none; color: rgba(2, 105, 200, 1); border-bottom: 1px solid rgba(209, 233, 255, 1) }
.markdown-body a:active, .markdown-body a:hover { color: rgba(39, 91, 140, 1) }
.markdown-body table { display: inline-block !important; font-size: 12px; width: auto; max-width: 100%; overflow: auto; border: 1px solid rgba(246, 246, 246, 1) }
.markdown-body thead { background: rgba(246, 246, 246, 1); color: rgba(0, 0, 0, 1); text-align: left }
.markdown-body tr:nth-child(2n) { background-color: rgba(252, 252, 252, 1) }
.markdown-body td, .markdown-body th { padding: 12px 7px; line-height: 24px }
.markdown-body td { min-width: 120px }
.markdown-body blockquote { color: rgba(102, 102, 102, 1); padding: 1px 23px; margin: 22px 0; border-left: 4px solid rgba(203, 203, 203, 1); background-color: rgba(248, 248, 248, 1) }
.markdown-body blockquote:after { display: block; content: "" }
.markdown-body blockquote>p { margin: 10px 0 }
.markdown-body ol, .markdown-body ul { padding-left: 28px }
.markdown-body ol li, .markdown-body ul li { margin-bottom: 0; list-style: inherit }
.markdown-body ol li .task-list-item, .markdown-body ul li .task-list-item { list-style: none }
.markdown-body ol li .task-list-item ol, .markdown-body ol li .task-list-item ul, .markdown-body ul li .task-list-item ol, .markdown-body ul li .task-list-item ul { margin-top: 0 }
.markdown-body ol ol, .markdown-body ol ul, .markdown-body ul ol, .markdown-body ul ul { margin-top: 3px }
.markdown-body ol li { padding-left: 6px }
.markdown-body .contains-task-list { padding-left: 0 }
.markdown-body .task-list-item { list-style: none }
@media (max-width: 720px) { .markdown-body h1 { font-size: 24px } .markdown-body h2 { font-size: 20px } .markdown-body h3 { font-size: 18px } }.markdown-body pre, .markdown-body pre>code.hljs { color: rgba(51, 51, 51, 1); background: rgba(248, 248, 248, 1) }
.hljs-comment, .hljs-quote { color: rgba(153, 153, 136, 1); font-style: italic }
.hljs-keyword, .hljs-selector-tag, .hljs-subst { color: rgba(51, 51, 51, 1); font-weight: 700 }
.hljs-literal, .hljs-number, .hljs-tag .hljs-attr, .hljs-template-variable, .hljs-variable { color: rgba(0, 128, 128, 1) }
.hljs-doctag, .hljs-string { color: rgba(221, 17, 68, 1) }
.hljs-section, .hljs-selector-id, .hljs-title { color: rgba(153, 0, 0, 1); font-weight: 700 }
.hljs-subst { font-weight: 400 }
.hljs-class .hljs-title, .hljs-type { color: rgba(68, 85, 136, 1); font-weight: 700 }
.hljs-attribute, .hljs-name, .hljs-tag { color: rgba(0, 0, 128, 1); font-weight: 400 }
.hljs-link, .hljs-regexp { color: rgba(0, 153, 38, 1) }
.hljs-bullet, .hljs-symbol { color: rgba(153, 0, 115, 1) }
.hljs-built_in, .hljs-builtin-name { color: rgba(0, 134, 179, 1) }
.hljs-meta { color: rgba(153, 153, 153, 1); font-weight: 700 }
.hljs-deletion { background: rgba(255, 221, 221, 1) }
.hljs-addition { background: rgba(221, 255, 221, 1) }
.hljs-emphasis { font-style: italic }
.hljs-strong { font-weight: 700 }
React-Native开发鸿蒙NEXT-权限处理
原创 悬空八只脚 悬空八只脚 2024年11月01日 20:34 江苏
开发app首先绕不开的就是权限隐私处理。
RN中对app权限的获取判断涉及到原生与js的交互,比起原生app的直接请求需要考虑交互过程中的异常处理。利用RN开发HarmonyOS Next应用同样,下面结合项目看看如何在原生(ArkTS)与RN(js)间进行权限请求交互。
尽管现在越来越强调仅在需要时进行动态请求,一般还是会把权限做成应用启动批量请求默认权限和具体使用时动态申请。为此,在RN代码中,构建了SpecSystemTurboModule类,分别提供初始默认批量请求和动态请求方法。
SpecSystemTurboModule.tsx
import {TurboModule, TurboModuleRegistry} from 'react-native';
// 使用自定义的TurboModules
export interface SpecSystemTurboModule extends TurboModule {
......
// 校验初始化权限
checkedPermission(): void;
// 查询指定权限
queryPermission(permissionEnum: string): void;
......
}
export default TurboModuleRegistry.getEnforcing<SpecSystemTurboModule>(
'SystemTurboModule',
);
鉴于Android端对权限请求的要求,将启动时默认的批量请求触发放置在用户同意隐私协议之后。由于目前尚未将新工程适配andorid与ios,暂时判断下操作系统类型只针对鸿蒙系统。
xx页面.tsx
/**
* 刷新隐私协议同意状态
*/
const doRefreshPrivacyAgreeState = async () => {
// 判断用户是否同意过隐私协议
let _privacyAgreeState = await getData('privacyAgreeState');
if (_privacyAgreeState == null || _privacyAgreeState == 'no') {
setShowPrivacyPolicy(true);
} else {
......
if (Platform.OS === 'harmony') {
// TODO:权限校验
SystemTurboModule.checkedPermission();
}
......
}
};
初始权限请求由于仅会在应用启动时请求一次,对于权限请求的接收,在根页面(app.tsx)中定义消息监听。
App.tsx
function App(): JSX.Element {
......
// 权限校验/申请结果的监听
const permissionResultEventEmitterRef = useRef(null);
useEffect(() => {
......
permissionResultEventEmitterRef.current = DeviceEventEmitter.addListener(
'......name111',
(data: string) => {
console.log(App.TAG + ' permissionResult = ' + data);
try {
// todo:这是针对鸿蒙权限的处理,不同的系统申请的权限名称数量不一样,需要做针对性处理
// todo:现在实现了RN测拿到原生对权限结果的返回,可以在RN里针对原生的权限情况做针对处理了
let result = JSON.parse(data);
let permissions = JSON.parse(result.data.value);
console.log(typeof permissions);
......对数据的业务处理
} catch (e) {
console.log(TAG + 'permissionResult ERROR = ' + e);
}
},
);
return () => {
......
permissionResultEventEmitterRef.current &&
permissionResultEventEmitterRef.current.remove();
......
};
}, []);
......
}
对于动态请求部分,则在需要的时候先请求权限,根据返回结果判断是否执行和请求相关的动作,这里以项目中利用react-native-image-picker更行用户个人头像为例。
在点击用户头像时,先请求相机权限
xxx页面.tsx
const check = async select => {
......
if (select == 0) {
//更新头像
checkPermission();
}
......
}
const checkPermission = () => {
if (Platform.OS === 'harmony') {
// TODO:先权限校验,根据结果打开相机
SystemTurboModule.queryPermission('CAMERA');
}
}
同样,这页面中定义用于接收动态权限请求的消息监听,根据返回结果判断是否成功获取了权限,进而决定是提示用户没有权限还是去打开相机。注意这里定义的消息名称和初始化批量获取是两个分开的。动态请求是更加普遍的方式,初始批量请求存在审核被拒风险,尽可能按需请求权限。
const queryPermissionResultEventEmitterRef = useRef(null);
......
queryPermissionResultEventEmitterRef.current =
DeviceEventEmitter.addListener(
'......name222',
(data: string) => {
console.log(TAG + ' queryPermissionResultListener = ' + data);
if (global.TAG === TAG) {
try {
// todo:这是针对鸿蒙权限的处理,不同的系统申请的权限名称数量不一样,需要做针对性处理
let result = JSON.parse(data);
let permissions = JSON.parse(result.data.value);
permissions.map(item => {
if (
item.permission &&
item.permission === 'CAMERA' &&
item.result == 0
) {
// 打开相机
selectPic();
} else {
xnToast('请打开相机权限!');
}
});
} catch (e) {
console.log(TAG + 'permissionResult ERROR = ' + e);
}
}
},
);
......
接下来看下原生部分。用于交互的SystemTurboModule中,通过emitter抛出原生消息
SystemTurboModule.ets
import emitter from '@ohos.events.emitter';
import ConstUtil from '../utils/ConstUtil';
......
export interface TurboModuleEventData {
param: string
}
export class SystemTurboModule extends TurboModule {
......
checkedPermission() {
console.log("checkedPermission.log from SystemTurboModule: ")
emitter.emit(ConstUtil.event_id_check_permissions,{});
}
queryPermission(permissionEnum: string) {
console.log("queryPermission.log from SystemTurboModule: ")
let data: TurboModuleEventData = { param: permissionEnum }
emitter.emit(ConstUtil.event_id_query_permission,{data});
}
......
}
原生部分对权限的处理集中在EntryAbility.ets。
onWindowStageCreate中定义消息接收。
通过@ohos.abilityAccessCtrl类完成权限的请求。默认权限其实是在ArkTS中直接定义的,动态申请时,由于ios/android/harmony对于权限名称定义的不同,同样需要根据参数做一对一的匹配(是否存在类似ClassFromName的方式?)。
3.获取的结果同样通过emitter抛给index.ets,之所以这样是因为在index中有构造RN容器的创建方法,可以获取到当前bundle的RN对象实例。
import { RNAbility, RNOHCoreContext } from '@rnoh/react-native-openharmony';
import window from '@ohos.window';
import { emitter } from '@kit.BasicServicesKit';
import abilityAccessCtrl, { Context, PermissionRequestResult, Permissions } from '@ohos.abilityAccessCtrl';
import { hilog } from '@kit.PerformanceAnalysisKit';
import { JSON } from '@kit.ArkTS';
import common from '@ohos.app.ability.common';
import { PermissionResult } from '../model/DataModel'
import ConstUtil from '../utils/ConstUtil'
import { App } from '@kit.ArkUI';
export let preferences: dataPreferences.Preferences | null = null
let atManager: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager();
let appAccessTokenId:number = -1;
export default class EntryAbility extends RNAbility {
onWindowStageCreate(windowStage: window.WindowStage): void {
......
// 校验初始化权限
emitter.on(ConstUtil.event_id_check_permissions, () => {
console.info('event_id_check_permissions');
this.checkPermissions();
});
// 使用前申请权限权限
emitter.on(ConstUtil.event_id_query_permission, (data) => {
try{
console.info('event_id_check_permission and data = ' + JSON.stringify(data));
if(data.data){
this.queryPermission(data.data.param);
}
} catch (e) {
}
});
......
}
public checkPermissions(){
if (appAccessTokenId != -1) {
atManager.requestPermissionsFromUser(getContext(this),
['ohos.permission.ACCESS_BLUETOOTH',
'ohos.permission.APPROXIMATELY_LOCATION',
'ohos.permission.LOCATION',
]
).then((data: PermissionRequestResult) => {
let authResults:Array<PermissionResult> = new Array;
authResults.push(new PermissionResult('ACCESS_BLUETOOTH',data.authResults[0]))
// authResults.push(new PermissionResult('CAMERA',data.authResults[1]));// 相机权限在使用之前单独申请(鸿蒙要求)
authResults.push(new PermissionResult('APPROXIMATELY_LOCATION',data.authResults[2]));
authResults.push(new PermissionResult('LOCATION',data.authResults[3]));
let eventData: emitter.EventData = {
data: {
"key": "permissionResult",
"value":JSON.stringify(authResults),
}
};
// 发送给index.ets,在index里通过rnInstance发送给js
emitter.emit(ConstUtil.event_id_check_permission_result,eventData);
}).catch((err: BusinessError) => {
console.error('data:' + JSON.stringify(err));
});
}else{
hilog.error(0x0000, 'testTag', 'checkPermissions failed: %{public}s', "xxxxxx");
}
}
/**
* 临时申请权限
*/
public queryPermission(permissionString:string){
if (appAccessTokenId != -1) {
let permissions:Array<Permissions> = new Array;
// 转换
if(permissionString === 'CAMERA'){
permissions.push('ohos.permission.CAMERA');
}
if(permissions.length > 0){
atManager.requestPermissionsFromUser(getContext(this),
permissions
).then((data: PermissionRequestResult) => {
let authResults:Array<PermissionResult> = new Array;
authResults.push(new PermissionResult(permissionString,data.authResults[0]));
let eventData: emitter.EventData = {
data: {
"key": "queryPermissionResult",
"value":JSON.stringify(authResults),
}
};
// 发送给index.ets,在index里通过rnInstance发送给js
emitter.emit(ConstUtil.event_id_query_permission_result,eventData);
}).catch((err: BusinessError) => {
console.error('data:' + JSON.stringify(err));
});
}
}else{
hilog.error(0x0000, 'testTag', 'checkPermissions failed: %{public}s', "xxxxxx");
}
}
......
}
在index.ets中,主要实现向RN发送权限获取结果。
- 在aboutToAppear生命周期中注册消息接收
- 利用当前bundle对应的RN实例向RN发送消息
import {
AnyJSBundleProvider,
ComponentBuilderContext,
FileJSBundleProvider,
MetroJSBundleProvider,
ResourceJSBundleProvider,
RNApp,
RNSurface,
RNOHErrorDialog,
LogBoxDialog,
LogBoxTurboModule,
RNOHLogger,
TraceJSBundleProviderDecorator,
RNOHCoreContext,
RNInstance,
RNComponentContext,
RNOHContext,
buildRNComponentForTag,
} from '@rnoh/react-native-openharmony'
import { SampleView, PropsDisplayer, GeneratedSampleView } from "@rnoh/sample-package"
import {
RNLinearGradient,
LINEAR_GRADIENT_TYPE,
LinearGradientDescriptor
} from "@react-native-oh-tpl/react-native-linear-gradient"
import ConstUtil from '../utils/ConstUtil'
import { emitter } from '@kit.BasicServicesKit';
import window from '@ohos.window';
import PrecreateRN from './PrecreateRN';
import { arkTsComponentNames } from "../rn/LoadBundle"
import { createRNPackages, LoadManager, buildCustomComponent, ENABLE_CAPI_ARCHITECTURE } from '../rn';
import { rnPackageEventData, TurboModuleEventData } from '../TurboModule/SystemTurboModule';
import json from '@ohos.util.json';
@Entry
@Component
struct Index {
private _rnInstance?: RNInstance | null;
aboutToAppear() {
......
// 注册原生发送给rn的emitter
this.registerNativeToJsEmitter();
......
}
registerNativeToJsEmitter() {
......
// 权限校验结果
emitter.on(ConstUtil.event_id_check_permission_result, (data) => {
console.info('event_id_check_permissions and data = ' + JSON.stringify(data));
this.sendDeviceEvent(ConstUtil.event_native_to_js_permission_result, JSON.stringify(data));
});
this._rnInstance = LoadManager.metroInstance;
......
}
sendDeviceEvent(eventName: string, payload: string) {
if (this._rnInstance != null) {
console.error('向js发送消息, eventName = ' + eventName || '' + " and payload = " + payload || '');
this._rnInstance.emitDeviceEvent(eventName, payload);
} else {
console.error('_rnInstance 为 null!!!无法向js发送消息');
}
}
......
}
以上便是RN开发HarmonyOS NEXT应用中权限处理的一种处理方式,同时也是RN与原生交互的通用方法,整体基于RN的TurboModules。对于ios与android,只需针对各自系统开发原生代码处理权限,在RN端需要针对不同操作系统返回的权限处理结果做分类处理,当然也可以在原生端做下统一的封装。
微信扫一扫
关注该公众号悬空八只脚
React-Native开发鸿蒙NEXT-权限处理的更多相关文章
- React Native 开发笔记
ReactNativeDemo 学习ReactNative开发,搭建ReactNative第一个项目 React Native 开发笔记 1.安装Homebrew $ /usr/bin/ruby -e ...
- 搭建基本的React Native开发环境
步骤如下: 1.安装HomeBrew,命令如下: 在终端输入命令:$ ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Home ...
- React Native 开发环境安装和配置使用报错: -bash: react-native: command not found
[React Native 开发环境安装和配置:-bash: react-native: command not found 报错: 前提是安装homebrew,node.js ,npm ,watc ...
- Mac配置React Native开发环境
一直觉得学习一样东西,不动手怎么也学不会,就像学习swift,看了视频没有动手操作,记住的也就那么点,自己写出东西不是这里有问题就是那里出错. 所以,以后学习自己要多动手. 现在我的学习任务就是: 提 ...
- React Native开发入门
目录: 一.前言 二.什么是React Native 三.开发环境搭建 四.预备知识 五.最简单的React Native小程序 六.总结 七.参考资料 一.前言 虽然只是简单的了解了一下Reac ...
- React Native开发技术周报2
(1).资讯 1.React Native 0.22_rc版本发布 添加了热自动重载功能 (2).技术文章 1.用 React Native 设计的第一个 iOS 应用 我们想为用户设计一款移动端的应 ...
- React Native开发技术周报1
(一).资讯 1.React Native 0.21版本发布,最新版本功能特点,修复的Bug可以看一下已翻译 重要:如果升级 Android 项目到这个版本一定要读! 我们简化了 Android 应用 ...
- DECO 一个REACT NAtive 开发IDE工具
DECO 一个REACT NAtive 开发IDE工具. 目前只支持 OS,NO WINDOWS https://www.decosoftware.com/ 一个方便的快速 ERXPRESS 教程:h ...
- React Native 开发之 (02) 用Sublime 3作为React Native的开发IDE
Sublime Text是一个代码编辑器.也是HTML和散文先进的文本编辑器.漂亮的用户界面和非凡的功能,例如:迷你地图,多选择Python插件,代码段等等.完全可自定义键绑定,菜单和工具栏等等.漂亮 ...
- 【转】【React Native开发】
[React Native开发]React Native控件之ListView组件讲解以及最齐全实例(19) [React Native开发]React Native控件之Touchable*系列组 ...
随机推荐
- Visual Studio 卸载
1.找个安装镜像文件 2.必须以管理员身份运行cmd 3.在CMD里输入"G:\vs_professional.exe /uninstall /force" 4.企业版就把prof ...
- ESP AT指令使用记录
一.前言 本篇文章主要用于记录自己在使用AT指令时候的流程,记录一些资料与程序等.如果能帮到你,请给我点个赞. 二.背景知识 ESP-AT是什么? ESP-AT 是乐鑫开发的可直接用于量产的物联网应用 ...
- 寻找旋转排序数组中的最小值 II
地址:https://leetcode-cn.com/problems/find-minimum-in-rotated-sorted-array-ii/ <?php /** 154. 寻找旋转排 ...
- python进程 - 调试报错 you are not using fork to start your child processes
在走这段代码的时候报错了,记录一下我的调试过程,感觉有个思路来走就挺好的. 1.报错与解决 文件名字:ClassifierTest.py import torch import torchvision ...
- nginx 根据 URL 参数引入不同的文件
同步发布:https://blog.jijian.link/2020-06-30/nginx-import-file/ 编程世界中各种奇奇怪怪的需求都有,本次遇到一个需求:根据URL参数判断,包含 x ...
- Golang 入门 : 创建第一个Go程序
创建第一个Go程序 新建一个 helloworld.go 文件,写入以下程序 package main import ( "fmt" ) // 一个函数声明 /* 一个main函数 ...
- Linux运维面试题之:Root密码忘记如何解决
目录 6.5 Root密码忘记如何解决 6.5.1 系统自带救援模式 6.5.2 U盘.光盘救援系统 6.5 Root密码忘记如何解决 解决方案有两种:自救,别人救 解决方案 应用场景 1️⃣ 系统自 ...
- linux 根目录扩容方法
准备知识 linux volume 1.(PV)physical volume disk : 物理硬盘 物理硬盘需要转换成lvm(logic volume manage)可识别的状态,将磁盘的syst ...
- MySQL中怎么分析性能?
MySQL中主要有4种方式可以分析数据库性能,分别是慢查询日志,profile,Com_xxx和explain. 慢查询日志 先用下面命令查询慢查询日志是否开启, show variables lik ...
- 【Java】网络编程
InternetAccess类的使用 一.概述 计算机网络: 把分布在不同地理区域的计算机与专门的外部设备用通信线路互连成一个规模大.功能强的网络系统,从而使众多的计算机可以方便地互相传递信息共享硬件 ...