HarmonyOs应用权限申请,system_grant和user_grant区别。本文附头像上传申请user-grant权限代码示例

HarmonyOs应用权限申请,system_grant和user_grant区别。本文附头像上传申请user-grant权限代码示例

system_grant(系统授权)

system_grant指的是系统授权类型,在该类型的权限许可下,应用被允许访问的数据不会涉及到用户或设备的敏感信息,应用被允许执行的操作对系统或者其他应用产生的影响可控

user_grant(用户授权)

user_grant指的是用户授权类型,在该类型的权限许可下,应用被允许访问的数据将会涉及到用户或设备的敏感信息,应用被允许执行的操作可能对系统或者其他应用产生严重的影响。

权限APL等级

根据权限对于不同等级应用有不同的开放范围,权限类型对应分为以下三个等级,等级依次提高。

APL级别说明开放范围
normal允许应用访问超出默认规则外的普通系统资源,如配置Wi-Fi信息、调用相机拍摄等。这些系统资源的开放(包括数据和功能)对用户隐私以及其他应用带来的风险低。APL等级为normal及以上的应用。
system_basic允许应用访问操作系统基础服务(系统提供或者预置的基础功能)相关的资源,如系统设置、身份认证等。这些系统资源的开放对用户隐私以及其他应用带来的风险较高。- APL等级为system_basic及以上的应用。- 部分权限对normal级别的应用受限开放,这部分权限在本指导中描述为“受限开放权限”。
system_core涉及开放操作系统核心资源的访问操作。这部分系统资源是系统最核心的底层服务,如果遭受破坏,操作系统将无法正常运行。- APL等级为system_core的应用。- 仅对系统应用开放。
  • 每次执行需要目标权限的操作时,应用都必须检查自己是否已经具有该权限。

    如需检查用户是否已向您的应用授予特定权限,可以使用checkAccessToken()函数,此方法会返回Promise<[GrantStatus]>:PERMISSION_GRANTED或PERMISSION_DENIED。

  • 每次访问受目标权限保护的接口之前,都需要使用requestPermissionsFromUser()接口请求相应的权限。

    用户可能在动态授予权限后通过系统设置来取消应用的权限,因此不能将之前授予的授权状态持久化。

  • user_grant权限授权要基于用户可知可控的原则,需要应用在运行时主动调用系统动态申请权限的接口,系统弹框由用户授权,用户结合应用运行场景的上下文,识别出应用申请相应敏感权限的合理性,从而做出正确的选择。

  • 系统不鼓励频繁弹窗打扰用户,如果用户拒绝授权,将无法再次拉起弹窗,需要应用引导用户在系统应用“设置”的界面中手动授予权限。

  • API12新增可以二次向用户申请授权requestPermissionOnSetting()

  • 系统权限弹窗不可被遮挡。

    系统权限弹窗不可被其他组件/控件遮挡,弹窗信息需要完整展示,以便用户识别并完成授权动作。

    如果系统权限弹窗与其他组件/控件同时同位置展示,系统权限弹窗将默认覆盖其他组件/控件。

代码示例:点击头像申请访问相机和相册媒体的权限,拒绝后二次点击半模态弹窗按钮向用户进行二次权限申请:
实现思路:
1.点击头像时利用checkAccessToken()检查当前是否已拥有权限,如果有则直接使用,如果没有则使用requestPermissionsFromUser()进行向用户询问权限授权
2.如果用户全部拒绝,下一次使用时则使用requestPermissionOnSetting()进行二次用户询问拉起弹窗(也可以引导用户去设置界面手动授权,在requestPermissionsFromUser()拒绝策略中即可实现)

//校验权限工具类

import { abilityAccessCtrl,Context, bundleManager, common, Permissions } from '@kit.AbilityKit';
import { BusinessError } from '@kit.BasicServicesKit';
/*** 校验当前是否已经授权(已封装成工具类,如使用三层架构则可放入common中)* @param permission* @returns*/
export async function checkPermissionGrant(permission: Permissions): Promise<abilityAccessCtrl.GrantStatus> {let atManager: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager();let grantStatus: abilityAccessCtrl.GrantStatus = abilityAccessCtrl.GrantStatus.PERMISSION_DENIED;// 获取应用程序的accessTokenIDlet tokenId: number = 0;try {let bundleInfo: bundleManager.BundleInfo = await bundleManager.getBundleInfoForSelf(bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_APPLICATION);let appInfo: bundleManager.ApplicationInfo = bundleInfo.appInfo;tokenId = appInfo.accessTokenId;} catch (error) {const err: BusinessError = error as BusinessError;console.error(`Failed to get bundle info for self. Code is ${err.code}, message is ${err.message}`);}// 校验应用是否被授予权限try {grantStatus = await atManager.checkAccessToken(tokenId, permission);} catch (error) {const err: BusinessError = error as BusinessError;console.error(`Failed to check access token. Code is ${err.code}, message is ${err.message}`);}return grantStatus;
}
/***向用户二次询问拉起弹窗授权*/
export function reqPermissionTwice(permissions: Array<Permissions>, context: common.UIAbilityContext): Promise<Array<abilityAccessCtrl.GrantStatus>> {let atManager: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager();return atManager.requestPermissionOnSetting(context, permissions)
}

