1# 使用剪贴板进行延迟复制粘贴 2<!--Kit: Basic Services Kit--> 3<!--Subsystem: MiscServices--> 4<!--Owner: @yangxiaodong41--> 5<!--Designer: @guo867--> 6<!--Tester: @maxiaorong2--> 7<!--Adviser: @fang-jinxu--> 8 9## 场景介绍 10 11[剪贴板服务](../../reference/apis-basic-services-kit/js-apis-pasteboard.md)主要提供管理系统剪贴板的能力,为系统复制、粘贴功能提供支持。 12 13反复执行复制操作时,剪贴板缓存中会存储多余数据从而导致内存增加,为了优化内存以及后续支持指定数据类型粘贴,剪贴板提供了延迟复制粘贴的功能。 14 15用户复制使用延迟复制技术的应用内的数据时,该条真实数据不会立即写入剪贴板服务的缓存中,而是等需要粘贴时,再从应用获取数据。 16 17## 约束限制 18 19- 剪贴板内容包含剪贴板系统服务元数据和应用设置的数据,总大小上限默认为128MB,PC/2in1设备可通过系统配置修改上限,有效范围为128MB~2GB。 20 21- NDK接口仅支持Record级别的延迟复制粘贴。 22 23- ArkTS接口仅支持PasteData级别的延迟复制粘贴。 24 25## 使用基于Record级别的延迟复制粘贴(推荐) 26 27本方案可以在粘贴前查询数据type信息,应用可以据此决定是否向剪贴板请求数据,因此建议使用本方案实现延迟复制功能。 28 29### 接口说明 30 31详细接口见[Pasteboard文档](../../reference/apis-basic-services-kit/capi-pasteboard.md)和[UDMF接口文档](../../reference/apis-arkdata/capi-udmf.md)。 32 33| 名称 | 说明 | 34| -------- |----------------------------------------------------------------------| 35| OH_UdmfRecordProvider* OH_UdmfRecordProvider_Create() | 创建一个指向统一数据提供者的指针。 | 36| int OH_UdmfRecordProvider_SetData(OH_UdmfRecordProvider* provider, void* context, const OH_UdmfRecordProvider_GetData callback, const UdmfData_Finalize finalize) | 设置统一数据提供者的回调函数。 | 37| int OH_UdmfRecord_SetProvider(OH_UdmfRecord* pThis, const char* const* types, unsigned int count, OH_UdmfRecordProvider* provider) | 将统一数据提供者配置到OH_UdmfRecord中。 | 38| int OH_Pasteboard_SetData(OH_Pasteboard* pasteboard, OH_UdmfData* data) | 向剪贴板中写入数据。 | 39| OH_UdmfData * OH_Pasteboard_GetData(OH_Pasteboard* pasteboard, int* status) | 获取剪贴板中的数据。 | 40| OH_UdmfRecord** OH_UdmfData_GetRecords(OH_UdmfData* pThis, unsigned int* count) | 获取OH_UdmfData中全部的数据记录。 | 41 42### 开发步骤 43 44 下面以纯文本类型和HTML类型数据为例,说明如何向剪贴板服务设置延迟复制数据。 45 46 为了代码可读性,代码中省略了各个步骤操作结果的校验,实际开发中需要确认每次调用的成功。 47 481. 引用头文件。 49 50 ```c 51 #include <database/pasteboard/oh_pasteboard.h> 52 #include <database/udmf/udmf.h> 53 #include <database/udmf/udmf_meta.h> 54 #include <database/udmf/uds.h> 55 ``` 56 572. 定义`OH_UdmfRecordProvider`的数据提供函数和实例注销回调函数。 58 59 ```c 60 // 1. 获取数据时触发的提供剪贴板数据的回调函数。 61 void* GetDataCallback(void* context, const char* type) { 62 // 纯文本类型 63 if (strcmp(type, UDMF_META_PLAIN_TEXT) == 0) { 64 // 创建纯文本类型的Uds对象。 65 OH_UdsPlainText* udsText = OH_UdsPlainText_Create(); 66 // 设置纯文本内容。 67 OH_UdsPlainText_SetContent(udsText, "hello world"); 68 return udsText; 69 } 70 // HTML类型 71 else if (strcmp(type, UDMF_META_HTML) == 0) { 72 // 创建HTML类型的Uds对象。 73 OH_UdsHtml* udsHtml = OH_UdsHtml_Create(); 74 // 设置HTML内容。 75 OH_UdsHtml_SetContent(udsHtml, "<div>hello world</div>"); 76 return udsHtml; 77 } 78 return nullptr; 79 } 80 // 2. OH_UdmfRecordProvider销毁时触发的回调函数。 81 void ProviderFinalizeCallback(void* context) { 82 printf("OH_UdmfRecordProvider finalize."); 83 } 84 ``` 85 863. 在剪贴板中准备延迟复制数据。需要注意,此步骤完成后纯文本类型数据与HTML类型数据并未真正写入剪贴板服务,只有当数据使用者从`OH_UdmfRecord`中获取`OH_UdsPlainText`或`OH_UdsHtml`时,才会触发上文定义的`GetDataCallback`数据提供函数,从中得到数据。 87 88 ```c 89 // 3. 创建OH_UdmfRecord对象。 90 OH_UdmfRecord* record = OH_UdmfRecord_Create(); 91 92 // 4. 创建OH_UdmfRecordProvider对象,并设置用于提供延迟数据、析构的两个回调函数。 93 OH_UdmfRecordProvider* provider = OH_UdmfRecordProvider_Create(); 94 OH_UdmfRecordProvider_SetData(provider, (void*)record, GetDataCallback, ProviderFinalizeCallback); 95 96 // 5. 将provider绑定到record,并设置支持的数据类型。 97 const char* types[2] = { UDMF_META_PLAIN_TEXT, UDMF_META_HTML }; 98 OH_UdmfRecord_SetProvider(record, types, 2, provider); 99 100 // 6. 创建OH_UdmfData对象,并向OH_UdmfData中添加OH_UdmfRecord。 101 OH_UdmfData* setData = OH_UdmfData_Create(); 102 OH_UdmfData_AddRecord(setData, record); 103 104 // 7. 创建OH_Pasteboard对象,将数据写入剪贴板中。 105 OH_Pasteboard* pasteboard = OH_Pasteboard_Create(); 106 OH_Pasteboard_SetData(pasteboard, setData); 107 ``` 108 1094. 从剪贴板获取延迟复制数据。 110 111 ```c 112 // 8. 从剪贴板获取OH_UdmfData。 113 int status = -1; 114 OH_UdmfData* getData = OH_Pasteboard_GetData(pasteboard, &status); 115 116 // 9. 获取OH_UdmfData中的所有OH_UdmfRecord。 117 unsigned int recordCount = 0; 118 OH_UdmfRecord** getRecords = OH_UdmfData_GetRecords(getData, &recordCount); 119 120 // 10. 遍历OH_UdmfRecord。 121 for (unsigned int recordIndex = 0; recordIndex < recordCount; ++recordIndex) { 122 OH_UdmfRecord* record = getRecords[recordIndex]; 123 124 // 11. 查询OH_UdmfRecord中的数据类型。 125 unsigned typeCount = 0; 126 char** recordTypes = OH_UdmfRecord_GetTypes(record, &typeCount); 127 128 // 12. 遍历数据类型。 129 for (unsigned int typeIndex = 0; typeIndex < typeCount; ++typeIndex) { 130 char* recordType = recordTypes[typeIndex]; 131 132 // 纯文本类型 133 if (strcmp(recordType, UDMF_META_PLAIN_TEXT) == 0) { 134 // 创建纯文本类型的Uds对象 135 OH_UdsPlainText* udsText = OH_UdsPlainText_Create(); 136 // 从record中获取纯文本类型的Uds对象 137 OH_UdmfRecord_GetPlainText(record, udsText); 138 // 从Uds对象中获取内容 139 const char* content = OH_UdsPlainText_GetContent(udsText); 140 } 141 // HTML类型 142 else if (strcmp(recordType, UDMF_META_HTML) == 0) { 143 // 创建HTML类型的Uds对象 144 OH_UdsHtml* udsHtml = OH_UdsHtml_Create(); 145 // 从record中获取HTML类型的Uds对象 146 OH_UdmfRecord_GetHtml(record, udsHtml); 147 // 从Uds对象中获取内容 148 const char* content = OH_UdsHtml_GetContent(udsHtml); 149 } 150 } 151 } 152 ``` 153 1545. 使用完毕后需要及时释放相关对象的内存。 155 156 ```c 157 OH_UdsPlainText_Destroy(udsText); 158 OH_UdsHtml_Destroy(udsHtml); 159 OH_UdmfRecordProvider_Destroy(provider); 160 OH_UdmfRecord_Destroy(record); 161 OH_UdmfData_Destroy(setData); 162 OH_UdmfData_Destroy(getData); 163 OH_Pasteboard_Destroy(pasteboard); 164 ``` 165 166 167## 使用基于PasteData级别的延迟复制粘贴 168 169本方案不支持粘贴前对数据type的查询。 170 171### 接口说明 172 173| 名称 | 说明 | 174| -------- |----------------------------------------------------------------------| 175| setUnifiedData(data: unifiedDataChannel.UnifiedData): Promise\<void> | 将统一数据类型的数据写入系统剪贴板,在使用延迟复制粘贴功能时,不可与getUnifiedDataSync同线程调用。| 176| setUnifiedDataSync(data: unifiedDataChannel.UnifiedData): void | 将统一数据类型的数据写入系统剪贴板,此接口为同步接口,在使用延迟复制粘贴功能时,不可与getUnifiedDataSync同线程调用。| 177| getUnifiedData(): Promise\<unifiedDataChannel.UnifiedData> | 从系统剪贴板中读取统一数据类型的数据。| 178| getUnifiedDataSync(): unifiedDataChannel.UnifiedData | 从系统剪贴板中读取统一数据类型的数据,此接口为同步接口,在使用延迟复制粘贴功能时,不可与setUnifiedData和setUnifiedDataSync同线程调用。| 179| setAppShareOptions(shareOptions: ShareOption): void | 应用设置本应用剪贴板数据的可粘贴范围。| 180| removeAppShareOptions(): void | 应用删除本应用设置的剪贴板数据可粘贴范围配置。| 181 182### 开发步骤 183 1841. 导入pasteboard,unifiedDataChannel和uniformTypeDescriptor模块。 185 186 ```ts\ 187 import {unifiedDataChannel, uniformTypeDescriptor} from '@kit.ArkData'; 188 import {BusinessError, pasteboard} from '@kit.BasicServicesKit' 189 ``` 190 1912. 构造一条PlainText数据,并书写获取延时数据的函数。 192 193 ```ts 194 let plainTextData = new unifiedDataChannel.UnifiedData(); 195 let GetDelayPlainText = ((dataType:string) => { 196 let plainText = new unifiedDataChannel.PlainText(); 197 plainText.details = { 198 Key: 'delayPlaintext', 199 Value: 'delayPlaintext', 200 }; 201 plainText.textContent = 'delayTextContent'; 202 plainText.abstract = 'delayTextContent'; 203 plainTextData.addRecord(plainText); 204 return plainTextData; 205 }); 206 ``` 207 2083. 向系统剪贴板中存入一条PlainText数据。 209 210 ```ts 211 let SetDelayPlainText = (() => { 212 plainTextData.properties.shareOptions = unifiedDataChannel.ShareOptions.CROSS_APP; 213 // 跨应用使用时设置为CROSS_APP,本应用内使用时设置为IN_APP 214 plainTextData.properties.getDelayData = GetDelayPlainText; 215 pasteboard.getSystemPasteboard().setUnifiedData(plainTextData).then(()=>{ 216 // 存入成功,处理正常场景 217 }).catch((error: BusinessError) => { 218 // 处理异常场景 219 }); 220 }) 221 ``` 222 2234. 从系统剪贴板中读取这条text数据。 224 225 ```ts 226 let GetPlainTextUnifiedData = (() => { 227 pasteboard.getSystemPasteboard().getUnifiedData().then((data) => { 228 let outputData = data; 229 let records = outputData.getRecords(); 230 if (records[0].getType() == uniformTypeDescriptor.UniformDataType.PLAIN_TEXT) { 231 let record = records[0] as unifiedDataChannel.PlainText; 232 console.info('GetPlainText success, type:' + records[0].getType() + ', details:' + 233 JSON.stringify(record.details) + ', textContent:' + record.textContent + ', abstract:' + record.abstract); 234 } else { 235 console.info('Get Plain Text Data No Success, Type is: ' + records[0].getType()); 236 } 237 }).catch((error: BusinessError) => { 238 //处理异常场景 239 }) 240 }) 241 ``` 242 2435. 应用设置本应用剪贴板数据的可粘贴范围。 244 245 ```ts 246 let systemPasteboard: pasteboard.SystemPasteboard = pasteboard.getSystemPasteboard(); 247 try { 248 systemPasteboard.setAppShareOptions(pasteboard.ShareOption.INAPP); 249 console.info('Set app share options success.'); 250 } catch (err) { 251 let error: BusinessError = err as BusinessError; 252 //处理异常场景 253 } 254 ``` 255 2566. 应用删除本应用设置的剪贴板数据可粘贴范围配置。 257 258 ```ts 259 let systemPasteboard: pasteboard.SystemPasteboard = pasteboard.getSystemPasteboard(); 260 try { 261 systemPasteboard.removeAppShareOptions(); 262 console.info('Remove app share options success.'); 263 } catch (err) { 264 let error: BusinessError = err as BusinessError; 265 //处理异常场景 266 } 267 ```