Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get access to phonegap API from a remote page

I have to following situation: I have a already existing remote webpage and i want to develope an app which uses this page. So far, so good. When I start the app the local index.html is loaded and it redirects (window.open target: _self) to the external website. This website is opened in the phonegap webview. On the external website I added the cordova.js in order to get access to the native phonegap API. But it doesn't work correctly. The deviceReady event is triggered correctly, but I have no access to the phonegap API, for example navigator.camera.

How can I get it done, to get access to the API?

Please do not comment that it will be rejected by AppStore etc. etc.

Thank you for your help!

like image 573
riedelinho Avatar asked Feb 24 '14 10:02

riedelinho


2 Answers

Well, for me the solution was a mixture of several sources, but most of the solution was found here.

What you should do is the following:

  1. Define your config.xml to point directly to the remote index.html.

    <content src="http://your-remote-location/index.html" /> 
  2. In your index.html any reference to a local android device resource prepend with some unique prefix like **injection**. For instance for cordova.js you'll come up with something like:

    <script type="text/javascript" src="**injection**www/cordova.js"></script> 
  3. Find SystemWebViewClient.java under the following location: your-project-location\platforms\android\CordovaLib\src\org\apache\cordova\engine.

  4. Add the following enum declaration in the private members section of the class at the top:

    private enum WebExtension {     PNG, MP3, MP4, TTF, SVG, JS, ICO, HTML, CSS, EOT, WOFF, JSON; } 
  5. Locate the shouldInterceptRequest method and add the following right after the try { line:

    if(url != null && url.contains(INJECTION_TOKEN)) {     String assetPath = url.substring(url.indexOf(INJECTION_TOKEN) + INJECTION_TOKEN.length(), url.length());     try {         String mimeType = "text/plain";          String ext = assetPath.substring(assetPath.lastIndexOf(".") + 1, assetPath.length());         WebExtension extension = WebExtension.valueOf(ext.toUpperCase());          switch(extension) {             case PNG:                 mimeType = "image/png";                 break;             case MP3:                 mimeType = "audio/mpeg";                 break;             case MP4:                 mimeType = "video/mp4";                 break;             case TTF:                 mimeType = "application/x-font-ttf";                 break;             case SVG:                 mimeType = "image/svg+xml";                 break;             case JS:                 mimeType = "application/javascript";                 break;             case ICO:                 mimeType = "image/x-icon";                 break;             case HTML:                 mimeType = "text/html";                 break;             case CSS:                 mimeType = "text/css";                 break;             case EOT:                 mimeType = "application/vnd.ms-fontobject";                 break;             case WOFF:                 mimeType = "application/x-font-woff";                 break;             case JSON:                 mimeType = "application/json";                 break;         }          WebResourceResponse response = new WebResourceResponse(             mimeType,             "UTF-8",             parentEngine.webView.getContext().getAssets().open(assetPath)         );         return response;     } catch (IOException e) {         e.printStackTrace(); // Failed to load asset file     } } 

The result of all of it will be interception of every resource request and in case it will contain the **injection** string in it, it will cut down the resource location and will request it from local device location under which the application is running. The mimeType is necessary to load the resource in the correct manner by the app browser.

Hope it helps someone.

like image 116
Lentyai Avatar answered Oct 14 '22 02:10

Lentyai


Including the cordova.js script in the remote site is going to be tricky, because there's a different cordova.js for each platform. You could modify the server so that it returns the correct cordova.js based on the user agent, but this is also tricky because it will include this script when you view the site from a mobile browser, and this is undesirable because javascript errors might be shown to the user. Same story when viewing the site from a desktop computer, the cordova.js should not be included.

It looks to me that you have a local web page (with the cordova script included) and from there you change to the remote page (that also includes the script). I'm not sure this page change is going to work. If it worked, you might have to wait for the second deviceready event.

But you can just set the remote site page as the root page in the cordova app, no need for an intermediate "loader" page. Just set it in the config.xml file:

<content src="http://your.website.fake/index.html" /> 

You need to make sure that you allow loading your site in the app. In this same file, you should add:

<access origin="http://your.website.fake" subdomains="true"/>  
like image 43
Mister Smith Avatar answered Oct 14 '22 03:10

Mister Smith