react-router: React router path "/" doesn't work correctly on Cordova Android?

Hello, I am using react-router, and generate a bundle.js file with webpack,

my dependencies are:

    "react": "^0.13.3",
    "react-redux": "^2.0.0",
    "redux": "^2.0.0",
    "redux-thunk": "^0.1.0",
    "react-router": "1.0.0-beta3",

then I use the bundle.js in a script tag in my cordova app:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <title>ReaktMob</title>
    <meta name="description" content="React-Redux-Cordova app">
    <meta name="viewport" content="user-scalable=no, initial-scale=1, minimal-ui, maximum-scale=1, minimum-scale=1" />
    <link href="./assets/lib/ionic/css/ionic.css" rel="stylesheet">
    <!-- <link href="css/site.css" rel="stylesheet"> -->
  </head>
  <body>
    <div id="root"></div>
    <script src="./lib/moment.min.js"></script>
    <script src="./lib/CordovaPromiseFS.js"></script>
    <script src="./static/bundle.js"></script>
  </body>
</html>

my bundle.js is created with this file: (index.js)

import { Provider } from 'react-redux';
import { Router, Route } from 'react-router';
import BrowserHistory from 'react-router/lib/BrowserHistory';

const history = new BrowserHistory();
React.render(
  // child must be wrapped in a function
  // workaround for issue in React 0.13.
  <Provider store={store}>
    {() =>
      <Router history={history}>
        <Route path="/" component={MainContainer} />
      </Router>
    }
  </Provider>,

  document.getElementById('root')
);

But when I run it on my phone (cordova run android) The path = “/” always seems to resolve to “/android_asset/www/index.html” and my app won’t work on phone because of this.

Warning: Location "/android_asset/www/index.html" did not match any routes

The router behaves correctly when I am developing on my browser, though: (in fact the below is my full code that works on the browser, I stripped it down to narrow down the root cause on my phone)

  <Provider store={store}>
    {() =>
      <Router history={history}>
        <Route component={MainContainer}>
          <Route path="/" component={App} />
          <Route path="/:itemuuid" component={AppTemp} />
        </Route>
      </Router>
    }
  </Provider>

What do I do in this case to get my app to behave correctly on-device? Am I using the react-router API correctly or is there something else I don’t know about?

About this issue

  • Original URL
  • State: closed
  • Created 9 years ago
  • Comments: 20 (5 by maintainers)

Most upvoted comments

Thank you all for your suggestions. I have confirmed the solution and would like to share it here.

If you are using desktop browser e.g. Chrome, you can use BrowserHistory.

const history = new BrowserHistory();

However if you are using Cordova, you have to use HashHistory:

const history = new HashHistory();

The URLs you get will no doubt be different for each implementation, but only the latter works on Cordova.

@anri-asaturov Many thanks for the suggestion! I have not started using CrossWalk yet (will do so) but if it works I suspect it’s due to CrossWalk supporting ‘pushState’ history, same as modern desktop browsers.

@knowbody Now I confirmed it’s not a problem with the version I’m using but with the router’s History implementation used. Hope it helps other users and thanks for your suggestion!

Cheers all!

browser history assumes you have a server. Cordova apps run w/o a server, so you need hash history.

@evanshortiss: The code has evolved a little since I wrote the snippet above.

let baseName = document.location.pathname.split('index.html')[0] + 'index.html';

I have a vague memory that the code change was to handle deep linking.

Using older versions, react-router 2.3.0 and history 2.0.1.

Thank you all for your suggestions. I have confirmed the solution and would like to share it here.

If you are using desktop browser e.g. Chrome, you can use BrowserHistory.

const history = new BrowserHistory();

However if you are using Cordova, you have to use HashHistory:

const history = new HashHistory();

The URLs you get will no doubt be different for each implementation, but only the latter works on Cordova.

@anri-asaturov Many thanks for the suggestion! I have not started using CrossWalk yet (will do so) but if it works I suspect it’s due to CrossWalk supporting ‘pushState’ history, same as modern desktop browsers.

@knowbody Now I confirmed it’s not a problem with the version I’m using but with the router’s History implementation used. Hope it helps other users and thanks for your suggestion!

Cheers all!

Works great for me; thanks!

@mbrevda @mkristo might be a little late, but I’m trying this now like so but having no luck on Cordova with:

import { Router, browserHistory, useRouterHistory, Redirect } from 'react-router'
import { createHistory } from 'history';

let historyEngine = browserHistory;

if (isCordova()) {
  historyEngine = useRouterHistory(createHistory)({
    basename: document.location.href.replace('file://', '')
  });
}

I end up with the follwing in an iOS Simulator file:///login - Failed to load resource: The requested URL was not found on this server.

I’ve only started using react-router recently so not much insight without reading into the code, but it appears that this solution has an error in the replace logic Perhaps something to do with versions of history and react-router etc. I’d imaging the path should be file:///APP_CONTAINER/TYPICAL_IOS_URL_STUFF/index.html/login

Using history@2.1.2 and react-router@2.6.0

@mkristo would you kindly post a snippet showing your solution, including the require/import statements? Thanks!

great, thanks @ubill