//主页面(其中涉及一些工具类未提供,不影响本次示例功能实现,布局会有影响。项目代码还在开发中,之后会开源)

import {AppStorageEnum,NavigationBar,HdUser,hdHttp,cameraCapture,HdLoadingDialo,logger,authStore,reqPermissionTwice,checkPermissionGrant} from "@ss/basic"
import { fileIo, picker } from '@kit.CoreFileKit'
import { BusinessError, request } from '@kit.BasicServicesKit'
import { promptAction } from '@kit.ArkUI'
import { router } from '@kit.ArkUI'
import { abilityAccessCtrl, common, Permissions } from '@kit.AbilityKit'@Component
export struct MineIndexView {pageInfos: NavPathStack = new NavPathStack()@StorageProp(AppStorageEnum.TOP_AVOID_HEIGHT)avoidTopHeight: number = 0@StorageProp(AppStorageEnum.LOGIN_USER)loginUser: HdUser = {} as HdUser@State isShowSheet: boolean = falsedialog: CustomDialogController = new CustomDialogController({builder: HdLoadingDialog({ message: '更新中...' }),customStyle: true,alignment: DialogAlignment.Center})permissions: Array<Permissions> = ['ohos.permission.CAMERA', 'ohos.permission.WRITE_MEDIA'];isGrantFirst: boolean = falseaboutToAppear(): void {console.log(JSON.stringify(this.loginUser))// this.checkPermissions()}async checkPermissions(permission: Permissions): Promise<void> {//通过checkAccessToken校验本次usergrant是否已授权let grantStatus: abilityAccessCtrl.GrantStatus = await checkPermissionGrant(permission);//根据返回结果处理业务const currentPermission: Array<Permissions> = [permission]if (grantStatus === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED) { //授权logger.info("已授权")if (currentPermission[0] == this.permissions[0]) {this.updateAvatarForCamera()} else {this.updateAvatarForPhotos()}} else { //未授权logger.info("未授权")if (this.isGrantFirst) { //因为二次询问授权之前必须调用一次requestPermissionsFromUser//二次向用户申请授权api12拥有reqPermissionTwice(currentPermission, getContext(this) as common.UIAbilityContext).then((data: Array<abilityAccessCtrl.GrantStatus>) => {if (data[0] == abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED) {if (currentPermission[0] == this.permissions[0]) {this.updateAvatarForCamera()} else {this.updateAvatarForPhotos()}}}).catch((err: BusinessError) => {console.error('data:' + JSON.stringify(err));});}}}//询问用户是否授权,只会调起一次弹窗reqPermissionsFromUser(permissions: Array<Permissions>, context: common.UIAbilityContext): void {let atManager: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager();// requestPermissionsFromUser会判断权限的授权状态来决定是否唤起弹窗atManager.requestPermissionsFromUser(context, permissions).then((data) => {let grantStatus: Array<number> = data.authResults;let length: number = grantStatus.length;let count: number = 0for (let i = 0; i < length; i++) {count = count + 1if (grantStatus[i] === 0) {// 用户授权,可以继续访问目标操作this.isShowSheet = true} else {// 用户拒绝授权,提示用户必须授权才能访问当前页面的功能,并引导用户到系统设置中打开相应的权限if(count == length)this.isShowSheet = false}}// 授权成功}).catch((err: BusinessError) => {console.error(`Failed to request permissions from user. Code is ${err.code}, message is ${err.message}`);})}/*** 唤起相机上传图片*/async updateAvatarForCamera() {//调用相机唤起工具类let URI = await cameraCapture(getContext(this) as common.UIAbilityContext)if (URI != undefined) {// 2. 存储到沙箱中(fileIo在API9之后就废弃了,使用fs替换)const context = getContext(this)const fileType = 'jpg'const fileName = Date.now() + '.' + fileTypeconst copyFilePath = context.cacheDir + '/' + fileNameconst file = fileIo.openSync(URI, fileIo.OpenMode.READ_ONLY)fileIo.copyFileSync(file.fd, copyFilePath)// 3. 准备请求配置const config: request.UploadConfig = {url: hdHttp.baseURL + 'userInfo/avatar',method: 'POST',header: {'Accept': '*/*','Authorization': `Bearer ${this.loginUser.token}`,'Content-Type': 'multipart/form-data'},files: [{name: 'file', //multipart提交时,表单项目的名称,缺省为fileuri: `internal://cache/` + fileName, //仅支持"internal"协议类型,"internal://cache/"为应用的私有目录,是必填字段type: fileType, //文件的内容类型,默认根据文件名或路径的后缀获取。filename: fileName //multipart提交时,请求头中的文件名。}],data: []}// 4. 开始上传this.dialog.open() //自定义加载弹窗request.uploadFile(context, config, (err, data) => {if (err) {return logger.error('UPLOAD', err.message)}data.on('complete', () => {// 5. 更新头像hdHttp.get<HdUser>('userInfo').then(res => {this.loginUser.avatar = res.data.avatarauthStore.setUser(this.loginUser)promptAction.showToast({ message: '更新头像成功' }) //提示弹窗this.dialog.close()})})})}}/*** 唤起相册上传图片*/updateAvatarForPhotos() {const photoSelectOptions = new picker.PhotoSelectOptions()photoSelectOptions.MIMEType = picker.PhotoViewMIMETypes.IMAGE_TYPEphotoSelectOptions.maxSelectNumber = 1const photoViewPicker = new picker.PhotoViewPicker()photoViewPicker.select(photoSelectOptions).then(result => {// 1. 得到文件路径const URI = result.photoUris[0]// 2. 存储到沙箱中(fileIo在API9之后就废弃了,使用fs替换)const context = getContext(this)const fileType = 'jpg'const fileName = Date.now() + '.' + fileTypeconst copyFilePath = context.cacheDir + '/' + fileNameconst file = fileIo.openSync(URI, fileIo.OpenMode.READ_ONLY)fileIo.copyFileSync(file.fd, copyFilePath)// 3. 准备请求配置const config: request.UploadConfig = {url: hdHttp.baseURL + 'userInfo/avatar',method: 'POST',header: {'Accept': '*/*','Authorization': `Bearer ${this.loginUser.token}`,'Content-Type': 'multipart/form-data'},files: [{name: 'file', //multipart提交时,表单项目的名称,缺省为fileuri: `internal://cache/` + fileName, //仅支持"internal"协议类型,"internal://cache/"为应用的私有目录,是必填字段type: fileType, //文件的内容类型,默认根据文件名或路径的后缀获取。filename: fileName //multipart提交时,请求头中的文件名。}],data: []}// 4. 开始上传this.dialog.open() //自定义加载弹窗request.uploadFile(context, config, (err, data) => {if (err) {return logger.error('UPLOAD', err.message)}data.on('complete', () => {// 5. 更新头像hdHttp.get<HdUser>('userInfo').then(res => {this.loginUser.avatar = res.data.avatarauthStore.setUser(this.loginUser)promptAction.showToast({ message: '更新头像成功' }) //提示弹窗this.dialog.close()})})})})}@BuilderbuilderMenuBack() {Button({ type: ButtonType.Circle }) { //设置按钮的类型未圆形按钮Image($r("app.media.left"))}.onClick(() => {router.back()}).width(25).height(25).backgroundColor('rgba(255, 255, 255, 0)')}@BuilderbuilderMenuMail() {Button({ type: ButtonType.Circle }) { //设置按钮的类型未圆形按钮Image($r("app.media.mail"))}.onClick(() => {this.pageInfos.pushPathByName("MailCenterView", false);}).width(25).height(25).backgroundColor('rgba(255, 255, 255, 0)')}/*** 半模态对话框*/@BuilderbuildAvatarSheet() {Column() {Text("拍照").width('100%').height('50%').lineHeight('45%').textAlign(TextAlign.Center).backgroundColor('#e5e7ed').onClick(() => {this.isShowSheet = !this.isShowSheetthis.checkPermissions(this.permissions[0])})Divider().color(Color.White)Text("从相册选择").width('100%').height('50%').lineHeight('45%').textAlign(TextAlign.Center).backgroundColor('#e5e7ed').onClick(() => {//并非多次一举,再调用reqPermissionsFromUser之前如果打开半模态化转场会阻塞主线程(原因不知)if(!this.isGrantFirst) {this.isGrantFirst = truethis.reqPermissionsFromUser(this.permissions, getContext(this) as common.UIAbilityContext)}else{this.isShowSheet = !this.isShowSheet}})}.width('100%').height(150)}build() {Navigation(this.pageInfos) {Column() {NavigationBar({buildButtonBackParam: () => {this.builderMenuBack()},buildMenuOneParam: () => {this.builderMenuMail()}})Flex({ alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center, direction: FlexDirection.Column }) {Image($rawfile('kyrie.jpg')).id("mine").width(90).height(90).clip(true).borderRadius(45).margin({ top: 45 }).geometryTransition("avatar").transition(TransitionEffect.opacity(0.99)).onClick(() => {this.isShowSheet = !this.isShowSheetif(!this.isGrantFirst)this.reqPermissionsFromUser(this.permissions, getContext(this) as common.UIAbilityContext)})Text(this.loginUser.username).fontWeight(700).fontSize(16).margin({ top: 8 })Button({ type: ButtonType.Capsule, stateEffect: false }) {Text("终身大会员").fontColor("#7f8085").fontSize(12)}.width(150).height(32).margin({ top: 8 }).backgroundColor("#dbdce1")}.bindSheet(this.isShowSheet, this.buildAvatarSheet(), {height: 150,dragBar: false,showClose: false,onDisappear: () => {this.isShowSheet = false}}).width("90%").height(200)}.width('100%').transition(TransitionEffect.asymmetric(TransitionEffect.opacity(0.99),TransitionEffect.OPACITY)).height('100%')}.backgroundColor("#e4e5ea")}
}

效果图:
1.第一次点击头像
在这里插入图片描述
2.假如全部拒绝,第二次访问继续询问(具体业务权限)
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/411370.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

大数据测试怎么做,数据应用测试、数据平台测试、数据仓库测试

本期内容由中通科技高级质量工程师龙渊在公益讲座中分享&#xff0c;他从大数据测试整体介绍、数据应用测试、数据平台测试以及数据仓库测试等方面&#xff0c;与大家共同探讨了大数据测试的方法实施与落地。 以下是讲座正文&#xff1a; 今天我们分享的内容主要从大数据简介…

二、基于Vue3的开发-环境搭建【Visual Studio Code】扩展组件

Visual Studio Code中的扩展组件 1、安装的扩展工具2、说明2.1 、代码规范性检查EsLint2.2 、代码语法高亮提示工具Vue - Official2.3 、阿里的AI代码开发提示工具 TONGYI Lingma 1、安装的扩展工具 2、说明 2.1 、代码规范性检查EsLint Visual Studio Code 中【设置】-setti…

基于springboot+vue+uniapp的使命召唤游戏助手小程序

开发语言&#xff1a;Java框架&#xff1a;springbootuniappJDK版本&#xff1a;JDK1.8服务器&#xff1a;tomcat7数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09;数据库工具&#xff1a;Navicat11开发软件&#xff1a;eclipse/myeclipse/ideaMaven包&#…

OSI七层模型中的数据链路层

图片&#xff1a;数据帧的格式 这里面的一个关键点是&#xff0c;数据的源IP和目标IP在哪里&#xff1f; 就在图中的“数据”里面&#xff0c;这个“数据”也就是网络层的数据包&#xff0c;如果是TCP类型的数据包&#xff0c;数据包里面就包含TCP类型的首部信息&#xff0c;…

使用excel把json文件转为表格

json文件格式 [ { "ID": "16", "名称": "测站", "管理ID": "3", "管理名称": "土", "辅助信息": { "百度经度&qu…

linux neo4j 切换知识图谱

neo4j 安装 linux neo4j的安装可以浏览这篇文章&#xff1a; ubuntu sudo apt-get install neo4j 配置安装与设置远程访问 引言 如果你是window用户&#xff0c;直接下载桌面版进行安装与使用即可&#xff1b; 我有一台linux的服务器&#xff0c;想部署在上面&#xff0c;不…

阿里云私有镜像仓库配置及使用

1 登录阿里云 阿里云访问地址&#xff1a;https://www.aliyun.com/ 右上角选择“控制台” 2 创建个人实例 搜索框搜索“容器镜像服务” 新建“个人实例” 选择“创建个人版” 同意协议&#xff0c;点击确定 3 个人实例配置 设置Registry登录密码 密码要求&#xff1…

[Arxiv 2024] Self-Rewarding Language Models

Contents IntroductionMethodExperimentsReferences Introduction 作者提出 Self-Rewarding 训练框架&#xff0c;LLM 在训练过程中同时担任 actor 和 critic&#xff0c;actor 负责合成新数据&#xff0c;critic 负责判断合成数据质量用于组成高质量的偏好数据集用于模型的下…

NoSql数据库Redis集群

一、关系型数据库和 NoSQL 数据库 1.1 数据库主要分为两大类&#xff1a;关系型数据库与 NoSQL 数据库 关系型数据库 &#xff0c;是建立在关系模型基础上的数据库&#xff0c;其借助于集合代数等数学概念和方法来处理数据库中的数据主流的 MySQL 、 Oracle 、 MS SQL Server…

ElasticSearch和Kibana的安全设置以及https设置

&#x1f468;‍&#x1f4bb;本文专栏&#xff1a;ElasticSearch和Kibana的安全设置以及https设置 &#x1f468;‍&#x1f4bb;本文简述&#xff1a;跟着猿灰灰一起学Java&#xff01; &#x1f468;‍&#x1f4bb;上一篇文章&#xff1a; &#x1f468;‍&#x1f4bb;有任…

『功能项目』怪物受击的动画事件【10】

我们打开上一篇09着色器光透魔法球的项目&#xff0c; 本章要做的事情是在场景中创建一个怪物对象&#xff0c;当怪物被主角的魔法球击中后播放受击动画效果&#xff0c;此类技术用到动画事件帧&#xff0c;在动画上创建脚本。 首先打开资源商店选择一个免费资源的怪物模型加载…

apache httpclient速成

目录标题 快速使用连接池参数连接池状态清除闲置连接evictIdleConnections删除过期连接 timeToLive 和evictExpiredConnections 注意释放内存关闭流 http和netty的关系 导入依赖 <dependency><groupId>org.apache.httpcomponents.client5</groupId><artif…

【ceph学习】S3权限认证部分

认证过程简介 认证的过程是一个对用户信息进行解析并且判断前后得到的秘钥是否一致的过程。 auth_regitry的创建 在rgw_main.cc:main()中进行初始化auth_registry对象 /*rgw_main.cc*/ /* Initialize the registry of auth strategies which will coordinate * the dynamic…

浏览器中的开源SQL可视化工具:sqliteviz

sqliteviz&#xff1a; 在浏览器中&#xff0c;即刻开启数据可视化之旅。- 精选真开源&#xff0c;释放新价值。 概览 sqliteviz是一个专为数据可视化而设计的单页离线优先PWA&#xff0c;它利用了现代浏览器技术&#xff0c;让用户无需安装任何软件即可在本地浏览器中进行SQL…

WxPython可视化编辑器

作者&#xff1a;陈炳强 WxPython是python的一个用来写桌面程序的模块,目前只写了小部分功能跟组件, 用Python写中文&#xff0c;非常方便&#xff01; 下载地址&#xff1a;https://pan.quark.cn/s/ba19b2472246

大模型提示词工程技术2-设计有效的提示词技巧、角色与上下文在提示中的应用

大模型提示词工程技术2-设计有效的提示词技巧、角色与上下文在提示中的应用。《大模型提示词工程技术》的作者&#xff1a;微学AI&#xff0c;这是一本专注于提升人工智能大模型性能的著作&#xff0c;它深入浅出地讲解了如何通过优化输入提示词来引导大模型生成高质量、准确的…

19.神经网络 - 线性层及其他层介绍

神经网络 - 线性层及其他层介绍 1.批标准化层–归一化层&#xff08;不难&#xff0c;自学看官方文档&#xff09; Normalization Layers torch.nn — PyTorch 1.10 documentation BatchNorm2d — PyTorch 1.10 documentation 对输入采用Batch Normalization&#xff0c;可…

美发店会员系统设计解读之规格选择-SAAS本地化及未来之窗行业应用跨平台架构

一、请求产品信息 $.ajax({type:"get", //请求方式async:true, //是否异步url:"服务器",dataType:"json", //跨域json请求一定是jsonpjsonp: "cwpd_showData_dy_spec", //跨域请求的参数名&#xff0c;默认是callback//js…

从学习到工作,2024年不可或缺的翻译助手精选

翻译工具利用先进的机器学习和自然语言处理技术&#xff0c;能够迅速将一种语言的文档转换为另一种语言&#xff0c;极大地促进了信息的无障碍流通。接下来&#xff0c;我们将介绍几款功能强大、操作简便的类似deepl翻译的工具&#xff0c;帮助你轻松应对各种翻译需求。 第一款…

pymysql cursor使用教程

Python之PyMySQL的使用&#xff1a; 在python3.x中&#xff0c;可以使用pymysql来MySQL数据库的连接&#xff0c;并实现数据库的各种操作&#xff0c;本次博客主要介绍了pymysql的安装和使用方法。 PyMySQL的安装 一、.windows上的安装方法&#xff1a; 在python3.6中&…