HarmonyOS实战开发-为应用添加运行时权限

介绍

通过AbilityAccessCtrl动态向用户申请“允许不同设备间的数据交换”的权限,使用设备管理实例获取周边不可信设备列表。

说明: 查询周边不可信设备之前,请确保本设备与周边设备未进行配对。如果已配对,则恢复出厂设置之后重新查询。

相关概念

  • 访问控制权限申请:应用的APL(Ability Privilege Level)等级分为normal、system_basic和system_core三个等级,默认情况下,应用的APL等级都为normal等级。权限类型分为system_grant和user_grant两种类型。应用可申请的权限项参见应用权限列表。
  • 权限类型说明:根据授权方式的不同,权限类型可分为system_grant(系统授权)和user_grant(用户授权)。
  • 应用ALP等级说明:元能力权限等级APL(Ability Privilege Level)指的是应用的权限申请优先级的定义,不同APL等级的应用能够申请的权限等级不同。
  • 应用权限列表:在申请目标权限前,建议开发者先阅读访问控制开发概述-权限的工作流程。对权限的工作流程有基本的了解后,再结合以下权限的具体说明,判断应用能否申请目标权限,提高开发效率。
  • 设备管理实例:用于获取可信设备和本地设备的相关信息。在调用DeviceManager的方法前,需要先通过createDeviceManager构建一个DeviceManager实例dmInstance。

约束与限制

通过DevEco Studio自动下载的SDK均为public版本,public-SDK不支持开发者使用系统API。本篇Codelab使用的DeviceManager(设备管理实例)依赖于系统API,需下载full-SDK并替换工具自动下载的public-SDK。具体操作可参考指南《如何替换full-SDK》。

相关权限

本篇Codelab需要在配置文件module.json5里添加允许不同设备间的数据交换权限:ohos.permission.DISTRIBUTED_DATASYNC。

环境搭建

软件要求

  • DevEco Studio版本:DevEco Studio 3.1 Release。
  • OpenHarmony SDK版本:API version 9。

硬件要求

  • 开发板类型:润和RK3568开发板。
  • OpenHarmony系统:3.2 Release。

环境搭建

完成本篇Codelab我们首先要完成开发环境的搭建,本示例以RK3568开发板为例,参照以下步骤进行:

  1. 获取OpenHarmony系统版本:标准系统解决方案(二进制)。以3.2 Release版本为例:

2.搭建烧录环境。

  1. 完成DevEco Device Tool的安装
  2. 完成RK3568开发板的烧录

3.搭建开发环境。

  1. 开始前请参考工具准备,完成DevEco Studio的安装和开发环境配置。
  2. 开发环境配置完成后,请参考使用工程向导创建工程(模板选择“Empty Ability”)。
  3. 工程创建完成后,选择使用真机进行调测。

代码结构解读

本篇Codelab只对核心代码进行讲解。

├──entry/src/main/ets                      // 代码区
│  ├──common
│  │  ├──constants
│  │  │  └──CommonConstants.ets            // 公共常量类
│  │  └──util
│  │     ├──DeviceListUtil.ets             // 设备查询工具类
│  │     ├──Logger.ets                     // 日志管理工具类
│  │     └──PermissionUtil.ets             // 权限申请工具类
│  ├──entryability
│  │  └──EntryAbility.ts                   // 程序入口类
│  ├──pages
│  │  └──HomePage.ets                      // 主页面
│  └──view
│     ├──DeviceBean.ets                    // 设备信息类
│     ├──DeviceItem.ets                    // 设备信息对象
│     ├──DeviceListDialog.ets              // 设备列表展示弹框
│     └──NoPermissionDialog.ets            // 无权限弹框
└──entry/src/main/resource                 // 应用静态资源目录

页面设计

页面分为授权图片、授权说明、查询内网设备按钮三部分,效果如图所示:

