前言
在移动端的日常应用开发中,读取剪切板的内容是一个比较常见的功能实现,比如登录中验证码的粘贴输入,或者购物APP 中搜索框内容的粘贴输入。在这篇文章中,我们就来了解一下在鸿蒙系统中,开发者如何获取剪切板中的内容。
整体流程
如果开发者想要获取剪切板中的内容,主要分为以下三个步骤:
- 第一步,需要先去
module.json5文件中去申请读取剪切板的权限。 - 第二步,需要获取当前应用的授权状态来进行逻辑处理。
- 最后一步,则是在根据应用的授权状态结果来进行相应的 UI 处理。
下面,让我们一步一步去实现一下!
申请权限
首先,我们使用剪切板功能需要在 module.json5 文件中去申请相应的权限,申请剪切板读取功能的权限代码如下:
// module.json5
"requestPermissions": [
{
"name": "ohos.permission.READ_PASTEBOARD",
"reason": "$string:request_paste_reason",
"usedScene": {
"abilities": ["EntryAbility"]
}
}
],
// string.json
{
"name": "request_paste_reason",
"value": "需要获取系统剪切板权限进行业务处理!"
}
- name 字段是指我们需要申请什么权限,此处我们填写读取剪切板权限即可:
ohos.permission.READ_PASTEBOARD。 - reason 字段则是向用户说明,应用程序为什么需要用户的剪切板读取权限,注意此处需要使用
string.json中的值,如果直接输入一个字符串会报错。如下图: - usedScene 字段则是需要在哪个 ability 中使用。
Tips: 如果没有在 module.json5 文件中申请权限,但在代码中又写了判断应用是否获得用户剪切板读取权限的代码,那会直接走 requestPermissionsFromUser方法用户拒绝的分支,而不是应用崩溃。
获取应用的申请权限
首先,我们需要检测当前应用是否已经获取了用户的读取剪切板权限,先导入使用到的头文件:
import { abilityAccessCtrl, bundleManager, common, Permissions } from '@kit.AbilityKit';
特别注意 bundleManager 的头文件不要导入成下面这个。。。。
// import { bundleManager } from '@kit.MDMKit';
import { BusinessError, pasteboard } from '@kit.BasicServicesKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
import { promptAction } from '@kit.ArkUI';
接着去判断应用是否有某个权限的授权:
async checkAccessToken(permission: Permissions): Promise<abilityAccessCtrl.GrantStatus> {
let atManager: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager();
let grantStatus: abilityAccessCtrl.GrantStatus = abilityAccessCtrl.GrantStatus.PERMISSION_DENIED;
// 获取应用程序的accessTokenID
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 (error) {
// 错误逻辑处理
}
// 校验应用是否被授予权限
try {
grantStatus = await atManager.checkAccessToken(tokenId, permission);
} catch (error) {
// 错误逻辑处理
}
return grantStatus;
}
如果,当前应用已经获得了剪切板读取权限,那么直接去读取剪切板的内容:
async getPaste() {
const permissions: Array<Permissions> = ['ohos.permission.READ_PASTEBOARD'];
let grantStatus1: abilityAccessCtrl.GrantStatus = await this.checkAccessToken(permissions[0]);
if (grantStatus1 === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED) {
try {
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;
}
this.pasteText = pasteData.getPrimaryText();
});
} catch (err) {
// 错误逻辑处理
}
} else {
// 申请权限
if (this.permission_state) {
this.reqPermissionsFromUser(permissions)
} else {
}
}
}
如果未获得权限,则调用 requestPermissionsFromUser 方法去弹框提示用户授权:
reqPermissionsFromUser(permissions: Array<Permissions>): void {
let context = getContext(this) as common.UIAbilityContext;
let atManager = abilityAccessCtrl.createAtManager();
// requestPermissionsFromUser会判断权限的授权状态来决定是否唤起弹窗
atManager.requestPermissionsFromUser(context, permissions).then((data) => {
let grantStatus: Array<number> = data.authResults;
let length: number = grantStatus.length;
for (let i = 0; i < length; i++) {
if (grantStatus[i] === 0) {
// 用户授权,可以继续访问目标操作
this.permission_state = true;
} else {
// 用户拒绝授权,提示用户必须授权才能访问当前页面的功能,并引导用户到系统设置中打开相应的权限
promptAction.showToast({message: "请去系统设置 -> 隐私与安全 -> 剪切板权限 允许应用访问", duration: 2000})
this.permission_state = false;
}
}
// 授权成功
}).catch((err: String) => {
})
}
需要注意的是,如果用户权限弹窗已经点击了拒绝,requestPermissionsFromUser 则不会再弹窗,而是直接走用户拒绝授权的分支。
获得授权之后的 UI 展示
这一步就是根据自己的业务需求进行 UI 上的处理了,完整代码如下:
@Entry
@Component
struct Index {
@State permission_state: boolean = true;
@State pasteText: string = '';
build() {
Column() {
Button("获取剪切板内容")
.onClick(() => {
this.getPaste();
})
Text(this.pasteText)
}
.height('100%')
.width('100%')
}
}
PasteButton
PasteButton 组件是鸿蒙系统的一种特殊的系统安全控件,它允许应用在用户的授权下无提示地读取剪贴板数据。比如粘贴验证码这个场景,使用该组件就可以避免用户还得点击授权弹框然后再粘贴。示例代码如下:
PasteButton().onClick((event: ClickEvent, result: PasteButtonOnClickResult) => {
if (PasteButtonOnClickResult.SUCCESS === result) {
pasteboard.getSystemPasteboard().getData((err: BusinessError, pasteData: pasteboard.PasteData) => {
this.pasteText = pasteData.getPrimaryText();
});
}
})