I'm trying to build a cross platform app with Cordova and React. However I'm having a hard time getting the app to consistently find images from www
whose paths are defined in JSX.
Setup
<meta http-equiv="Content-Security-Policy"
content="default-src 'self' data: gap: https://ssl.gstatic.com 'unsafe-eval'; style-src 'self' 'unsafe-inline' 'unsafe-eval' https://fonts.googleapis.com file: data: content; media-src *; img-src * 'self' 'unsafe-inline' 'unsafe-eval' file: data: content:; connect-src https://example.com 'self' ws:; font-src https://fonts.googleapis.com https://fonts.gstatic.com 'self'">
Don't worry, I'll restrict this once I have the app working.Investigation thus far
index.html
as <img src="static/media/my_image.becd5aba.jpg"/>
then the image loads fine./
in JSX to create a relative path, it doesn't load.static/media/my_image.becd5aba.jpg
in JSX, it doesn't load.Inspecting these two elements using the Safari inspector for my iOS sim gives the following paths
Image that displays from index.html:
static/media/my_image.becd5aba.jpg
file:///Users/anthonymanning-franklin/Library/Developer/CoreSimulator/Devices/SOME-BIG-PATH-STUFF/data/Containers/Bundle/Application/MORE-PATH-GUFF/MyApp.app/www/static/media/my_image.becd5aba.jpg
Image that doesn't display:
static/media/my_image.becd5aba.jpg
file:///static/media/my_image.becd5aba.jpg
Potential solutions
Does Cordova run a webserver or am I literally browsing the filesystem in the webview? It looks like the issue is to do with relative paths not resolving correctly in the file system context, so it looks at file:///static
instead of file://path/to/application/static/
.
I've tried the following
import myImage from './../../assets/my_image.jpg'
let cordova = window.cordova;
...
<img src={`${cordova.file.applicationDirectory}${myImage}`}/>
But I get a React error
Attempted to update component
V
that has already been unmounted (or failed to mount).
I guess I need some sort of effective way of referencing the full path in Javascript at run time.
Similar issues
Any ideas?
Turns out solution #2 was on the right track.
cordova.file.applicationDirectory
gives me the right path to the app root but it required the following steps:
cordova plugin add cordova-plugin-file
<script type="text/javascript" src="cordova.js"></script>
in index.html
Ensure your React code begins after deviceready
. In my case I set index.js
to the following:
import React from 'react';
import ReactDOM from 'react-dom';
import './css/index.css';
import App from './App';
import registerServiceWorker from './registerServiceWorker';
document.addEventListener('deviceready', () => {
ReactDOM.render(<App />, document.getElementById('root'));
registerServiceWorker();
}, false);
Then created a cordova_globals.js file as such:
let FILE_PATH = '';
document.addEventListener('deviceready', () => {
FILE_PATH = `${window.cordova.file.applicationDirectory}www`;
}, false);
export {FILE_PATH};
Now in my JSX I can reference local images as such:
import {FILE_PATH} from 'cordova_globals.js'
<img src={`${FILE_PATH}${myImage}`}/>