iOS无法用uni.canvasToTempFilePath导出canvas内容,因默认禁用像素读取权限,须设type="2d"或用createOffscreenCanvas;保存失败多因路径格式错误,iOS需file://且编码中文,Android常需去除file://前缀;海报模糊因未按pixelRatio放大canvas物理尺寸。

uni-app 里用 canvas 生成二维码再保存到相册,为什么 iOS 拍不出来?
App 端(尤其 iOS)无法直接用 uni.canvasToTempFilePath 导出 canvas 内容,是因为 iOS 的 canvas 在非 webview 环境下默认不启用像素读取权限——哪怕你画完了,toTempFilePath 返回的仍是空路径或报错 fail canvas is empty。
- 必须在
canvas创建时显式设置type="2d",且不能依赖 H5 的自动 fallback - iOS App 需调用原生插件桥接,纯 JS + canvas 不行;Android 虽部分支持,但不同厂商 WebView 行为不一致
- 推荐绕过 canvas:用已验证的原生能力插件,比如
uni-plugin-qrcode或uni-app-qr,它们内部封装了 iOS/Android 原生二维码绘制逻辑 - 若坚持手写,iOS 必须用
uni.createOffscreenCanvas()(仅 3.7.10+ 支持),且需配合getContext('2d')后立即调用drawImage等操作,否则依然为空
uni-app 海报合成中,文字换行、图片裁剪、字体大小适配怎么不翻车?
海报里最常崩的是文字:ctx.fillText 不自动换行,ctx.setFontSize 在不同端单位不统一,iOS 上自定义字体(如 .ttf)还可能加载失败导致回退成系统默认字体,字号看起来小一圈。
- 文字换行必须自己切分:按字数 or 按宽度测距(
ctx.measureText),逐行fillText,别指望wrapText这种不存在的方法 - 字号统一用
px,但要在manifest.json里关掉 “启用屏幕旋转” 和 “使用系统字体”,否则 iOS 会强制缩放 - 图片裁剪用
ctx.drawImage(img, sx, sy, sw, sh, dx, dy, dw, dh),注意sx/sy是源图坐标,不是 canvas 坐标;Android 上若图源是本地路径(uni.getFileSystemManager().readFile得到的 base64),要先转成uni.getImageInfo才能传给 canvas - 所有图片资源优先用网络地址(CDN)或
static目录下的相对路径,避免使用uni.chooseImage返回的临时路径,App 端可能读不到
uni.saveImageToPhotosAlbum 报错 errCode: -1 怎么快速定位?
这个错误不是权限问题,而是文件路径根本无效。App 端对路径格式极其敏感:iOS 只认 file:// 开头的本地沙盒路径,Android 则接受 data:、file://、甚至部分 http://(但不推荐)。
- 生成的临时文件路径必须来自
uni.canvasToTempFilePath或uni.downloadFile成功回调里的tempFilePath,不能自己拼字符串 - 如果用了原生插件生成二维码,它返回的路径大概率是
file://格式,但 Android 部分机型要求去掉开头的file://才能保存,得用正则.replace(/^file:\/\//, '')兜底 - iOS 上如果路径带中文或特殊符号(如空格、括号),
saveImageToPhotosAlbum会静默失败,务必用encodeURIComponent编码路径后再传入 - 真机调试时打开
uni.showLoading+console.log打印路径全貌,比看错误码更管用
海报合成后尺寸模糊、发虚,是不是 dpi 没设对?
不是 dpi 问题,是 canvas 画布的物理像素和 CSS 像素没对齐。uni-app 默认创建的 canvas 是 300×300 CSS 像素,但实际渲染分辨率可能是 2x 或 3x 屏幕,导致绘制内容被拉伸模糊。
- 创建 canvas 时必须手动设置宽高属性:
<canvas canvas-id="myCanvas" style="width: 750px; height: 1334px;"></canvas>,同时在 JS 里用query.select获取节点,再调用node.width = 750 * pixelRatio、node.height = 1334 * pixelRatio -
pixelRatio从uni.getSystemInfoSync().pixelRatio拿,iOS 通常是 2 或 3,Android 多为 2.75 或 3 - 后续所有绘图坐标、尺寸都要按这个放大后的 canvas 尺寸计算,比如想画一个 100px 宽的文字块,在 3x 屏上就得传
100 * 3 - 最后导出前,记得把
canvasToTempFilePath的quality设为1(最高),否则默认 0.8 会二次压缩
事情说清了就结束。真正卡住你的,往往不是“怎么做”,而是 iOS 上那个看不见的 canvas 权限、Android 上路径开头多出来的 file://、还有 canvas 物理尺寸和逻辑尺寸之间那层薄薄的换算。


















