uni-app中uni.canvasToTempFilePath方法在iOS app移动端报错

发布于 1周前 作者 yuanlaile 来自 Uni-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.",安卓手机端可以正常传图片

12 回复

我使用下面 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>

调试步骤与注意事项

  1. 检查canvasId:确保canvas-iduni.canvasToTempFilePath中的canvasId完全一致。

  2. 绘制时机:在调用uni.canvasToTempFilePath之前,确保画布已经绘制完成。可以通过监听draw回调或使用setTimeout来确保绘制完成。

  3. 权限问题:iOS对于文件系统访问有严格限制,确保应用有写入临时文件的权限。虽然uni-app通常处理这些权限,但在某些情况下可能需要手动检查或请求权限。

  4. 错误处理:详细检查fail回调中的错误信息,这可能会给出具体的失败原因,如内存不足、文件路径错误等。

  5. 日志输出:增加更多的日志输出,可以帮助定位问题发生的具体位置。

  6. 版本兼容性:检查uni-app和iOS SDK的版本兼容性,确保使用的API在当前版本中受支持。

如果以上步骤仍然无法解决问题,建议查看uni-app的官方文档或社区论坛,看看是否有其他开发者遇到并解决了类似的问题。同时,也可以考虑向uni-app的开发者团队报告此问题。

回到顶部