• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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   ```