tags: Flutter
、Bug
[Debug] Flutter Image.network() 在 Web 下,圖片會載入失敗
問題
使用 Image.network()
,會跑出下面的錯誤訊息,而且只在 web 下才會出現,在 iOS/Android 圖片都會順利顯示。
══╡ EXCEPTION CAUGHT BY IMAGE RESOURCE SERVICE ╞════════════════════════════════════════════════════
The following ImageCodecException was thrown resolving an image codec:
Failed to load network image.
Image URL: https:…
Trying to load an image from another domain? Find answers at:
https://flutter.dev/docs/development/platform-integration/web-images
When the exception was thrown, this was the stack
Image provider: NetworkImage(“https://…”, scale:1)
Image key: NetworkImage(“https://…”, scale: 1)
原因
主要原因應該是 CORS 問題,它可能會受到所使用的 web renderer 影響,解決方向主要有三個:
- 直接解決根本的 CORS 問題,需要請後端協助修改 headers 相關設定
- 使用代理服務器: 設置一個代理服務器來轉發 client 請求
- 方向就是修改 web renderer 設定
以下解法基本是圍繞的第三個方向去解的。
當 --web-renderer=auto
(預設值),會根據使用者的裝置,自動選擇最適合的 renderer,在 desktop browser 下,預設使用的就是 CanvasKit,需要指定成 html
,才能解決。
💡 Flutter 在 Web 平台上的渲染引擎設定,有三種可選擇:
html
:使用瀏覽器原生的 HTML、CSS、JavaScript 來渲染應用程式,支援最廣泛但效能較差。canvaskit
:使用 Skia Graphics Engine 將 Flutter 畫面轉換成 Canvas 元素,相較於 html 有較好的效能,但相容性較差。auto
:根據瀏覽器的支援度自動選擇渲染引擎,預設為 canvaskit,但若瀏覽器支援度足夠高則會自動切換為 html。
解決方法
方法一:修改 Flutter 設定檔(一勞永逸)
找到 web 資料夾底下的 index.html
檔案,在 initializeEngine 設定中加入renderer:'html'
,之後不論是用 VS code debugging 或者終端機下 flutter run --debug -d chrome
,都可以順利看到圖片了。
// index.html
<!DOCTYPE html>
<html>
<head> ... </head>
<body>
<script>
window.addEventListener('load', function(ev) {
_flutter.loader.loadEntrypoint({
serviceWorker: {
serviceWorkerVersion: serviceWorkerVersion,
},
onEntrypointLoaded: function(engineInitializer) {
engineInitializer.initializeEngine({
renderer:'html' // 這邊指定 renderer
}).then(function(appRunner) {
appRunner.runApp();
});
}
});
});
</script>
</body>
</html>
方法二:passing flag (適合慣用 Terminal debugging 的人)
將指令後面多加 --web-renderer html
,缺點是每次都要打這段
$flutter run -d chrome --web-renderer html
方法三:修改 VS code 設定檔 (適合慣用 VS code debugging 的人)
因為是針對 VS code 設定,所以缺點也很明顯,將來如果不是透過 VS code run debugging (e.g. 透過 Terminal),圖片依舊會跑不出來;優點則是只要設定一次即可,而且可以依據需求,選擇要 by 專案或者是 by User 去做設置。
下面兩種作法擇一即可,效果一樣:
-
直接新增設定檔
在專案底下,新增 .vscode
資料夾和 settings.json
檔案,檔案內容為:
{
"dart.flutterWebRenderer": "html"
}
-
透過 GUI
從左下齒輪,找到 Settings
,然後搜尋 flutter renderer
,將原本 Dart: Flutter Web Renderer
由預設的 auto
改為 html
。
參考資料
- Image.network() doesn’t show some images on the web but works on android.
- [web]: NetworkImage crash while loading images
- Add a setting to easily set Flutter’s web renderer in user/workspace settings
- Capture from onError ImageCodecException
- Web renderers
- Flutter web can’t load network image from another domain