uni-app中uni.canvasToTempFilePath方法在iOS app移动端报错
uni-app中uni.canvasToTempFilePath方法在iOS app移动端报错
开发环境 | 版本号 | 项目创建方式 |
---|---|---|
Windows | 10企业版 | HBuilderX |
产品分类:uniapp/App
PC开发环境操作系统:Windows
HBuilderX类型:正式
HBuilderX版本号:4.29
手机系统:iOS
手机系统版本号:iOS 16
手机厂商:苹果
手机机型:8plus
页面类型:vue
vue版本:vue2
打包方式:云端
操作步骤:
canvasId: 'watermarkCanvas',
success: (res) => {
console.log("res",res);
resolve(res.tempFilePath);
},
fail: (err) => {
console.log("err11",err);
reject(err);
}
});
预期结果:
在 ios app端返回图片临时路径
实际结果:
报错 "errMsg": "canvasToTempFilePath:fail SecurityError: The operation is insecure."
bug描述:
hbuilderx 4.29最新版本,uni.canvasToTempFilePath方法在ios app移动端报错 "errMsg": "canvasToTempFilePath:fail SecurityError: The operation is insecure.",安卓手机端可以正常传图片
我使用下面 demo 运行到 vue2 + ios 真机、模拟器上未报错
<template>
<view>
<view>canvas to temp file path</view>
<canvas style="width: 300px; height: 200px;border: 1px solid red;" id="myCanvas" canvas-id="myCanvas"></canvas>
<button @click='generateImage'>generate file</button>
</view>
</template>
<script>
export default {
data() {
return {
}
},
methods: {
drawCanvas() {
var ctx = uni.createCanvasContext('myCanvas')
// begin path
ctx.rect(10, 10, 100, 30)
ctx.setFillStyle('yellow')
ctx.fill()
// begin another path
ctx.beginPath()
ctx.rect(10, 40, 100, 30)
// only fill this rect, not in current path
ctx.setFillStyle('blue')
ctx.fillRect(10, 70, 100, 30)
ctx.rect(10, 100, 100, 30)
// it will fill current path
ctx.setFillStyle('red')
ctx.fill()
ctx.draw(true, () => {
this.generateImage()
})
},
generateImage() {
uni.canvasToTempFilePath({
x: 100,
y: 200,
width: 50,
height: 50,
destWidth: 100,
destHeight: 100,
canvasId: 'myCanvas',
success: (res)=> {
// 在H5平台下,tempFilePath 为 base64
console.log(res)
},
fail(res) {
console.log('error', res)
}
})
}
},
onReady() {
this.drawCanvas()
}
}
</script>
<style>
</style>找到问题是ctx.drawImage()引起的,注掉就返回路径了,但是需要用到这个方法怎么办啊
回复 h***@126.com: 像我一样提供你到基础代码,说明你是怎么写的,是引入三方图片画布被污染吗
回复 DCloud_UNI_OttoJi:我的写法是下面那条
addWatermark(data) {
return new Promise((resolve, reject) => {
uni.getImageInfo({
src: data.url,
success: (info) => {
console.log(‘info’, info);
setTimeout(() => {
console.log('info.width, info.height', info.width, info.height);
const ctx = uni.createCanvasContext('watermarkCanvas');
ctx.beginPath()
ctx.drawImage(info.path, 0, 0, info.width, info.height);
ctx.width = info.width / 2;
ctx.height = info.height / 2;
// 设置水印 文本换行
const breakTextLines = (markDept, maxWidth) => {
const words = markDept.split('');
let line = '';
const lines = [];
for (let i = 0; i < words.length; i++) {
const word = words[i];
const testLine = line + word;
const metrics = ctx.measureText(testLine);
if (metrics.width > maxWidth && i > 0) {
lines.push(line);
line = word;
} else {
line = testLine;
}
}
lines.push(line);
return lines;
};
if (data.markShow) {
// 设置水印样式
ctx.setFontSize(20); // 设置字体大小
ctx.setFillStyle('white'); // 设置水印颜色
ctx.setGlobalAlpha(0.7); // 设置水印透明度
// 动态添加水印
let yPosition = 100;
data.listItem.forEach((item,index) => {
// 只有当 status 为 true 时才绘制水印
if (item.status !== false) {
if(index == 1){//定位的水印
ctx.fillText(item.key, 30, yPosition); // 设置水印位置
yPosition += 20;
const lines = breakTextLines(item.value, 200);
const linesLength = lines.length;
lines.forEach((line, index) => {
ctx.fillText(line, 30, (index * 20 + yPosition))
})
yPosition += 100; // 为下一组水印留出空间
}else{
ctx.fillText(item.key, 30, yPosition);
yPosition += 20;
ctx.fillText(item.value, 30, yPosition);
yPosition += 40; // 为下一组水印留出空间
}
}
});
}
ctx.fill()
console.log("aaaaaaaaaaaaaaaaaaaa",ctx);
ctx.draw(true, () => {
// this.generateImage()
uni.canvasToTempFilePath({
canvasId: 'watermarkCanvas',
success: (res) => {
console.log("res",res);
resolve(res.tempFilePath);
},
fail: (err) => {
console.log("err11",err);
reject(err);
}
});
});
},300)
},
fail: (err) => {
console.log("err",err);
reject(err);
}
});
});
},
ios app 用this.livePusher.snapshot 拍照后 uni.getImageInfo返回的info
{
“height”: 384,
“orientation”: “up”,
“path”: “file:///var/mobile/Containers/Data/Application/139421CD-C332-4D5D-8C19-6D5BEEE4FBFC/Documents/Pandora/apps/EC2B81D49F96C6F0B82075DFEA627006/doc/uniapp_temp_1729761123932/compressed/1729761218126_2024-10-24%2017:13:38.jpg”,
“type”: “jpeg”,
“width”: 288,
“errMsg”: “getImageInfo:ok”
}
这个方法中去掉 ctx.drawImage, ios app就能正常生成本地文件路径
加个这个试下const ctx = uni.createCanvasContext(‘watermarkCanvas’, this);
回复 蔡cai: 加了后还是报错,“errMsg”: “canvasToTempFilePath:fail SecurityError: The operation is insecure.”
回复 h***@126.com: 没报过这个错,要不你降下hbuilderx版本或者升级版本看看
回复 蔡cai: 这个就是刚从低版升到最新版的
回复 h***@126.com: 这个报错,在 ask 社区搜一下,比如 https://ask.dcloud.net.cn/article/41016
可以使用uni.saveFile将图片保存到本地,然后使用保存后的图片地址。就可以l
在处理uni-app中uni.canvasToTempFilePath
方法在iOS移动端报错的问题时,首先需要确保代码本身没有逻辑错误,并且遵循了uni-app的API规范。以下是一个简单的代码示例,演示如何在uni-app中使用uni.canvasToTempFilePath
方法,并附带一些可能的调试步骤和注意事项,帮助定位问题。
代码示例
<template>
<view>
<canvas canvas-id="myCanvas" style="width: 300px; height: 200px;"></canvas>
<button @click="saveCanvas">保存画布到临时文件</button>
</view>
</template>
<script>
export default {
methods: {
drawCanvas() {
const ctx = uni.createCanvasContext('myCanvas');
ctx.setFillStyle('red');
ctx.fillRect(10, 10, 150, 75);
ctx.draw();
},
saveCanvas() {
uni.canvasToTempFilePath({
canvasId: 'myCanvas',
success: (res) => {
console.log('临时文件路径:', res.tempFilePath);
// 可以进一步处理文件路径,如上传等
},
fail: (err) => {
console.error('保存画布失败:', err);
}
}, this);
}
},
onReady() {
this.drawCanvas();
}
}
</script>
<style>
/* 样式可以根据需要调整 */
</style>
调试步骤与注意事项
-
检查canvasId:确保
canvas-id
与uni.canvasToTempFilePath
中的canvasId
完全一致。 -
绘制时机:在调用
uni.canvasToTempFilePath
之前,确保画布已经绘制完成。可以通过监听draw
回调或使用setTimeout
来确保绘制完成。 -
权限问题:iOS对于文件系统访问有严格限制,确保应用有写入临时文件的权限。虽然uni-app通常处理这些权限,但在某些情况下可能需要手动检查或请求权限。
-
错误处理:详细检查
fail
回调中的错误信息,这可能会给出具体的失败原因,如内存不足、文件路径错误等。 -
日志输出:增加更多的日志输出,可以帮助定位问题发生的具体位置。
-
版本兼容性:检查uni-app和iOS SDK的版本兼容性,确保使用的API在当前版本中受支持。
如果以上步骤仍然无法解决问题,建议查看uni-app的官方文档或社区论坛,看看是否有其他开发者遇到并解决了类似的问题。同时,也可以考虑向uni-app的开发者团队报告此问题。