1、申请访问剪贴板权限

读取剪贴板权限为ACL受控权限,只有符合条件的应用才可以申请,使用系统控件和安全粘贴控件的应用不需要申请。

添加权限示例:

module.json中添加权限
"requestPermissions": [
      {
        "name": "ohos.permission.READ_PASTEBOARD",
        "reason": "$string:module_desc",
        "usedScene": {
          "abilities": [
            "EntryAbility.ets"
          ],
          "when": "always"
        }
      }
    ]
async getPermission(): Promise<boolean> {
    let atManager: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager();
    let bundleInfo: bundleManager.BundleInfo;
    bundleInfo = await bundleManager.getBundleInfoForSelf(bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_APPLICATION);
    let tokenId: number = bundleInfo.appInfo.accessTokenId;
    let permissions: Permissions[] = ['ohos.permission.READ_PASTEBOARD'];
    let grantStatus: abilityAccessCtrl.GrantStatus = atManager.checkAccessTokenSync(tokenId, permissions[0]);
    if (grantStatus === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED) {
      return true;
    }
    let requestResult: PermissionRequestResult = await atManager.requestPermissionsFromUser(getContext(), permissions);
    if (requestResult.authResults.length > 0) {
      return requestResult.authResults[0] === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED;
    } else {
      return false;
    }
  }

2、使用剪贴板进行复制粘贴

ArkTS以及C/C++开发指导链接参考:使用剪贴板进行复制粘贴使用剪贴板进行延迟复制粘贴使用剪贴板进行复制粘贴 (C/C++)

2.1 剪贴板多样式能力介绍

概要

Record对应复制数据的不同内容片段,Entry对应同一份数据的不同格式。

剪贴板多样式指的是一个record中携带多个entry数据,并且剪贴板对PasteData和UDMF两种数据结构都能够支持,以下有这两种数据结构构造多样式的方法:分别对应TS接口多样式以及NDK接口多样式。

由于现在有部分应用没有适配多entry,默认读取record的第一个样式,这里建议应用设置多entry时,将系统提供的样式放在前面,自定义的样式放在最后,提高系统兼容性

2.1.1如何复制多样式数据

为了复制应用和粘贴应用对剪贴板数据内容理解一致,更好的实现不同应用间的复制粘贴体验,应用适配剪贴板时需按如下原则处理:

1)复制数据内容尽量只使用一个Record携带,对于复制数据内容的不同格式,使用同一Record的不同Entry携带。

2)如果存在一个Record无法携带所有数据的场景,比如多文件复制时的多个uri,此时使用多Record携带复制数据内容的不同部分。

3)应用将支持的所有剪贴板数据格式都写入剪贴板,以保证复制数据可以在所有可能粘贴的场景被粘贴。

NDK接口

使用UDMF数据结构,在剪贴板的NDK中复制的时候,数据结构示意图如下:

如下为复制一个单record,多样式的数据的代码示例。粘贴数据的代码示例见指导文档。

// 创建样式数据
OH_UdsPlainText *plainText = OH_UdsPlainText_Create();
OH_UdsPlainText_SetContent(plainText, "Hello world");

OH_UdsHtml *html = OH_UdsHtml_Create();
OH_UdsHtml_SetContent(html, "<html><h>Hello world</h></html>");

OH_UdsFileUri *fileUri = OH_UdsFileUri_Create();
OH_UdsFileUri_SetFileUri(fileUri, "file://media/Photo/1/IMG_1731465487_001/screenshot_20241113_091535.jpeg");
OH_UdsFileUri_SetFileType(fileUri, "general.image");

// 创建一个record,将样式数据加进去
OH_UdmfRecord *record = OH_UdmfRecord_Create();
OH_UdmfRecord_AddPlainText(record, plainText);
OH_UdmfRecord_AddHtml(record, html);
OH_UdmfRecord_AddFileUri(record, fileUri);

// 创建udmfData,将record加进去
OH_UdmfData *data = OH_UdmfData_Create();
OH_UdmfData_AddRecord(data, record);

// 复制数据
OH_Pasteboard* pasteboard = OH_Pasteboard_Create();
OH_Pasteboard_SetData(pasteboard, data);

TS接口

使用TS接口,进行原始数据结构,进行复制粘贴时,使用的剪贴板数据结构示意图如下:

有两种方式来构造单record中多样式数据的方法。

1、createData构造多样式:

// 创建1个包含单record,多样式数据
let pasteData: pasteboard.PasteData = pasteboard.createData({
    'text/plain': 'hello',
    'text/uri': 'file://media/Photo/1/IMG_1731465487_001/screenshot_20241113_091535.jpeg',
    'app/xml': new ArrayBuffer(256),
});
// 粘贴到剪贴板
pasteboard.getSystemPasteboard().setData(pasteData);

2、addEntry构造多样式:

// 创建一个包含单样式的pasteData数据
let pasteData: pasteboard.PasteData = pasteboard.createData({
    'app/xml': new ArrayBuffer(256),  // 这是一个自定义样式数据
});

// 给pasteData中的这个record添加额外两种样式
let record: pasteboard.PasteDataRecord = pasteData.getRecord(0);;
record.addEntry(pasteboard.MIMETYPE_TEXT_HTML, '<html><h>Hello world</h></html>');
record.addEntry(pasteboard.MIMETYPE_TEXT_PLAIN, 'hello world');

// 粘贴到剪贴板
pasteboard.getSystemPasteboard().setData(pasteData);

2.1.2如何粘贴多样式数据

剪贴板数据属于个人数据,读取剪贴板数据需要支持剪贴板读取权限授权,剪贴板提供了安全控件和用户授权ohos.permission.READ_PASTEBOARD权限两种授权方式。

