1# 使用剪贴板进行延迟复制粘贴
2
3## 场景介绍
4
5[剪贴板服务](../../reference/apis-basic-services-kit/js-apis-pasteboard.md)主要提供管理系统剪贴板的能力,为系统复制、粘贴功能提供支持。
6
7反复执行复制操作时,剪贴板缓存中会存储多余数据从而导致内存增加,为了优化内存以及后续支持指定数据类型粘贴,剪贴板提供了延迟复制粘贴的功能。
8
9用户复制使用延迟粘贴技术的应用内的数据时,该条真实数据不会立即写入剪贴板服务的缓存中,而是等需要粘贴时,再从应用获取数据。
10
11## 约束限制
12
13- 剪贴板内容大小<128MB时支持使用。
14
15## 使用基于Record级别的延迟复制粘贴(推荐)
16
17本方案可以在粘贴前查询数据type信息,应用可以据此决定是否向剪贴板请求数据,因此建议使用本方案实现延迟复制功能。
18
19### 接口说明
20
21详细接口见[Pasteboard文档](../../reference/apis-basic-services-kit/_pasteboard.md)和[UDMF接口文档](../../reference/apis-arkdata/_u_d_m_f.md)。
22
23| 名称 | 说明                                                                   |
24| -------- |----------------------------------------------------------------------|
25| OH_UdmfRecordProvider* OH_UdmfRecordProvider_Create()        | 创建一个指向统一数据提供者的指针。                          |
26| int OH_UdmfRecordProvider_SetData(OH_UdmfRecordProvider* provider, void* context, const OH_UdmfRecordProvider_GetData callback, const UdmfData_Finalize finalize) | 设置统一数据提供者的回调函数。                              |
27| int OH_UdmfRecord_SetProvider(OH_UdmfRecord* pThis, const char* const* types, unsigned int count, OH_UdmfRecordProvider* provider) | 将统一数据提供者配置到OH_UdmfRecord中。                     |
28| int OH_Pasteboard_SetData(OH_Pasteboard* pasteboard, OH_UdmfData* data) | 向剪贴板中写入数据。                                    |
29| OH_UdmfData * OH_Pasteboard_GetData (OH_Pasteboard* pasteboard, int* status) | 获取剪贴板中的数据。 |
30| OH_UdmfRecord** OH_UdmfData_GetRecords(OH_UdmfData* pThis, unsigned int* count) | 获取OH_UdmfData中全部的数据记录。                           |
31
32### 开发步骤
33
34 下面以超链接hyperlink类型数据场景为例,说明如何延迟发送数据。
35
36 为了代码可读性,代码中省略了各个步骤操作结果的校验,实际开发中需要确认每次调用的成功。
37
381. 引用头文件。
39
40   ```c
41   #include <database/pasteboard/oh_pasteboard.h>
42   #include <database/udmf/udmf.h>
43   #include <database/udmf/udmf_meta.h>
44   #include <database/udmf/uds.h>
45   ```
46
472. 定义OH_UdmfRecordProvider的数据提供函数和实例注销回调函数。
48
49   ```c
50   // 1. 获取数据时触发的提供剪贴板数据的回调函数。
51   void* GetDataCallback(void* context, const char* type) {
52      if (strcmp(type, UDMF_META_HYPERLINK) == 0) {
53          // 2. 创建超链接hyperlink数据的UDS数据结构。
54          OH_UdsHyperlink* hyperlink = OH_UdsHyperlink_Create();
55          // 3. 设置hyperlink中的URL和描述信息。
56          OH_UdsHyperlink_SetUrl(hyperlink, "www.demo.com");
57          OH_UdsHyperlink_SetDescription(hyperlink, "This is www.demo.com description.");
58          return hyperlink;
59      }
60      return nullptr;
61   }
62   // 4. OH_UdmfRecordProvider销毁时触发的回调函数。
63   void ProviderFinalizeCallback(void* context) { printf("OH_UdmfRecordProvider finalize."); }
64   ```
65
663. 在剪贴板中准备延迟复制数据。需要注意,此步骤完成后超链接类型数据并未真正写入数据库,只有当数据使用者从OH_UdmfRecord中获取OH_UdsHyperlink时,才会触发上文定义的`GetDataCallback`数据提供函数,从中得到数据。
67
68   ```c
69   // 5. 创建一个OH_UdmfRecord对象,并将OH_UdmfRecordProvider配置到其中。
70   OH_UdmfRecord* record = OH_UdmfRecord_Create();
71
72   // 6. 创建一个统一数据提供者,并配置它提供数据、销毁时的两个回调函数。
73   OH_UdmfRecordProvider* provider = OH_UdmfRecordProvider_Create();
74   OH_UdmfRecordProvider_SetData(provider, (void*)record, GetDataCallback, ProviderFinalizeCallback);
75   const char* types[1] = { UDMF_META_HYPERLINK };
76   OH_UdmfRecord_SetProvider(record, types, 1, provider);
77
78   // 7. 创建OH_UdmfData对象,并向OH_UdmfData中添加OH_UdmfRecord。
79   OH_UdmfData* setData = OH_UdmfData_Create();
80   OH_UdmfData_AddRecord(setData, record);
81
82   // 8. 创建OH_Pasteboard对象,将数据写入剪贴板中。
83   OH_Pasteboard* pasteboard = OH_Pasteboard_Create();
84   OH_Pasteboard_SetData(pasteboard, setData);
85   ```
86
874. 在剪贴板中获取延迟复制数据。
88
89   ```c
90   // 9. 剪贴板中获取延迟复制数据
91   int status = -1;
92   OH_UdmfData* getData = OH_Pasteboard_GetData(pasteboard, &status);
93
94   // 10. 获取数据中records
95   unsigned int count = 0;
96   OH_UdmfRecord** getRecords = OH_UdmfData_GetRecords(getData, &count);
97
98   // 11. 创建OH_UdsHyperlink对象,并从records中获取超链接类型数据
99   OH_UdsHyperlink* getHyperlink = OH_UdsHyperlink_Create();
100   OH_UdmfRecord_GetHyperlink(getRecords[0], getHyperlink);
101
102   // 12. 获取超链接类型数据中的URL和描述信息。
103   const char* getUrl = OH_UdsHyperlink_GetUrl(getHyperlink);
104   const char* getDescription = OH_UdsHyperlink_GetDescription(getHyperlink);
105   ```
106
1075. 使用完毕后删除相关对象。
108
109   ```c
110   OH_UdsHyperlink_Destroy(getHyperlink);
111   OH_UdmfRecordProvider_Destroy(provider);
112   OH_UdmfRecord_Destroy(record);
113   OH_UdmfData_Destroy(setData);
114   OH_UdmfData_Destroy(getData);
115   OH_Pasteboard_Destroy(pasteboard);
116   ```
117
118
119## 使用基于PasteData级别的延迟复制粘贴
120
121本方案不支持粘贴前对数据type的查询。
122
123### 接口说明
124
125| 名称 | 说明                                                                   |
126| -------- |----------------------------------------------------------------------|
127| setUnifiedData(data: udc.UnifiedData): Promise\<void> | 将统一数据类型的数据写入系统剪贴板,在使用延迟复制粘贴功能时,不可与getUnifiedDataSync同线程调用。|
128| setUnifiedDataSync(data: udc.UnifiedData): void | 将统一数据类型的数据写入系统剪贴板,此接口为同步接口,在使用延迟复制粘贴功能时,不可与getUnifiedDataSync同线程调用。|
129| getUnifiedData(): Promise\<udc.UnifiedData> | 从系统剪贴板中读取统一数据类型的数据。|
130| getUnifiedDataSync(): udc.UnifiedData | 从系统剪贴板中读取统一数据类型的数据,此接口为同步接口,在使用延迟复制粘贴功能时,不可与setUnifiedData和setUnifiedDataSync同线程调用。|
131| setAppShareOptions(shareOptions: ShareOption): void | 应用设置本应用剪贴板数据的可粘贴范围。|
132| removeAppShareOptions(): void | 应用删除本应用设置的剪贴板数据可粘贴范围配置。|
133
134### 开发步骤
135
1361. 导入pasteboard,unifiedDataChannel和uniformTypeDescriptor模块。
137
138   ```ts\
139   import {unifiedDataChannel, uniformTypeDescriptor} from '@kit.ArkData';
140   import {BusinessError, pasteboard} from '@kit.BasicServicesKit'
141   ```
142
1432. 构造一条PlainText数据,并书写获取延时数据的函数。
144
145   ```ts
146   let plainTextData = new unifiedDataChannel.UnifiedData();
147   let GetDelayPlainText = ((dataType:string) => {
148     let plainText = new unifiedDataChannel.PlainText();
149     plainText.details = {
150       Key: 'delayPlaintext',
151       Value: 'delayPlaintext',
152     };
153     plainText.textContent = 'delayTextContent';
154     plainText.abstract = 'delayTextContent';
155     plainTextData.addRecord(plainText);
156     return plainTextData;
157   });
158   ```
159
1603. 向系统剪贴板中存入一条PlainText数据。
161
162   ```ts
163   let SetDelayPlainText = (() => {
164     plainTextData.properties.shareOptions = unifiedDataChannel.ShareOptions.CROSS_APP;
165     // 跨应用使用时设置为CROSS_APP,本应用内使用时设置为IN_APP
166     plainTextData.properties.getDelayData = GetDelayPlainText;
167     pasteboard.getSystemPasteboard().setUnifiedData(plainTextData).then(()=>{
168       // 存入成功,处理正常场景
169     }).catch((error: BusinessError) => {
170       // 处理异常场景
171     });
172   })
173   ```
174
1754. 从系统剪贴板中读取这条text数据
176
177   ```ts
178   let GetPlainTextUnifiedData = (() => {
179     pasteboard.getSystemPasteboard().getUnifiedData().then((data) => {
180       let outputData = data;
181       let records = outputData.getRecords();
182       if (records[0].getType() == uniformTypeDescriptor.UniformDataType.PLAIN_TEXT) {
183         let record = records[0] as unifiedDataChannel.PlainText;
184         console.log('GetPlainText success, type:' + records[0].getType + ', details:' +
185         JSON.stringify(record.details) + ', textContent:' + record.textContent + ', abstract:' + record.abstract);
186       } else {
187         console.log('Get Plain Text Data No Success, Type is: ' + records[0].getType());
188       }
189     }).catch((error: BusinessError) => {
190       //处理异常场景
191     })
192   })
193   ```
194
1955. 应用设置本应用剪贴板数据的可粘贴范围。
196
197   ```ts
198   let systemPasteboard: pasteboard.SystemPasteboard = pasteboard.getSystemPasteboard();
199   try {
200       systemPasteboard.setAppShareOptions(pasteboard.ShareOption.INAPP);
201       console.info('Set app share options success.');
202   } catch (err) {
203       let error: BusinessError = err as BusinessError;
204       //处理异常场景
205   }
206   ```
207
2086. 应用删除本应用设置的剪贴板数据可粘贴范围配置。
209
210   ```ts
211   let systemPasteboard: pasteboard.SystemPasteboard = pasteboard.getSystemPasteboard();
212   try {
213	   systemPasteboard.removeAppShareOptions();
214	   console.info('Remove app share options success.');
215   } catch (err) {
216	   let error: BusinessError = err as BusinessError;
217       //处理异常场景
218   }
219   ```