// HomePage.ets
struct HomePage {
  @State authorizedImage: Resource = $r('app.media.ic_unauthorized');
  @State permissionDescribe: Resource = $r('app.string.no_permission');
  noPermissionDialog: CustomDialogController = new CustomDialogController({
    builder: NoPermissionDialog(),
    autoCancel: false,
    alignment: DialogAlignment.Bottom,
    offset: {
      dx: CommonConstants.DIALOG_OFFSET_X,
      dy: CommonConstants.DIALOG_OFFSET_Y
    }
  });
  deviceListDialog: CustomDialogController = new CustomDialogController({
    builder: DeviceListDialog(),
    autoCancel: false,
    alignment: DialogAlignment.Bottom,
    offset: {
      dx: CommonConstants.DIALOG_OFFSET_X,
      dy: CommonConstants.DIALOG_OFFSET_Y
    }
  })
  ...
  build() {
    Column() {
      Image(this.authorizedImage)
        ...
      Text(this.permissionDescribe)
        ...
      Column() {
        Button($r('app.string.button_text'), { type: ButtonType.Capsule, stateEffect: true })
          ...
      }
      ...
    }
    ...
  }
}

授权状态为未授权时,点击查询内网设备按钮打开未申请权限提示的弹框,效果如图所示:

// NoPermissionDialog.ets
@CustomDialog
export struct NoPermissionDialog {
  controller: CustomDialogController;
 
  build() {
    Column() {
      Text($r('app.string.no_permission_title'))
        ...
      Text($r('app.string.clear_permission'))
        ...
      Text($r('app.string.dialog_confirm'))
        ...
        .onClick(() => {
          this.controller.close();
        })
    }
    ...
  }
}

授权状态为已授权时,点击查询内网设备按钮打开设备查询列表弹框,效果如图所示:

// DeviceListDialog.ets
@CustomDialog
export struct DeviceListDialog {
  private deviceListUtil: DeviceListUtil = new DeviceListUtil();
  @State deviceList: Array<DeviceBean> = [];
  controller: CustomDialogController;
  ...
  build() {
    Column() {
      Text($r('app.string.device_list'))
        ...
      Column() {
        if (this.deviceList.length === 0) {
          Text($r('app.string.no_device'))
            ...
        } else {
          Column() {
            List() {
              ForEach(this.deviceList, (item: DeviceBean, index: number) => {
                ListItem() {
                  DeviceItem({item: item, index: index});
                }
              }, (item: DeviceBean) => JSON.stringify(item))
            }
          }
          ...
        }
      }
      ...
      Text($r('app.string.dialog_confirm'))
        ...
        .onClick(() => {
          this.deviceListUtil.stopDeviceDiscovery();
          this.controller.close();
        })
    }
    ...
  }
}

权限申请

首次进入主页面弹出授权弹框,点击禁止按钮不会授权,点击允许按钮进行授权,再次进入首页不会出现授权弹框。

// HomePage.ets
struct HomePage {
  ...
  async aboutToAppear() {
    let result = await PermissionUtil.applyPermission();
    if (result === 0) {
      this.permissionDescribe = $r('app.string.has_permission');
      this.authorizedImage = $r('app.media.ic_authorized');
    } else {
      this.permissionDescribe = $r('app.string.no_permission');
    }
  }
  ...
}

// PermissionUtil.ets
async applyPermission() {
  let atManager = abilityAccessCtrl.createAtManager();
  let data = await atManager.requestPermissionsFromUser(getContext(this), [CommonConstants.PERMISSION]);
  let grantStatus: Array<number> = data.authResults;
  let length: number = grantStatus.length;
  if (length === 0) {
    return 1;
  }
  return grantStatus[0];
}

主页面点击查询内网设备按钮时,先查询是否授权,根据授权状态打开对应的弹框(未授权:打开未授权弹框;已授权:打开设备查询列表弹框)。

// HomePage.ets
struct HomePage {
  ...
  build() {
    Column() {
      ...
      Column() {
        Button($r('app.string.button_text'), { type: ButtonType.Capsule, stateEffect: true })
          ...
          .onClick(async () => {
            let result = await PermissionUtil.checkPermission();
            if(result === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED) {
              this.deviceListDialog.open();
            } else {
              this.noPermissionDialog.open();
            }
          })
      }
      ...
    }
    ...
  }
}

