当前位置:首页 > 数据库

HarmonyOS Sample 之 Pasteboard 分布式粘贴板

想了解更多内容,分布请访问:

和华为官方合作共建的式粘鸿蒙技术社区

https://harmonyos.51cto.com

一、介绍

HarmonyOS提供系统剪贴板服务的贴板操作接口,支持用户程序从系统剪贴板中读取、分布写入和查询剪贴板数据,式粘以及添加、贴板移除系统剪贴板数据变化的分布回调。

设备内:

用户通过系统剪贴板服务,式粘可实现应用之间的贴板简单数据传递。例如:在应用A中复制的分布数据,可以在应用B中粘贴,式粘反之亦可。贴板

设备间:

在分布式粘贴板场景中,分布粘贴的式粘数据可以跨设备写入。例如,贴板设备A上的应用程序使用系统粘贴板接口将从设备A复制的数据通过IDL接口存储到设备B的系统粘贴板中。如果数据允许,设备B上的应用程序可以读取并粘贴系统粘贴板中的复制数据。实现设备之间粘贴板的分布式协同。

基于以上理解,实现一个分布式粘贴板应用程序,应用程序分为客户端(copy)和服务端(paste)两部分,云服务器提供商通过idl实现数据传递。

客户端负责数据采集,服务端负责数据的展示和应用,客户端和服务端可以安装在同一台设备中,也可以安装在不同的设备中,服务端也可以按照在多台设备中,服务端通过分布式数据库实现粘贴板数据的自动同步。

二、效果展示

三、搭建环境

安装DevEco Studio,详情请参考DevEco Studio下载。

设置DevEco Studio开发环境,DevEco Studio开发环境需要依赖于网络环境,需要连接上网络才能确保工具的正常使用,可以根据如下两种情况来配置开发环境:

如果可以直接访问Internet,只需进行下载HarmonyOS SDK操作。

如果网络不能直接访问Internet,需要通过代理服务器才可以访问,请参考配置开发环境。

下载源码后,使用DevEco Studio 打开项目,模拟器运行即可。

真机运行需要将config.json中的buddleName修改为自己的,如果没有请到AGC上进行配置,参见 使用模拟器进行调试 。

四、项目结构

五、代码讲解

5.1 系统粘贴板基础功能介绍

系统粘贴板对象介绍

1.SystemPasteboard //系统粘贴板对象,亿华云计算定义系统粘贴板操作,包括复制、粘贴和设置粘贴板内容更改的侦听器。

2.PasteData//表示粘贴板上的粘贴数据。

3.PasteData.DataProperty //该类定义了系统粘贴板上 PasteData 的属性,包括时间戳、MIME 类型和其他属性数据。

4.PasteData.Record//该类将单个粘贴的数据定义为 Record,它可以是纯文本、HTML 文本、URI 和意图。 PasteData 对象包含一个或多个记录。

客户端(copy)CopyAbilitySlice.java

获取系统粘贴板,监听粘贴板数据变化

