第8章_HarmonyOs开发图解 剪贴板

100 阅读5分钟

第8章 HarmonyOs开发图解 剪贴板

HarmonyOS 学习系统 | 阶段二:进阶实战期 建议学习时长:1 周


学习目标

序号能力
1掌握 SystemPasteboard 和 PasteData 的使用方法
2能实现文本复制、粘贴和剪贴板监听功能
3理解剪贴板的权限限制和大小限制

内容讲解

8.1 剪贴板 API

社区大门口有一块便签板(系统剪贴板)。你在便签板上贴了一张写着"张三 电话 138xxxx"的便签。不管你是谁(哪个应用),只要走到便签板前(应用获得前台焦点),就能看到最新的便签内容。新的便签会覆盖旧的,便签板上的内容不会因为你离开就消失。

HarmonyOS 的 SystemPasteboard 提供了系统剪贴板操作接口,PasteData 是剪贴板数据的载体。

获取剪贴板对象
// 获取系统剪贴板实例
SystemPasteboard pasteboard = SystemPasteboard.getSystemPasteboard(this);
写入剪贴板
// 创建纯文本数据
PasteData pasteData = PasteData.createPlainTextData("Hello HarmonyOS!");
// 写入剪贴板
pasteboard.setPasteData(pasteData);

PasteData 支持多种数据类型:

创建方法数据类型说明
createPlainTextData()纯文本最常用的类型
createHtmlData()HTML 文本保留富文本格式
createUriData()URI 数据传递链接或文件路径
createIntentData()Intent 数据传递 Intent 对象
createMimeData()MIME 类型自定义 MIME 类型数据
读取剪贴板
// 检查剪贴板是否有数据
if (pasteboard.hasPasteData()) {
    // 获取剪贴板数据
    PasteData data = pasteboard.getPasteData();
    // 获取主文本
    String text = data.getPrimaryText();
    // 获取 HTML 文本
    String html = data.getPrimaryHtml();
    // 获取 URI
    Uri uri = data.getPrimaryUri();
    // 使用数据...
}
清除剪贴板
// 清除剪贴板内容
pasteboard.clearPasteData();

8.2 剪贴板变化监听

SystemPasteboard 支持监听剪贴板内容变化:

// 添加监听器
pasteboard.addPasteDataChangedListener(new IPasteDataChangedListener() {
    @Override
    public void onChanged() {
        HiLog.info(TAG, "剪贴板内容发生了变化");
        // 获取最新内容
        if (pasteboard.hasPasteData()) {
            String newText = pasteboard.getPasteData().getPrimaryText();
            HiLog.info(TAG, "新内容: " + newText);
        }
    }
});

// 移除监听器
pasteboard.removePasteDataChangedListener(listener);

8.3 实战要点

剪贴板的权限限制

只有前台获得焦点的应用才有读取剪贴板的权限(系统默认输入法除外)。这意味着后台服务无法直接读取剪贴板内容。

剪贴板的大小限制

剪贴板单次传递内容不能超过 500KB。如果需要传递大数据量,应使用文件或分布式数据管理来实现。

剪贴板的覆盖机制

每次调用 setPasteData() 都会覆盖之前的剪贴板内容。系统剪贴板是全局唯一的,所有应用共享同一个剪贴板。

8.4 综合实战:剪贴板工具页面

下面是一个完整的剪贴板工具页面实现,包含复制、粘贴和监听功能:

public class ClipboardSlice extends AbilitySlice {
    private static final HiLogLabel TAG = new HiLogLabel(0, 0, "ClipboardSlice");
    private SystemPasteboard pasteboard;
    private Text tvPasteContent;

