app端水印必须使用原生插件实现,webview层的css或canvas方案无法覆盖状态栏、导航栏及软键盘区域,且截图录屏时必然丢失;推荐watermark-plus插件并配合服务端签名文本。

App端水印必须走原生插件,WebView层无效
在 App 端(iOS/Android),position: fixed 或 Canvas 绘制的水印只能盖住 WebView 内容区,完全无法覆盖状态栏、导航栏、软键盘弹出区域,截图/录屏时也必然丢失。这不是兼容性问题,而是图层隔离的硬限制:WebView 是子视图,真正顶层是 UIWindow(iOS)或 DecorView(Android)。所以任何 JS/CSS 方案在 App 端都只是“假水印”。
推荐用 watermark-plus 插件 + 服务端签名文本
社区较稳定的方案是 watermark-plus,它封装了双端原生绘制逻辑,调用简单但需注意关键约束:
-
text必须是字符串字面量或运行时拼接后传入,不能传响应式变量引用(原生侧不监听 JS 变量变化) -
alpha建议设为0.10–0.15,低于0.08在强光屏下基本不可见,高于0.2会干扰阅读 - Android 全面屏/刘海屏下若水印偏移,大概率是插件未调用
plus.screen.getRealSize()获取真实像素尺寸 - iOS 截图时 WebView 层水印被剥离是正常现象;真防截屏必须依赖原生层绘制,且需监听
plus.screen.onorientationchange重绘
动态修改水印内容要避开生命周期陷阱
水印一旦由原生插件绘制到窗口顶层,就不会随 Vue 页面卸载自动清除。动态修改必须主动调用更新接口,并确保时机正确:
- 登录成功后、首页
onLoad中立即调用setWatermark,避免白屏期无覆盖 - 用户切换账号或登出时,必须显式调用
clearWatermark(如果插件支持)或用空字符串重置:setWatermark({ text: '' }) - tab 切换或页面跳转时,
onHide不触发原生水印关闭,需在全局 store / pinia 中统一管理状态,并在路由守卫中同步调用 - 服务端返回的
text字段应含签名,如"张三_20260619_xxxhash";前端只透传,校验逻辑必须在原生插件内完成,否则 hook 替换参数即可绕过
Android 水印错位和 iOS 截图失效是常态,不是 bug
这些不是代码写错了,而是平台限制导致的必然表现:
- Android 上
screenWidth/screenHeight返回的是虚拟尺寸(含状态栏/导航栏),必须用plus.screen.getRealSize()获取物理像素再计算水印坐标 - iOS 截图 API(如
UIGraphicsImageRenderer)默认只捕获当前UIView层级,原生水印画在UIWindow顶层时,系统截图工具仍可能漏掉——这是苹果设计使然,无法靠前端修复 - 横竖屏切换、软键盘弹出都会触发视图重排,原生插件若没监听
plus.screen.onorientationchange和uni.onKeyboardHeightChanged,水印立刻错位或被遮挡