// PermissionUtil.ets
async checkPermission() {
  let atManager = abilityAccessCtrl.createAtManager();
  let grantStatus: abilityAccessCtrl.GrantStatus =  abilityAccessCtrl.GrantStatus.PERMISSION_DENIED;
  let 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 (err) {
    Logger.error(TAG, 'getBundleInfoForSelf failed, code is ${err.code}, message is ${err.message}');
  }
  try {
    grantStatus = await atManager.checkAccessToken(tokenId, CommonConstants.PERMISSION);
  } catch (err) {
    Logger.error(TAG, 'checkAccessToken failed, code is ${err.code}, message is ${err.message}');
  }
  return grantStatus;
}

设备查询

先创建dmInstance实例,再注册发现设备(deviceFoundOn)的回调方法,最后调用startDeviceDiscovery方法查询周边设备;当查询到设备之后调用deviceFoundOn方法处理设备信息。

//DeviceListDialog.ets
export struct DeviceListDialog {
  ...
  aboutToAppear() {
    this.deviceListUtil.initDmInstance((data: DeviceInfoInterface) => {
      ...
    });
  }
  ...
}

// DeviceListUtil.ets
// 创建dmInstance实例
initDmInstance(dealDeviceInfo: Function) {
  this.dealDeviceInfo = dealDeviceInfo;
  try {
    deviceManager.createDeviceManager(getContext(this).applicationInfo.name, (err, data) => {
      if (err) {
        Logger.error(TAG, 'createDeviceManager errCode:' + err.code + ',errMessage:' + err.message);
        return;
      }
      this.dmInstance = data;
      this.deviceFoundOn();
      this.startDeviceDiscovery();
    });
  } catch (err) {
    Logger.error(TAG, 'createDeviceManager err=' + JSON.stringify(err));
  }
}

// DeviceListUtil.ets
// 注册发现设备回调方法
deviceFoundOn() {
  try {
    if (this.dmInstance !== undefined) {
      this.dmInstance.on('deviceFound', (data) => {
        if (this.dealDeviceInfo !== undefined) {
          this.dealDeviceInfo(data);
        }
      });
    }
  } catch (err) {
    Logger.error(TAG, 'deviceFoundOn err:' + JSON.stringify(err));
  }
}

// DeviceListUtil.ets
// 发现周边设备方法
startDeviceDiscovery() {
  this.subscribeId = Math.floor(Math.random() * CommonConstants.RANDOM_ONE + CommonConstants.RANDOM_TWO);
  let subscribeInfo: SubscribeInfoInterface = {
    subscribeId: this.subscribeId,
    mode: CommonConstants.MODE,
    medium: 0,
    freq: CommonConstants.FREQ,
    isSameAccount: false,
    isWakeRemote: true,
    capability: 1
  };
  try {
    if (this.dmInstance !== undefined) {
      this.dmInstance.startDeviceDiscovery(subscribeInfo);
    }
  } catch (err) {
    Logger.error(TAG, 'startDeviceDiscovery err:' + JSON.stringify(err));
  }
}

总结

您已经完成了本次Codelab的学习,并了解到以下知识点:

  1. 访问控制授权申请。
  2. 权限类型说明。
  3. 如何获取周边设备。

为了帮助大家更深入有效的学习到鸿蒙开发知识点,小编特意给大家准备了一份全套最新版的HarmonyOS NEXT学习资源,获取完整版方式请点击→《HarmonyOS教学视频

HarmonyOS教学视频:语法ArkTS、TypeScript、ArkUI等.....视频教程

鸿蒙生态应用开发白皮书V2.0PDF:

获取完整版白皮书方式请点击→《鸿蒙生态应用开发白皮书V2.0PDF》

鸿蒙 (Harmony OS)开发学习手册

一、入门必看

  1. 应用开发导读(ArkTS)
  2. ……

二、HarmonyOS 概念

  1. 系统定义
  2. 技术架构
  3. 技术特性
  4. 系统安全
  5. ........

三、如何快速入门?《做鸿蒙应用开发到底学习些啥?》

  1. 基本概念
  2. 构建第一个ArkTS应用
  3. ……

四、开发基础知识

  1. 应用基础知识
  2. 配置文件
  3. 应用数据管理
  4. 应用安全管理
  5. 应用隐私保护
  6. 三方应用调用管控机制
  7. 资源分类与访问
  8. 学习ArkTS语言
  9. ……

