【HarmonyOS】应用实现读取剪切板内容(安全控件和自读取)

embedded/2024/11/18 8:25:34/

【HarmonyOS】应用实现读取粘贴板内容(安全控件和自读取)

前言

在这里插入图片描述

三方应用 读取系统剪切板是比较常见的功能。可以实现功能入口的快捷激活跳转,以及用户粘贴操作的简化,增强用户的体验感。

但是在用户日渐注重隐私的今天,系统对于剪切板权限的开放也在收紧。

鸿蒙中实现剪切板很简单,目前有两种方式,分别为:1.使用粘贴安全控件 2.申请用户授权,应用自己读取

解决方案

1.使用粘贴安全控件
鸿蒙系统提供了PasteButton安全组件,通过该按钮组件,用户点击即认为授权,不需要三方应用再自己申请权限。通过点击后的回调,再通过剪切板读取其中的内容pasteboard.getSystemPasteboard().getData。需要注意的时候,该按钮点击授权为临时授权,再app关闭,切到后台后授权就没有了,需要用户重新点击按钮。

所以一般该操作的设计都是,点击按钮后马上去读取剪切板内容,减少逻辑读取的链路。目前看读取虽然是异步,但是读取速度还是很快,影响不大

        PasteButton().padding({top: 12, bottom: 12, left: 24, right: 24}).onClick((event: ClickEvent, result: PasteButtonOnClickResult) => {console.log(this.TAG, " PasteboardPage PasteButton result: " + JSON.stringify(result) + " event: " + JSON.stringify(event));if (PasteButtonOnClickResult.SUCCESS === result) {pasteboard.getSystemPasteboard().getData((err: BusinessError, pasteData: pasteboard.PasteData) => {console.log(this.TAG, " PasteboardPage getData err: " + JSON.stringify(err) + " pasteData: " + JSON.stringify(pasteData));if (err) {return;}this.message = pasteData.getPrimaryText();});}})

----按钮样式需要显著,并且没有故意遮挡,透明度,UI叠加,误导用户等因素会导致按钮回调授权失败。原则是让用户能清晰感知此按钮是粘贴按钮。

2.申请用户授权,应用自读取
需要申请"ohos.permission.READ_PASTEBOARD"权限。该权限是管制权限,需要你的应用去通过场景申请,比如你有口令的场景,就可以申请该权限。【申请使用受限权限
在这里插入图片描述
------如果应用涉及获取受限权限,在应用发布上架时,应用市场(AGC)将根据应用的使用场景审核是否可以使用对应的受限权限。如不符合,应用的上架申请将被驳回,审核方式请见发布HarmonyOS应用。

当你申请了该权限后,就不需要安全控件,直接通过系统剪切板可以读取到其中的内容。
需要注意的是,申请的是对应场景,比如口令场景。但是系统并不会对你读取的内容做出过滤,你能读取到用户复制的所有内容,并不只是口令。

DEMO示例:

PasteboardPage.ets

import { hilog } from '@kit.PerformanceAnalysisKit';
import { abilityAccessCtrl, bundleManager, common } from '@kit.AbilityKit';
import { pasteboard, BusinessError } from '@kit.BasicServicesKit';/*** 剪切板*/


