iOS中WKWebView加载HTML/JS实现canvas绘图,需通过evaluateJavaScript注入JS驱动已定义的绘图函数,导出时用toDataURL获取base64再转UIImage,并注意同源、devicePixelRatio适配及页面加载完成时机。

iOS 本身不直接“调用” HTML5 绘图,而是通过 WKWebView 加载并运行 HTML/JS 代码,在 Web 环境中完成绘图;原生 Swift/Objective-C 无法绕过 Web 容器直接操作 canvas 上下文。
WKWebView 中加载含 canvas 的 HTML 页面
这是最基础也最常用的路径:把绘图逻辑写在 HTML + JS 里,让 WKWebView 渲染执行。
- 确保 HTML 文件包含合法的
和初始化 JS(如getContext('2d')) - 使用
loadFileURL(_:allowingReadAccessTo:)加载本地 HTML,避免跨域限制;不要用loadHTMLString(_:baseURL:)加载含相对路径资源(如图片)的页面,否则 canvas 图片可能空白 - 若需动态传参(比如画一条线的坐标),可用
evaluateJavaScript(_:completionHandler:)向已加载页面注入 JS 执行绘图命令
从 Swift 向 canvas 传递数据并触发绘图
原生层不能直接调用 canvas.getContext(),但可通过 JS 注入方式驱动已有 canvas 实例。
- 先在 HTML 中定义好全局绘图函数,例如:
window.drawPoint = function(x, y) { ctx.fillRect(x, y, 2, 2); }; - 在 Swift 中调用:
webView.evaluateJavaScript("drawPoint(100, 200)") { _, _ in } - 注意 JS 函数必须在页面加载完成(
webView(_:didFinishNavigation:)回调后)再调用,否则报错TypeError: undefined is not an object - 大量连续绘图(如手势轨迹)建议批量拼接 JS 字符串或使用
postMessage配合message事件,避免频繁 evaluate 带来的延迟
导出 canvas 内容为 UIImage
用户常误以为能直接从 WKWebView 取 canvas 的像素数据,实际只能通过 JS 拿到 data URL,再由原生侧转换。
立即学习“前端免费学习笔记(深入)”;
- JS 端调用:
canvas.toDataURL('image/png')(注意:仅支持 PNG/JPEG,且 canvas 未跨域) - Swift 端用
evaluateJavaScript获取该字符串,再用Data(base64Encoded:)解码为UIImage - 若 canvas 绘制了本地图片资源,务必确保该图片是同源(同 bundle 或已通过
allowingReadAccessTo:授权),否则toDataURL()返回空字符串 - 高分辨率屏(@2x/@3x)下 canvas 的
width/height属性默认是 CSS 像素,需手动设置canvas.width = canvas.clientWidth * window.devicePixelRatio等适配,否则导出图模糊
替代方案:纯原生绘图更可控
如果核心需求是“在 iOS 上动态绘图”,而非必须用 HTML5 canvas 标准,Core Graphics 或 SwiftUI Path 是更稳定、高性能的选择。
-
UIGraphicsImageRenderer可生成任意精度的UIImage,无 WebView 启动开销和 JS 调用延迟 - 需要与网页交互(如 H5 活动页嵌套绘图组件)才值得走 WKWebView + canvas 路线
- WKWebView 的 canvas 性能受 JS 引擎限制,复杂动画易掉帧;而
CALayer或SKView更适合实时渲染场景
canvas 在 iOS 上始终运行于 WebKit 的 JSContext 中,所有操作都绕不开页面生命周期、同源策略和 devicePixelRatio 适配——这些不是“调用接口”的问题,而是环境约束。真正卡住的往往不是语法,而是 base64 编码失败、devicePixelRatio 忘设、或 evaluateJavaScript 过早触发。