五、基于ArkTS 开发

  1. Ability开发
  2. UI开发
  3. 公共事件与通知
  4. 窗口管理
  5. 媒体
  6. 安全
  7. 网络与链接
  8. 电话服务
  9. 数据管理
  10. 后台任务(Background Task)管理
  11. 设备管理
  12. 设备使用信息统计
  13. DFX
  14. 国际化开发
  15. 折叠屏系列
  16. ……

更多了解更多鸿蒙开发的相关知识可以参考:《鸿蒙 (Harmony OS)开发学习手册

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Python中的全栈开发前端与后端的完美融合【第160篇—全栈开发】

&#x1f47d;发现宝藏 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。【点击进入巨牛的人工智能学习网站】。 Python中的全栈开发&#xff1a;前端与后端的完美融合 全栈开发已成为当今软件开发领域中的…

Linux权限提升总结

几个信息收集的项目推荐 运行这几个项目就会在目标主机上收集一些敏感信息供我们参考和使用 一个综合探针&#xff1a;traitor 一个自动化提权&#xff1a;BeRoot(gtfo3bins&lolbas) 使用python2运行beroot.py就可以运行程序&#xff0c;然后就可以收集到系统中的大量信…

景顺长城:《重塑与创造——2024 ai+洞察报告》

近期&#xff0c;景顺长城发布了《重塑与创造——2024 ai洞察报告》,报告深入探讨了人工智能&#xff08;AI&#xff09;产业的发展现状、未来趋势以及对各行业的潜在影响。报告认为&#xff0c;AI产业发展是多层次、多浪潮的&#xff0c;目前我们处于第二阶段但未来将持续伴随…

企业案例:金蝶云星空集成钉钉,帆软BI

正文&#xff1a;在数字化转型的大潮中&#xff0c;众多企业开始探索并实践高效的数据流转与集成&#xff0c;以提升内部管理效率和决策质量。本文将以某企业为例&#xff0c;详细介绍如何通过将钉钉审批流程的数据实时同步至金蝶云星空&#xff0c;并进一步在帆软报表平台上实…

缺省参数

缺省参数 缺省参数概念 缺省参数是声明或定义函数时为函数的参数指定一个缺省值。在调用该函数时&#xff0c;如果没有指定实 参则采用该形参的缺省值&#xff0c;否则使用指定的实参。 void Func(int a 0) {cout<<a<<endl; } int main() {Func(); // 没有传…

力扣刷题Days31-2.两数相关(js)

1&#xff0c;题目 给你两个 非空 的链表&#xff0c;表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的&#xff0c;并且每个节点只能存储 一位 数字。 请你将两个数相加&#xff0c;并以相同形式返回一个表示和的链表。 你可以假设除了数字 0 之外&#xff0c;…

基于ssm的企业销售人员培训系统(java项目+文档+源码)

风定落花生&#xff0c;歌声逐流水&#xff0c;大家好我是风歌&#xff0c;混迹在java圈的辛苦码农。今天要和大家聊的是一款基于ssm的企业销售人员培训系统。项目源码以及部署相关请联系风歌&#xff0c;文末附上联系信息 。 项目简介&#xff1a; 企业销售人员培训系统主要…

ios应用内支付

用uniapp开发iOS应用内支付 准备前端代码服务器端处理如果iOS支付遇到问题实在解决不了&#xff0c;可以联系我帮忙解决&#xff0c;前端后端都可以解决&#xff08;添加的时候一定要备注咨询iOS支付问题&#xff09; 准备前端代码 获取支付通道 (uni.getProvider) uni.getPr…

idea端口占用

报错&#xff1a;Verify the connector‘s configuration, identify and stop any process that‘s listening on port XXXX 翻译&#xff1a; 原因&#xff1a; 解决&#xff1a; 一、重启大法 二、手动关闭 启动spring项目是控制台报错&#xff0c;详细信息如下&#xff…

跨境独立站pandabuy cssbuy 跨境Micro微店商品详情

跨境独立站运用微店详情API接口&#xff1a;实现高效运营与营销新突破 在全球化日益加速的今天&#xff0c;跨境独立站成为越来越多商家拓展海外市场、提升品牌影响力的关键平台。为了更好地满足用户需求&#xff0c;提升用户体验&#xff0c;跨境独立站需要不断引入先进的技术…

PostgreSQL的学习心得和知识总结(一百三十五)|深入理解PostgreSQL数据库之查找 PostgreSQL C 代码中的内存泄漏

