Loading Local Assets in WebView in Flutter

Sha Qian
Flutter Community
Published in
3 min readFeb 22, 2019

The Flutter WebView plugin is in preview and at the moment it only loads URIs. It’d be nice if we can load local html (along with Javascript and CSS) files from local assets.

I made minimal changes to the plugin to provide a way to load asset files and have submitted a pull request: https://github.com/flutter/plugins/pull/1247

In case the pull request got rejected, you can refer to the File changed to patch your copy of webview package.

Patching WebView plugin

Allow me to briefly explain what the pull request does to patch the webview plugin.

iOS:

The plugin uses the WKWebView class in native code. It calls the loadRequest method to invoke a request to the URI passed in from Flutter.

The WKWebView class provides another method loadFileURL that can load a file URL. The definition is:

- (WKNavigation *)loadFileURL:(NSURL *)URL 
allowingReadAccessToURL:(NSURL *)readAccessURL;

In order to use this method, we need to know the URL of our asset file. We can find some hints in the Flutter online doc Sharing assets with the underlying platform. The example returns a path but we can use another method URLForResource to get the URL.

NSString* key = [registrar lookupKeyForAsset:@"icons/heart.png"];
NSString* path = [[NSBundle mainBundle] pathForResource:key ofType:nil];

With the current implementation, the FLTWebViewController and FLTWebViewFactory class in webview plugin don’t have access to registrar, so I changed their initWithMessenger method to initWithRegistrar. Now we have the answer to loading asset file in iOS webview:

NSString* key = [_registrar lookupKeyForAsset:url];
NSURL* nsUrl = [[NSBundle mainBundle] URLForResource:key withExtension:nil];
[_webView loadFileURL:nsUrl allowingReadAccessToURL:[NSURL URLWithString:@"file:///"]];

Android:

The webview plugin uses the WebView class on Android side and it calls the loadUrl method. This method already supports asset file URL in the following format:

file:///android_asset/{RELATIVE-PATH}

My first attempt was using “file:///android_asset/{MY-FOLDER}/{MY-FILE}.html” but it failed with File Not Found error.

I did some research and it turns out Flutter stores the user defined assets in a flutter_assets directory. So the answer to loading assets in Android webview is:

webView.loadUrl("file:///android_asset/flutter_assets/" + url);

Prepare the html and js file

To verify the functionality of the patched package, I decided to test if the webview can render a Three.js scene.

The html below is slightly altered from the sample code in the Three.js introduction. It generates a white cube with rotating animation.

We also need a copy of three.js: https://threejs.org/build/three.js

Then create a assets folder in the root of the Flutter project and place three.html and three.js in it. Finally in pubspec.yaml, add:

assets:
- assets/three.js
- assets/threejs.html

Create the WebView

The dart code below creates the WebView and renders the local assets/three.html file.

Inject Javascript code

The WebViewController class has an evaluateJavascript method. Using this method we can inject Javascript code to the webview.

The code in this example sets a random Hex color value to the material of the cube object defined in three.html.

The result

Here’s the demonstration of the example. A rotating cube is rendered in the scene and every time I tap the refresh button, the cube changes its color.

Thank you for reading till the end. :)

--

--