struct PasteboardPage {private TAG: string = "PasteboardPage"; message: string = '';private requestPermissions(context: common.Context): void {// 进入页面时,向用户请求授权广告跨应用关联访问权限const atManager: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager();try {atManager.requestPermissionsFromUser(context, ["ohos.permission.READ_PASTEBOARD"]).then((data) => {if (data.authResults[0] === 0) {this.readPasteBoardData();} else {hilog.error(0x0000, 'testTag', '%{public}s', 'user rejected');}}).catch((err: BusinessError) => {hilog.error(0x0000, 'testTag', '%{public}s', `request permission failed, error: ${err.code} ${err.message}`);})} catch (err) {hilog.error(0x0000, 'testTag', '%{public}s', `catch err->${err.code}, ${err.message}`);}}onClickReadPasteboard = ()=>{this.requestPermissions(getContext());}private readPasteBoardData(){let systemPasteboard: pasteboard.SystemPasteboard = pasteboard.getSystemPasteboard();systemPasteboard.getData((err: BusinessError, pasteData: pasteboard.PasteData) => {if (err) {console.error('Failed to get PasteData. Cause: ' + err.message);return;}let text: string = pasteData.getPrimaryText();this.message = text;});}build() {Column({ space: 10 }) {Text("点击启用授权读取剪切板").onClick(this.onClickReadPasteboard)TextInput({ placeholder: '请输入验证码', text: this.message }).onChange((value: string, previewText?: PreviewText)=>{console.log(this.TAG, " TextInput onChange value: " + JSON.stringify(value) + " previewText: " + JSON.stringify(previewText));this.message = value;})PasteButton().padding({top: 12, bottom: 12, left: 24, right: 24}).onClick((event: ClickEvent, result: PasteButtonOnClickResult) => {console.log(this.TAG, " PasteboardPage PasteButton result: " + JSON.stringify(result) + " event: " + JSON.stringify(event));if (PasteButtonOnClickResult.SUCCESS === result) {pasteboard.getSystemPasteboard().getData((err: BusinessError, pasteData: pasteboard.PasteData) => {console.log(this.TAG, " PasteboardPage getData err: " + JSON.stringify(err) + " pasteData: " + JSON.stringify(pasteData));if (err) {return;}this.message = pasteData.getPrimaryText();});}})}.justifyContent(FlexAlign.Center).width('100%').height('100%')}
}

module.json5

  "requestPermissions": [{"name": "ohos.permission.READ_PASTEBOARD","usedScene": {"abilities": ["FormAbility"],"when": "inuse"},"reason": "$string:module_desc",},]

http://www.ppmy.cn/embedded/138482.html

相关文章

01_Spring开胃菜

一、 为什么是Spring? 在正式进入Spring内容前我们先看看我们以往经典的程序设计。 当我们去登录时,会调用后端的Controller,Controller接收到用户的请求后会调用业务层的Service进行登录的业务处理,Service业务处理过程中会调用Dao层向DB获取数进行判断。 接下来我们用代…

软考教材重点内容 信息安全工程师 第 3 章 密码学基本理论

(本章相对老版本极大的简化,所有与算法相关的计算全部删除,因此考试需要了解各个常 用算法的基本参数以及考试中可能存在的古典密码算法的计算,典型的例子是 2021 和 2022 年分别考了 DES 算法中的 S 盒计算,RSA 中的已…

c ++零基础可视化——数组

c 零基础可视化 数组 一些知识: 关于给数组赋值,一个函数为memset,其在cplusplus.com中的描述如下: void * memset ( void * ptr, int value, size_t num );Sets the first num bytes of the block of memory pointed by ptr to…

爬虫策略与反爬机制——爬虫常见策略

随着网络爬虫技术的日益发展,反爬机制也变得越来越复杂,网站和服务商不断加强对爬虫行为的监控和限制,开发者需要采取一系列有效的爬虫策略来提高爬虫的效率并规避反爬措施。本章将介绍一些常见的爬虫策略,帮助开发者应对不同情况…

POUF: Prompt-oriented unsupervised fine-tuning for large pre-trained models

Motivation 通过提示,大规模预训练模型变得更具表现力和强大,近年来引起了人们的极大关注。虽然这些大型模型具有zero-shot能力,但一般来说,仍然需要标记数据来使它们适应下游任务。为了克服这一关键限制,我们提出了一个无监督微调框架,直接对模型进行微调或对未标记的目…

python核心语法(二)

第三节 类型转换 0.布尔值转换 使⽤⼀个内置函数bool()。 # 以下值都为True bool(2) bool(-1) bool(255) bool(0.1000001) bool(-99.99888) # 下⾯的值为False bool(0) bool(0.0)对于数值类型,所有的⾮零值转换为True, 只有零值才转换为False.字符串也可以转换为…

flutter打包签名问题

总结 build.gradle只配置了release签名,没有配置debug签名的前提下 flutter build apk --debug或者flutter run 使用的都是系统下的默认签名文件 flutter build apk --release或者AS Build->Flutter->Build APK使用的是release签名 build.gradle配置了rel…

【linux】(12)进程实时信息-top

top 是一个用于显示系统任务和进程实时信息的命令行工具,在 Unix 和 Linux 系统中非常常用。 基本用法 top启动 top 命令后,默认情况下显示当前系统中所有正在运行的进程,并实时更新。您可以通过交互式键盘命令和选项来控制 top 的显示和行…