鸿蒙 Next 中如何获取剪切板的内容?

623 阅读4分钟

前言

在移动端的日常应用开发中,读取剪切板的内容是一个比较常见的功能实现,比如登录中验证码的粘贴输入,或者购物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 中的值,如果直接输入一个字符串会报错。如下图: 截屏2024-08-05 15.42.55.png
  • 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();
    });
  }
})