    @Override
    public void onStart(Intent intent) {
        super.onStart(intent);
        super.setUIContent(ResourceTable.Layout_ability_clipboard);

        pasteboard = SystemPasteboard.getSystemPasteboard(this);
        tvPasteContent = (Text) findComponentById(ResourceTable.Id_tv_paste_content);

        Button btnCopy = (Button) findComponentById(ResourceTable.Id_btn_copy);
        Button btnPaste = (Button) findComponentById(ResourceTable.Id_btn_paste);
        Button btnClear = (Button) findComponentById(ResourceTable.Id_btn_clear);

        // 复制按钮
        btnCopy.setClickedListener(component -> {
            TextField tfInput = (TextField) findComponentById(
                ResourceTable.Id_tf_input);
            String text = tfInput.getText();
            if (!text.isEmpty()) {
                PasteData data = PasteData.createPlainTextData(text);
                pasteboard.setPasteData(data);
                new ToastDialog(getContext())
                    .setText("已复制到剪贴板")
                    .show();
            }
        });

        // 粘贴按钮
        btnPaste.setClickedListener(component -> {
            if (pasteboard.hasPasteData()) {
                PasteData data = pasteboard.getPasteData();
                String text = (data.getPrimaryText() != null)
                    ? data.getPrimaryText().toString() : "无文本内容";
                tvPasteContent.setText("剪贴板内容: " + text);
            } else {
                tvPasteContent.setText("剪贴板为空");
            }
        });

        // 清除按钮
        btnClear.setClickedListener(component -> {
            pasteboard.clearPasteData();
            tvPasteContent.setText("剪贴板已清除");
        });

        // 添加剪贴板变化监听
        pasteboard.addPasteDataChangedListener(() -> {
            getUITaskDispatcher().asyncDispatch(() -> {
                if (pasteboard.hasPasteData()) {
                    PasteData data = pasteboard.getPasteData();
                    String newText = (data.getPrimaryText() != null)
                        ? data.getPrimaryText().toString() : "非文本";
                    tvPasteContent.setText("监听到变化: " + newText);
                }
            });
        });
    }

    @Override
    public void onStop() {
        // 移除监听,防止内存泄漏
        pasteboard.removePasteDataChangedListener(null);
        super.onStop();
    }
}

8.5 剪贴板安全注意事项

  • 敏感数据:不要将密码、Token 等敏感信息写入剪贴板,任何前台应用都可以读取
  • 及时清除:使用完剪贴板后,建议调用 clearPasteData() 清除内容
  • 监听器泄漏:在 onStop() 或 onDestroy() 中务必移除监听器
  • 线程安全:剪贴板变化监听回调在非 UI 线程,更新 UI 需要通过 getUITaskDispatcher()

代码速查卡

API功能示例
SystemPasteboard.getSystemPasteboard()获取剪贴板实例SystemPasteboard.getSystemPasteboard(this)
PasteData.createPlainTextData()创建纯文本数据PasteData.createPlainTextData("text")
setPasteData()写入剪贴板pasteboard.setPasteData(pasteData)
getPasteData()读取剪贴板PasteData data = pasteboard.getPasteData()
hasPasteData()检查是否有数据pasteboard.hasPasteData()
clearPasteData()清除剪贴板pasteboard.clearPasteData()
addPasteDataChangedListener()添加变化监听pasteboard.addPasteDataChangedListener(listener)
removePasteDataChangedListener()移除变化监听pasteboard.removePasteDataChangedListener(listener)

与 Android/iOS 对比

特性HarmonyOSAndroidiOS
剪贴板管理类SystemPasteboardClipboardManagerUIPasteboard.general
数据类型文本/HTML/URI/Intent文本/URI/Intent文本/URL/图像/颜色
大小限制500KB无硬性限制无硬性限制
读取权限前台聚焦应用所有应用前台应用
变化监听addPasteDataChangedListeneraddPrimaryClipChangedListener无原生支持
创建数据PasteDataClipDataUIPasteboard 数据

⚠️ 踩坑回忆录

做剪贴板功能时踩了一个大坑:我写了一个后台服务定时读取剪贴板内容,结果发现怎么都读不到。后来才知道:只有前台获得焦点的应用才有读取剪贴板的权限(系统默认输入法除外)。另外,剪贴板单次传递内容不能超过 500KB,大数据量还是得用文件或分布式数据管理。

还有一个容易忽略的问题:SystemPasteboard.getSystemPasteboard(this) 中的 this 参数是 Context,如果你在非 UI 组件中调用(比如工具类),需要传入正确的 Context,否则会返回一个无效的剪贴板实例。


必做实操任务

序号任务难度
1实现一个"复制文本到剪贴板"的按钮功能★☆☆
2实现从剪贴板读取文本并显示的粘贴功能★☆☆
3添加剪贴板变化监听器,实时显示剪贴板内容变化★★☆
4尝试写入不同类型的数据(文本、HTML、URI)并分别读取★★☆
5实现一个简易的剪贴板管理工具,显示剪贴板历史记录★★★

学习检查清单

  • 能说出 SystemPasteboard 和 PasteData 的关系
  • 能实现文本的复制和粘贴
  • 理解剪贴板的权限限制
  • 知道剪贴板的大小限制(500KB)
  • 能实现剪贴板变化监听
  • 了解 PasteData 支持的数据类型
  • 知道什么时候应该清除剪贴板

进阶方向

  • 实现剪贴板与分布式数据管理结合的跨设备剪贴板
  • 了解系统输入法对剪贴板的特殊权限
  • 学习在 Service 中无法读取剪贴板的替代方案