Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

React router path "/" doesn't work correctly on Cordova Android? #2161

Closed
ubill opened this issue Oct 4, 2015 · 20 comments
Closed

React router path "/" doesn't work correctly on Cordova Android? #2161

ubill opened this issue Oct 4, 2015 · 20 comments

Comments

@ubill
Copy link

ubill commented Oct 4, 2015

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?

@anri-asaturov
Copy link

@ubill Have you tried crosswalk? cordova plugin add cordova-plugin-crosswalk-webview
Works for me on android and is faster than conventional webview.

@knowbody
Copy link
Contributor

knowbody commented Oct 6, 2015

I would highly recommend using the most recent stable version (v1.0.0-rc1) we fixed bunch of bugs.

Also as you are trying to use React Router with Cordova and also with Redux, have a look at this react-cordova-boilerplate.

@knowbody knowbody closed this as completed Oct 6, 2015
@ubill
Copy link
Author

ubill commented Oct 6, 2015

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!

@knowbody
Copy link
Contributor

knowbody commented Oct 6, 2015

great, thanks @ubill

@rclai
Copy link

rclai commented Oct 27, 2015

@ubill is there a reason why HashHistory works on Cordova? I've been using createBrowserHistory on Cordova with no problems. It's only when I was searching for a solution to the back button did I stumble on this thread.

@ubill
Copy link
Author

ubill commented Oct 31, 2015

@rclai I don't know of any reason. I was just sharing the finding that for my specific case HashHistory works, but the other scheme used by default by router (BrowserHistory) didn't work for me. - I'm not sure if it works for other people and I am the only one facing a problem. But if it doesn't work, only possibility I could think of:

  • the webview (or version of) specifically on my device somehow just doesn't support it

@wmertens
Copy link
Contributor

wmertens commented Dec 1, 2015

hashHistory works because it doesn't change the base URL from which assets are loaded, and also perhaps react-router bugs with file://

@pke
Copy link

pke commented Dec 9, 2015

@rclai So you have used createBrowserHistory and did run into any problems?

@rclai
Copy link

rclai commented Dec 9, 2015

Yeah it worked for me on an android phone

@pke
Copy link

pke commented Dec 9, 2015

I am getting

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

@ryanflorence
Copy link
Member

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

@pke
Copy link

pke commented Dec 10, 2015

I wonder why it works for @rclai then, Ryan? Also, why does it need a server? It does not fetch any content from a server, does it? Isn't it just rewriting the browsers location object but not actually handling any navigation? I mean, that's the idea of SPA, isn't it?

@wmertens
Copy link
Contributor

wmertens commented Dec 10, 2015

You can also simply set in head, but that doesn't work with file urls.

@mkristo
Copy link

mkristo commented Apr 28, 2016

I was able to get non-hash routing to work on Cordova (iOS and Android) by doing this ugly hack:

let history = useRouterHistory(createHistory)({baseName: document.location.href.replace('file://', '')})

@mbrevda
Copy link

mbrevda commented Sep 9, 2016

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

@evanshortiss
Copy link

@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
Copy link

mkristo commented Dec 25, 2016

@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.

@evanshortiss
Copy link

@mkristo, thanks! Will need to try this out - went down the hash history route which is working for now but would rather do what you've done to keep Cordova consistent 👍

@hutber
Copy link

hutber commented May 31, 2017

@evanshortiss where did you get isCordova() from :O?

@OlMrGreen
Copy link

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!

@lock lock bot locked as resolved and limited conversation to collaborators Jan 28, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests