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*系列组 ...
随机推荐
- MySQL 8.0下 200GB大表备份,利用传输表空间解决停服发版表备份问题
MySQL 8.0下 200GB大表备份,利用传输表空间解决停服发版表备份问题 问题背景 在停服发版更新的时候,需要预先对一个业务表进行备份,该业务表是200GB大小的表,大概200亿行数据. 因为 ...
- 市场教父 André Kostolany
大家好,我是 沃伦·爱德华·巴菲特(Warren Edward Buffett,1930 年 8 月 30 日 - ) 查尔斯·托马斯·芒格(Charles Thomas Munger,1924 年 ...
- CompletableFuture API介绍及使用
1. 介绍 CompletableFuture 是 Java 8 引入的一个用于异步编程的类,位于 java.util.concurrent 包中.它是对 Future 的增强,提供了更强大的功能来支 ...
- 使用SVM在数字验证码识别中的应用研究课程报告
第1章 概要设计 1.1 设计目的 支持向量机作为一类强大的监督学习模型,以其出色的泛化能力,在手写数字识别.面部检测.图像分类等多个领域展现出了其优越性.其在处理小样本.非线性及高维模式识别任务中表 ...
- Linux指令详解之:进程与系统负载
目录 5.4 进程(process) 5.4.1 守护进程 5.4.2 僵尸进程 5.4.3 孤儿进程 6.0 进程监控指令 6.0.1 ps(报告当前系统的进程状态) 6.0.2 ps aux 结果 ...
- 保姆级教程——手把手教会你如何在Linux上安装Redis
一.Linux系统安装Redis(7.4.0) 注意: 全程是在root底下操作,当然也可以采用sudo 1.1 安装Redis依赖 Redis是基于C语言编写的,因此首先需要安装Redis所需要的g ...
- Linux脚本-自动ping网址列表
背景 公司某一项业务需要管理多种类硬件,有一些硬件的管理功能没有实现前台展示,检测和硬件之间的网络连接状况需要通过ping每个ip地址来单独实现.在需要大规模调试网络的时候,每个硬件单独ping就显得 ...
- DVWA靶场实战(十三)——CSP Bypass
DVWA靶场实战(十三) 十三.CSP Bypass: 1.漏洞原理: CSP Bypass全称是Content-Security-Policy,中文叫做绕过内容安全策略.Content-Securi ...
- JLabel展示文本和图片--java进阶day03
1.JLabel 我们想要在窗体中展示图片或者文本是不能直接展示的,文本和图片必须要放在JLabel这个组件中 JLabel实质是窗体中的一块区域,创建了一个JLabel对象意味着在窗体中开辟了一块区 ...
- UML用例图-UML Use Case Diagram
.wj_nav { display: inline-block; width: 100%; margin-top: 0; margin-bottom: 0.375rem } .wj_nav_1 { p ...