目录结构 注&#xff1a;提前言明 本文借鉴了以下博主、书籍或网站的内容&#xff0c;其列表如下&#xff1a; 1、参考书籍&#xff1a;《PostgreSQL数据库内核分析》 2、参考书籍&#xff1a;《数据库事务处理的艺术&#xff1a;事务管理与并发控制》 3、PostgreSQL数据库仓库…

前端学习<三>CSS进阶——03-网页设计和开发中,那些困扰大神的关于字体的知识

前言 我周围的码农当中&#xff0c;有很多是技术大神&#xff0c;却常常被字体这种简单的东西所困扰。 这篇文章&#xff0c;我们来讲一讲关于字体的常识。这些常识所涉及到的问题&#xff0c;有很强的可操作性&#xff0c;都是在实际业务中真实遇到的&#xff0c;都是需要开…

Xinstall带你解锁新姿势:网页直接拉起iOS应用!

在移动互联网时代&#xff0c;用户体验至关重要。对于iOS用户来说&#xff0c;能够在使用网页时直接拉起对应的应用&#xff0c;无疑会大大提升操作便利性和效率。然而&#xff0c;要实现这一功能&#xff0c;往往需要繁琐的开发流程和高昂的维护成本。这时&#xff0c;一个名为…

【JavaWeb】Day31.SpringBootWeb请求响应——分层解耦(二)

3.IOC&DI 3.1 IOC&DI入门 完成Controller层、Service层、Dao层的代码解耦 思路&#xff1a; 1. 删除Controller层、Service层中new对象的代码 2. Service层及Dao层的实现类&#xff0c;交给IOC容器管理 3. 为Controller及Service注入运行时依赖的对象 Controller程序…

服务注册与发现

服务注册与发现 传统单体架构与分布式架构 单体架构的不足&#xff1a; 所有的服务都集中在一个应用中&#xff0c;一个服务出错&#xff0c;可能导致整个系统宕机随着用户越来越多&#xff0c;程序承受的并发越来越高&#xff0c;单体应用的并发能力有限。数据库瓶颈&#x…

RTSP/ONVIF安防监控云平台EasyNVR激活码授权异常(状态码-2)的原因排查:服务器时间异常

EasyNVR平台优秀的视频能力在于通过RTSP/ONVIF协议&#xff0c;将前端接入设备的音视频资源进行采集&#xff0c;并转码成适合全平台、全终端分发的视频流格式&#xff0c;包括RTMP、RTSP、FLV、HLS、WebRTC等格式。平台可提供视频直播监控、录像、检索与回看、云存储、国标级联…

蓝桥杯算法题——暴力枚举法

先估算这个数小于3的50次方 cnt0 for i in range(50):for j in range(50):for k in range(50):a3**ib5**jc7**kif a*b*c<59084709587505:cnt1 print(cnt-1)#当ijk都为0时&#xff0c;a*b*c1不是幸运数字所以要减去

2024 年每个程序员都应该尝试的 8 个AI工具

随着人工智能技术的极速发展&#xff0c;新的 AI 工具正以前所未有的速度涌现&#xff0c;为开发者们带来了前所未有的机会和挑战。在这个不断演进的时代&#xff0c;掌握最新的 AI 技术已成为每个程序员的必修课。 在本文中&#xff0c;我们收集了8 个程序员在 2024 年值得尝…

持续交付/持续部署流水线介绍(CD)

目录 一、概述 二、典型操作流程 2.1 CI/CD典型操作流 2.2 CI/CD操作流程说明 2.3 总结 三、基于GitHubDocker的持续交付/持续部署流水线&#xff08;公有云&#xff09; 3.1 基于GitHubDocker的持续交付/持续部署操作流程示意图 3.2 GitHubDocker持续交付/持续部署流水…

总结TCP协议各类知识点

前言 本篇博客博主将详细地介绍TCP有关知识点&#xff0c;坐好板凳发车啦~ 一.TCP特点 1.有连接 TCP传输的过程中类似于打电话的各个过程 2.可靠传输 通过TCP自身的多种机制来保证可靠传输 3.面向字节流 内容是以字节的方式来进行发送与接收 4.缓冲区 TCP有接收缓冲区…