【HarmonyOS 7】鸿蒙应用开发如何屏蔽剪切板
最近应用组在开发一个金融类应用,产品提了个需求:输入框不能粘贴,复制的内容也不能带到别的应用里。刚开始开发觉得挺简单,不就是屏蔽剪贴板嘛,结果一上手发现坑还挺多。
屏蔽剪切板这个说法其实挺笼统的,实际开发中会遇到好几种不同的场景。我帮忙看了下,把踩了一圈坑,常见的几种情况整理了一下。
屏蔽剪贴板这个需求说简单也简单,说复杂也复杂,关键是要搞清楚具体是哪种场景:
- 禁止输入框粘贴 → 用 onPaste + event.preventDefault()
- 限制复制范围 → 用 copyOption属性
- Web 组件控制复制 → Web 组件的 copyOptions属性
- 运行时拦截 → 监听剪贴板变化事件
实际开发中,这几个方案可能需要组合使用。比如我们做的金融应用,输入框禁止粘贴、复制内容限制在应用内,同时监听剪贴板变化防止敏感数据泄露,三管齐下才把需求搞定。
一、输入框禁止粘贴
这个需求最常见,比如密码输入框、验证码输入框,都不想让用户直接粘贴进去。
HarmonyOS 里 TextInput、TextArea、RichEditor 这些输入组件都提供了 onPaste 回调,在里面调用 event.preventDefault() 就能阻止默认粘贴行为。
arkts
@Entry
@Component
struct DisablePasteDemo {
build() {
Column({ space: 20 }) {
// 禁止粘贴的输入框
TextInput({ placeholder: '此输入框禁止粘贴' })
.width('90%')
.onPaste((value: string, event: PasteEvent) => {
if (event !== undefined && event.preventDefault) {
event.preventDefault()
}
})
// 正常输入框(对比)
TextInput({ placeholder: '正常输入框,可粘贴' })
.width('90%')
}
.width('100%')
.height('100%')
.justifyContent(FlexAlign.Center)
}
}
这里有个坑需要注意:onPaste 的 event.preventDefault() 只能阻止系统层面的粘贴,但挡不住输入法自带的剪贴板功能。有些输入法会自己维护一个剪贴板历史,用户从输入法的剪贴板面板里粘贴,onPaste 根本收不到事件。如果要完全屏蔽,只能让用户手动关闭输入法的剪贴板功能,或者换个输入法。
二、限制复制范围
有些场景下,复制是允许的,但不能把内容复制到应用外面。比如我们做的这个金融应用,用户可以复制一些内部信息,但不能把这些信息粘贴到微信、备忘录这些外部应用里。
copyOption 属性就是干这个的,它有三个级别:
| 取值 | 说明 |
|---|---|
| CopyOptions.None | 完全禁止复制,连文本都选不了 |
| CopyOptions.InApp | 只能应用内复制粘贴,复制的内容到外面用不了 |
| CopyOptions.LocalDevice | 设备内随便复制粘贴(默认值) |
arkts
@Entry
@Component
struct CopyOptionDemo {
build() {
Column({ space: 20 }) {
// 完全禁止复制
TextInput({ placeholder: '完全禁止复制' })
.width('90%')
.copyOption(CopyOptions.None)
// 仅支持应用内复制
TextInput({ placeholder: '仅应用内可粘贴' })
.width('90%')
.copyOption(CopyOptions.InApp)
// 默认:设备内可复制粘贴
TextInput({ placeholder: '设备内可复制粘贴' })
.width('90%')
.copyOption(CopyOptions.LocalDevice)
}
.width('100%')
.height('100%')
.justifyContent(FlexAlign.Center)
}
}
设置成 CopyOptions.InApp 后,在这个输入框里复制的内容,到了应用外面(比如备忘录)就粘贴不了了。这个功能在金融、医疗这些对数据安全要求高的场景里特别有用。
三、Web 组件屏蔽复制
如果应用里嵌了 H5 页面,也要控制复制行为的话,Web 组件也提供了 copyOptions 属性:
arkts
import { webview } from '@kit.ArkWeb';
@Entry
@Component
struct WebCopyOptionDemo {
controller: webview.WebviewController = new webview.WebviewController();
build() {
Column() {
Web({ src: 'https://example.com', controller: this.controller })
.copyOptions(CopyOptions.None)
.width('100%')
.height('100%')
}
}
}
CopyOptions.None在框架层直接屏蔽了文本选择能力,比 CSS 的 user-select: none更安全,JS 也绕不过去。
四、运行时拦截剪贴板
有些场景需要在运行时动态拦截剪贴板数据,比如用户复制了敏感信息后,应用需要检测到并清除。这个可以通过监听剪贴板变化事件来实现:
arkts
import { pasteboard } from '@kit.BasicServicesKit';
const systemPasteboard = pasteboard.getSystemPasteboard();
const listener: pasteboard.PasteboardChangedListener = {
onPasteboardChanged: () => {
if (systemPasteboard.hasDataSync()) {
const data = systemPasteboard.getDataSync();
const text = data.getPrimaryText();
// 判断是否为敏感数据,如果是则清除
if (isSensitiveData(text)) {
systemPasteboard.clearData();
}
}
}
};
systemPasteboard.on('update', listener);
这里有几个点要注意:
权限问题:从 API 12 开始,读取系统剪贴板需要申请 ohos.permission.READ_PASTEBOARD权限,而且这是个受限权限,得发邮件申请。但写入剪贴板不需要权限,如果只是要清除数据,不用申请读取权限。
安全控件:系统提供了 PasteButton粘贴安全控件,用户点击就视为临时授权,应用不用申请读取权限就能访问剪贴板内容。这个控件在需要用户主动触发粘贴的场景里很好用。
隐私合规:如果应用有读取剪贴板的行为,隐私政策里必须说明收集个人信息的目的、方式、范围,不然应用审核会被驳回。