/**  * 获取系统粘贴板  * 监听粘贴板数据变化  */ private void initPasteboard() {      HiLog.debug(LABEL, "initPasteboard");     //获取系统粘贴板对象     pasteboard = SystemPasteboard.getSystemPasteboard(this);     //监听粘贴板数据变化     pasteboard.addPasteDataChangedListener(() -> {          if (pasteboard.hasPasteData()) {              sync_text = getPasteData();             HiLog.debug(LABEL, "%{ public}s", "pasteStr:" + sync_text);         }     }); } 

获取粘贴板内容

/**  * 获取粘贴板记录  *  * @return  */ private String getPasteData() {      HiLog.debug(LABEL, "getPasteData");     String result = "";     //粘贴板数据对象     PasteData pasteData = pasteboard.getPasteData();     if (pasteData == null) {          return result;     }     PasteData.DataProperty dataProperty = pasteData.getProperty();     //     boolean hasHtml = dataProperty.hasMimeType(PasteData.MIMETYPE_TEXT_HTML);     boolean hasText = dataProperty.hasMimeType(PasteData.MIMETYPE_TEXT_PLAIN);     //数据格式类型     if (hasHtml || hasText) {          for (int i = 0; i < pasteData.getRecordCount(); i++) {              //粘贴板数据记录             PasteData.Record record = pasteData.getRecordAt(i);             //不同类型获取方式不同             String mimeType = record.getMimeType();             //HTML文本             if (mimeType.equals(PasteData.MIMETYPE_TEXT_HTML)) {                  result = record.getHtmlText();                 //纯文本             } else if (mimeType.equals(PasteData.MIMETYPE_TEXT_PLAIN)) {                  result = record.getPlainText().toString();                 //             } else {                  HiLog.info(LABEL, "%{ public}s", "getPasteData mimeType :" + mimeType);             }         }     }     return result; } 

设置文本到粘贴板中

/**  * 设置文本到粘贴板  *  * @param component  */ private void setTextToPaste(Component component) {      HiLog.info(LABEL, "setTextToPaste");     if (pasteboard != null) {          String text = syncText.getText();         if (text.isEmpty()) {              showTips(this, "请填写内容");             return;         }         //把记录添加到粘贴板         PasteData pasteData=  PasteData.creatPlainTextData(text);         //设置文本到粘贴板         pasteboard.setPasteData(pasteData);         showTips(this, "复制成功");         HiLog.info(LABEL, "setTextToPaste succeeded");     } } 

清空粘贴板

/**  * 清空粘贴板  *  * @param component  */ private void clearPasteboard(Component component) {      if (pasteboard != null) {          pasteboard.clear();         showTips(this, "Clear succeeded");     } } 

5.2 分布式粘贴板应用构建思路介绍

选择远端连接设备

本实例是通过新增加一个DevicesSelectAbility来实现的。

private void showDevicesDialog() {      Intent intent = new Intent();     //打开选择设备的Ability页面DevicesSelectAbility     Operation operation =             new Intent.OperationBuilder()                     .withDeviceId("")                     .withBundleName(getBundleName())                     .withAbilityName(DevicesSelectAbility.class)                     .build();     intent.setOperation(operation);     //携带一个设备选择请求标识,打开设备选择页面(DevicesSelectAbility) TODO     startAbilityForResult(intent, Constants.PRESENT_SELECT_DEVICES_REQUEST_CODE); } /**  * 打开设备选择Ability后,选择连接的设备执行setResult后触发  *  * @param requestCode  * @param resultCode  * @param resultIntent  */ @Override protected void onAbilityResult(int requestCode, int resultCode, Intent resultIntent) {      HiLog.debug(LABEL, "onAbilityResult");     if (requestCode == Constants.PRESENT_SELECT_DEVICES_REQUEST_CODE && resultIntent != null) {          //获取用户选择的设备         String devicesId = resultIntent.getStringParam(Constants.PARAM_DEVICE_ID);         //连接粘贴板服务端         connectService(devicesId);         return;     } } 

连接粘贴板服务端ServiceAbility服务

idl文件放在ohos.samples.pasteboard.paste目录下,Gradl窗口,执行compileDebugIdl 后,系统生成代理对象。

interface ohos.samples.pasteboard.paste.ISharePasteAgent {      /*      * 设置系统粘贴板      */     void setSystemPaste([in] String param); } 

连接服务端ServiceAbility,如果组网中没有其他设备就连接本地的服务端。

连接成功后,初始化idl的服务器租用SharePasteAgentProxy代理,用于下一步的同步数据。

//idl共享粘贴板代理 private SharePasteAgentProxy remoteAgentProxy; /**  * 连接粘贴板服务中心  */ private void connectService(String deviceId) {      HiLog.debug(LABEL, "%{ public}s", "connectService");     if (!isConnect) {          boolean isConnectRemote = deviceId != null;         //三元表达式,判断连接本地还是远端Service         Intent intent = isConnectRemote                 ? getRemoteServiceIntent(REMOTE_BUNDLE, REMOTE_SERVICE, deviceId)                 : getLocalServiceIntent(REMOTE_BUNDLE, REMOTE_SERVICE);         HiLog.debug(LABEL, "%{ public}s", "intent:" + intent);         //连接 Service         connectAbility(intent, new IAbilityConnection() {              @Override             public void onAbilityConnectDone(ElementName elementName, IRemoteObject iRemoteObject, int resultCode) {                  //发个通知,Service 连接成功了                 eventHandler.sendEvent(EVENT_ABILITY_CONNECT_DONE);                 //初始化代理                 remoteAgentProxy = new SharePasteAgentProxy(iRemoteObject);                 HiLog.debug(LABEL, "%{ public}s", "remoteAgentProxy:" + remoteAgentProxy);             }             @Override             public void onAbilityDisconnectDone(ElementName elementName, int resultCode) {                  //发个通知,Service 断开连接了,主动断开不会执行,关闭服务端会执行                 eventHandler.sendEvent(EVENT_ABILITY_DISCONNECT_DONE);             }         });     } } /**  * 获取远端粘贴板服务中心  *  * @param bundleName  * @param serviceName  * @return  */ private Intent getRemoteServiceIntent(String bundleName, String serviceName, String deviceId) {      HiLog.debug(LABEL, "%{ public}s", "getRemoteServiceIntent");     Operation operation = new Intent.OperationBuilder()             .withDeviceId(deviceId)             .withBundleName(bundleName)             .withAbilityName(serviceName)             //重要             .withFlags(Intent.FLAG_ABILITYSLICE_MULTI_DEVICE)             .build();     Intent intent = new Intent();     intent.setOperation(operation);     return intent; } /**  * 获取本地粘贴板服务中心  *  * @param bundleName  * @param serviceName  * @return  */ private Intent getLocalServiceIntent(String bundleName, String serviceName) {      HiLog.debug(LABEL, "%{ public}s", "getLocalServiceIntent");     Operation operation = new Intent.OperationBuilder().withDeviceId("")             .withBundleName(bundleName)             .withAbilityName(serviceName)             .build();     Intent intent = new Intent();     intent.setOperation(operation);     return intent; } 

同步数据到服务端

/**  * 同步粘贴板记录到粘贴板服务中心  *  * @param component  */ private void syncData(Component component) {      HiLog.debug(LABEL, "sync_text:" + sync_text);     if (!sync_text.isEmpty()) {          if (isConnect && remoteAgentProxy != null) {              //调用服务端IPC方法             try {                  remoteAgentProxy.setSystemPaste(sync_text);                 //更换文本                 syncText.setText(getRandomText());                 sync_text = "";                 showTips(this, "同步成功");             } catch (RemoteException remoteException) {                  remoteException.printStackTrace();             }         } else {              showTips(this, "正在连接设备");         }     } else {          showTips(this, "点击复制到粘贴板");     } } 

随机生成粘贴文本

/**  * 随机文本,模拟数据  *  * @return  */ public String getRandomText() {      List<String> list = Arrays.asList(             "快马加鞭未下鞍,离天三尺三",             "我自横刀向天笑,去留肝胆两昆仑",             "飞流直下三千尺,疑是银河落九天",             "君子求诸己,小人求诸人",             "吾日三省吾身:为人谋而不忠乎?与朋友交而不信乎?传不习乎?");     int random = new SecureRandom().nextInt(list.size());     return list.get(random); } 

服务端(paste)ServiceAbility.java

设置粘贴板服务

idl文件放在ohos.samples.pasteboard.paste目录下,Gradl窗口,执行compileDebugIdl 后,系统生成代理对象,idl提供了setSystemPaste接口供远端调用。

interface ohos.samples.pasteboard.paste.ISharePasteAgent {      /*      * 设置系统粘贴板      */     void setSystemPaste([in] String param); }  //idl的服务端实现, SharePasteAgentStub sharePasteAgentStub = new SharePasteAgentStub(DESCRIPTOR) {      @Override     public void setSystemPaste(String param) {          HiLog.info(LABEL, "%{ public}s", "param:" + param);         //插入数据库         ItemChild itemChild = new ItemChild();         String currentTime = DateUtils.getCurrentDate("yyMMdd HH:mm:ss");         itemChild.setWriteTime(currentTime);         itemChild.setWriteContent(param);         itemChild.setIndex(String.valueOf(UUID.randomUUID()));         //默认添加到未分类         itemChild.setTagName(Const.CATEGORY_TAG_UNCATEGOORIZED);         //添加粘贴板记录到分布式数据库         kvManagerUtils.addItemChild(itemChild);     } }; @Override protected IRemoteObject onConnect(Intent intent) {      HiLog.info(LABEL, "%{ public}s", "ServiceAbility onConnect");     return sharePasteAgentStub; } **初始化数据库** ```java //初始化数据库工具 kvManagerUtils = KvManagerUtils.getInstance(this); //初始化数据库管理对象 kvManagerUtils.initDbManager(eventHandler); //初始化数据库数据按钮 Image initDb = (Image) findComponentById(ResourceTable.Id_init_db); initDb.setClickedListener(component -> {      //默认选中“未定义”标签     current_select_category_index = 0;     //初始化数据库数据     kvManagerUtils.initDbData();     showTip("初始化完成"); }); 

初始化数据列表

/**  * 从分布式数据库中查询数据  */ public void queryData() {      HiLog.debug(LABEL, "queryData");     try {          //加载选中类别下的数据列表         initItemChild(kvManagerUtils.queryDataByTag(CategoryData.tagList.get(current_select_category_index)));     } catch (KvStoreException exception) {          HiLog.info(LABEL, "the value must be String");     } } /**  * 初始化选中标签的子项列表  *  * @param itemChildList itemChildList, the bean of itemChild  */ private void initItemChild(List<ItemChild> itemChildList) {      HiLog.debug(LABEL, "initItemChild:" + itemChildList);     if (itemChildList == null) {          return;     }     //清空组件     itemChildLayout.removeAllComponents();     // Create itemChild     for (ItemChild itemChild : itemChildList) {          //获取子项类别所在的组件         Component childComponent =                 LayoutScatter.getInstance(this).parse(ResourceTable.Layout_paste_record_per, null, false);         //写入时间         Text writeTime = (Text) childComponent.findComponentById(ResourceTable.Id_writeTime);         writeTime.setText(itemChild.getWriteTime());         //粘贴板内容         Text writeContent = (Text) childComponent.findComponentById(ResourceTable.Id_writeContent);         writeContent.setText(itemChild.getWriteContent());         //复制按钮         Text copy = (Text) childComponent.findComponentById(ResourceTable.Id_itemChildPerCopy);         //复制按钮的监听事件         copy.setClickedListener(component -> {              //复制内容到粘贴板             pasteboard.setPasteData(PasteData.creatPlainTextData(itemChild.getWriteContent()));             showTip("已复制到粘贴板");         });         //收藏按钮         Text favorite = (Text) childComponent.findComponentById(ResourceTable.Id_itemChildPerFavorite);         //收藏按钮的监听事件         favorite.setClickedListener(component -> {              //修改标签微已收藏             itemChild.setTagName(Const.CATEGORY_TAG_FAVORITED);             //保存数据             kvManagerUtils.addItemChild(itemChild);             showTip("已加入到收藏中");         });         /

分享到:

滇ICP备2023006006号-16