react-native-webview: Cannot load additional resources for HTML page loaded from local on-demand resource
Bug description:
I’m attempting to load a local website which has been downloaded as an on-demand resource bundle. On the native side I load the bundle, then pass the path of the index file back to React Native, which is then used by a RN Webview to load it. The index file loads successfully, but additional resources loaded by that page are being blocked with this error being thrown in the Javascript console:
Failed to load resource: The operation couldn’t be completed. Operation not permitted
The current WebView tag looks like this:
<WebView javaScriptEnabled={true} webkit={false} source={{ uri: indexURI }} style={{ flex: 1 }} allowFileAccess={true} originWhitelist={['*']} />
The index file I am loading is extremely simple, just the required HTML and body tags and an image tag with ‘./test.png’ as the source
Am I missing a property in the WebView that would allow these assets to be loaded?
Expected behavior: HTML files should be loaded along with all of the resources that it attempts to load
Environment:
- OS: iOS
- OS version: 12.4.4
- react-native version: 0.59.9
- react-native-webview version: 8.0.5
About this issue
- Original URL
- State: closed
- Created 4 years ago
- Reactions: 1
- Comments: 24 (4 by maintainers)
Loading local content with
source={ uri: <uri> }does work. It was fixed in #771. You need to setallowingReadAccessToURL={'file://'+<path_to_resource_folder>}.What’s still a problem, is loading local content if you import a html string into a webview via
source={ html: <html_string>, baseUrl: <path_to_resource_folder> }. In this case, settingallowingReadAccessToURLhas no effect, as the underlying WKWebView doesn’t support that paramater paired with loading HTML from a string. This problem does not show up on a simulator, or if<path_to_resource_folder>points to the apps bundle folder.This seems to be a deeper issue with WKWebView itself (https://bugs.webkit.org/show_bug.cgi?id=154916) and I am not sure how this library is supposed to fix this.
But working around the problem can be achieved in a couple of ways:
fs.writeFile(<path_to_temp_file>, <html>, 'utf8');) and then usingsource={ uri: <path_to_temp_file> }andallowingReadAccessToURL={<path_to_resource_folder>}(tested this, it works).you’re still using the local webserver, i can’t help you with that.
otherwise, you already seem to have your html as a file. all you should need to do is get rid of the local webserver and set
allowingReadAccessToURL={<path_to_folder_containing_html_file>}.@ekkis I always advise to profile any solution using either xcode or flipper. It also depends on the kind of devices your target audience use etc.
Should you find that you need to optimize (but again profile first, then optimize), then there are a few things you can do.
Once you have all your files loaded into WebView cache, you no longer need the server. There is an exception to this and that is if your HTML5 code sends ajax requests back to the domain that it originated from (that would be your server). If you are issuing requests to other domains using CORS then you should still be ok.
If you find that your HTML5 codebase is issuing ajax requests back to your server, then you could possibly modify your codebase to instead issue postMessage() events and have the react-native side catch those events and issue the requests on behalf of your HTML5 code. That will still allow you to terminate the server once you receive the DOMContentLoaded event.
Should you find that you absolutely cannot stop the server for any reason in an early fashion as described above, then I suggest trying to suspend the server when your app is in the background and restart it when it’s brought back to the foreground and then profile again. You can easily do that either by handling the associated react-native events or by enabling the
GCDWebServerOption_AutomaticallySuspendInBackgroundoption on GCDWebServer.Regarding appSize you can take leverage of Apple’s “On Demand Resources” feature and offload your bundle to Apple’s OnDemand servers. This solution is available since iOS9 and works very well. (https://developer.apple.com/videos/play/wwdc2015/214/)
But in all terms n purposes I can’t really tell you how expensive the overall solution will be. That is a factor of what your requirements are, what devices and OS versions you are targeting, how long your users spend on the WebView and how smart you can be working around any issues. A POC using the embedded server should be very quick to setup with barebone functionality. I suggest you do that and profile, profile, profile.
@flashman2 Hi, there’s a workaround you can try. Load your index.html file as you do now but also spawn an embedded static server to serve all the static assets being requested by the webview through that static server.
You can have a look at the “react-native-static-server” plugin that uses GCDWebServer on iOS to serve static assets. Leveraging the GCDWebServer is actually easy enough to even write your own native module around it, should the react-native-static-server does not fulfil all your needs. (in most cases it will though).