复制应用写入剪贴板的数据可能包含多种格式数据,粘贴应用需根据当前粘贴页面和场景选择最合适的格式进行粘贴显示。

剪贴板同时提供了TS API和NDK API,应用按需选择合适的API支持复制粘贴功能。

NDK接口

首先复制多样式数据,示例如下:

// 方法一:使用record和pasteData的构造函数逐个样式添加的方式构造多样式数据
// 创建一个html样式的record
auto record = PasteDataRecord::NewHtmlRecord("<html><h>Hello world</h></html>");

// 给这个record添加一个uri样式数据
auto uriUtdId = CommonUtils::Convert2UtdId(UDMF::UDType::UD_BUTT, MIMETYPE_TEXT_URI);
auto uriEntry = std::make_shared<PasteDataEntry>(uriUtdId, "file://media/Photo/1/IMG_1731465487_001/screenshot_20241113_091535.jpeg");
record.AddEntryByMimeType(MIMETYPE_TEXT_URI, uriEntry);

// 给这个record添加一个文本样式数据
auto textPlainUtdId = CommonUtils::Convert2UtdId(UDMF::UDType::UD_BUTT, MIMETYPE_TEXT_PLAIN);
auto textPlainEntry = std::make_shared<PasteDataEntry>(textPlainUtdId, "hello world");
record.AddEntryByMimeType(MIMETYPE_TEXT_PLAIN, textPlainEntry);

// 复制
auto pasteData = new PasteData::PasteData();
pasteData.addRecord(record);
PasteboardClient::GetInstance()->SetPasteData(pasteData);
// 方法二:使用PasteDataRecord的NewMultiTypeRecord函数创建多样式record,参数和调用情况和方法三相同

// 方法三:直接使用PasteboardClient提供的多样式数据创建的函数构造多样式数据
// 直接构造单record多样式的数据
std::shared_ptr<std::map<std::string, std::shared_ptr<EntryValue>>> mapPtr = std::make_shared<std::map<std::string, std::shared_ptr<EntryValue>>>;
mapPtr->insert_or_assign(MIMETYPE_TEXT_PLAIN, std::make_shared<ValueType>("Hello world"));
mapPtr->insert_or_assign(MIMETYPE_TEXT_URI, std::make_shared<ValueType>("<html>Hello world</html>"));
mapPtr->insert_or_assign(MIMETYPE_TEXT_HTML, std::make_shared<ValueType>("<html>Hello world</html>"));
// 创建一个包含1个record的pasteData,这个record中包含三种样式数据且这个record的默认样式为MIMETYPE_TEXT_PLAIN。
auto pasteData2 = PasteboardClient::GetInstance()->CreateMultiTypeData(mapPtr, MIMETYPE_TEXT_PLAIN);
PasteboardClient::GetInstance()->SetPasteData(pasteData2);

粘贴时读取pasteData以及从pasteData中读取record函数和非多样式没有区别,从record中读取样式数据时,推荐直接使用GetEntryByMimeType函数。

// 粘贴
PasteData gettedData;
PasteboardClient::GetInstance()->GetPasteData(gettedData);
auto textEntry = gettedData.GetRecordAt(0).GetEntryByMimeType(MIMETYPE_TEXT_PLAIN);
auto text = textEntry.ConvertToPlainText();
printf("Getted text: %s", text);

TS接口

// 创建1个包含单record,多样式数据
let pasteData: pasteboard.PasteData = pasteboard.createData({
    'text/plain': 'hello',
    'text/uri': 'file://media/Photo/1/IMG_1731465487_001/screenshot_20241113_091535.jpeg',
    'app/xml': new ArrayBuffer(256),
});
// 复制到剪贴板
pasteboard.getSystemPasteboard().setData(pasteData);

// 粘贴数据
let gettedData = await pasteboard.getSystemPasteboard().getData();
let gettedRecord = gettedData.getRecord(0);
// 判断这个record中是否有传入的样式数据,此示例中返回的types应该是: [ pasteboard.MIMETYPE_TEXT_PLAIN, pasteboard.MIMETYPE_TEXT_URI, 'app/xml' ]
let types: string[] = gettedRecord.getValidTypes([
    pasteboard.MIMETYPE_TEXT_PLAIN,
    pasteboard.MIMETYPE_TEXT_HTML,
    pasteboard.MIMETYPE_TEXT_URI,
    pasteboard.MIMETYPE_TEXT_WANT,
    pasteboard.MIMETYPE_PIXELMAP,
    'app/xml'
]);
// 读取其中默认的'text/plain'数据(也可以按照下面uri的读取方式读取)
let plainTextContent = gettedData.getPrimaryText();

// 读取其中的uri样式数据(非默认样式,只能用这个函数读取)
gettedRecord.getData(pasteboard.MIMETYPE_TEXT_URI).then((value: pasteboard.ValueType) => {
    let uri = value as string;
    console.info('Success to get text/uri value. value is: ' + uri);
}).catch((err: BusinessError) => {
    console.error('Failed to get text/uri value. Cause: ' + err.message);
});

2.2 跨设备剪贴板能力介绍

如果应用支持跨设备复制、粘贴,如下参数这样设置:

Udmf_ShareOption参数不设置,保持默认。

ShareOption参数不设置,保持默认。

API12后CROSSDEVICE废弃,由设置->多设备协同->跨设备剪贴板开关决定。

3 组件的CopyOptions参数不设置或设置为LocalDevice或设置为CROSS_DEVICE。

  • INAPP:表示仅允许在本设备本应用内粘贴。
  • LocalDevice、CROSS_DEVICE:允许在其他应用粘贴,是否允许跨设备粘贴由设置->多设备协同->跨设备剪贴板开关决定。

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