3

I've got a PhoneGap app that's working fine on iOS but when setup for a release build, does not work on Android.

I'm using the Phonegap CLI to create my application.

$ phonegap --version
4.2.0-0.24.2

The config.xml options for network access and whitelisting have been set:

<access origin="*" />
<feature name="http://api.phonegap.com/1.0/network" />

I've verified that my AndroidManifest.xml is requesting internet permission:

<uses-permission android:name="android.permission.INTERNET" />

My API returns the appropriate ACCESS-CONTROL-ALLOW-ORIGIN header value:

Access-Control-Allow-Origin: *

For good measure I've also added this to my JS:

$.support.cors = true;

If I set the android remote debugging attribute so that I can connect from chrome://inspect, then the network requests succeed and all is right with the world:

<application android:debuggable="true" ... >

However, if I simply remove that android:debuggable="true" so that I can submit to the play store, recompile, and test again, then my cross-domain ajax requests fail. When they fail, they're returning with jqXHR.status=0 and jqXHR.readyState=0, which in my experience indicates that the pre-flight OPTIONS request has failed for some reason.

Unfortunately, when I've enabled debugging and I connect to view the network requests, everything works -- so I can't see what might be wrong. I've restored to alert()-ing various things to try and figure out what's going on... but I'm not getting any further.

I can also run my application in a browser on my laptop using a file:// url (which is how it's opened in an Android app) as well as running it via a local webserver (at localhost:3030), and in both cases the cross-domain requests work completely fine.

I'm at a loss for what to do now. Is there something else I can alert to get more information about the error? (Maybe it's other headers causing the issue?)

Adam Tuttle
  • 19,505
  • 17
  • 80
  • 113

3 Answers3

1

I believe I've found the issue: Android doesn't like one of my intermediate SSL certificates. This is consistent with the behavior that I've noted:

  • works fine on iOS
  • works fine in Chrome on laptop (file:// and localhost)
  • works fine when using http://
  • apparent CORS pre-flight request failure (statusCode=0, status=0) when using https://

For now, I'll just be using non-SSL access to my api so I can move forward, and I'll let the server admin know there's something wrong with SSL ~ probably an intermediate cert that Android doesn't trust.

Adam Tuttle
  • 19,505
  • 17
  • 80
  • 113
1

Yeah, it's definitely a certificate problem.

If you want to ignore the certificate error and continue loading you can do this:

yourCordovaWebView.setWebViewClient(new WebViewClient(){

    @Override
    public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {

        handler.proceed();

    }

});

But doing that you remove all the security and become vulnerable to man in the middle attacks

You can inspect the SslError to see the real problem

jcesarmobile
  • 51,328
  • 11
  • 132
  • 176
  • I'm curious why enabling android debugging works around this issue. Does it affect the way that network requests are routed (through the internet connection of the debugging computer, perhaps)? Or does it simply ignore all SSL errors as you've outlined, to support debugging those SSL requests? – Adam Tuttle Apr 16 '15 at 13:02
  • 1
    Yes, debuggable=true allows self-signed and bad certificates – jcesarmobile Apr 16 '15 at 14:20
  • It's on the cordova code, see this related question http://stackoverflow.com/questions/8977226/phonegap-ajax-call-to-https-server-with-self-signed-certificate-fails – jcesarmobile Apr 16 '15 at 14:22
1

I had the same issue i.e. it works fine from desktop browser or android browser but does not work from phonegap app. It turns out that phonegap app is more strict about the certificate chain which you MUST set correctly in your webserver.

I use node.js for the webserver. So the correct way to set it should be:

sslOptions = {
    key: fs.readFileSync('/CertificateFolder/privkey.pem'),
    cert: fs.readFileSync('/CertificateFolder/cert.pem'),
    ca: fs.readFileSync('/CertificateFolder/chain.pem')
},
https = require('https').Server(sslOptions, app)

The key element here is "chain.pem" which if not added, the website will still work in web browser but not in phonegap app.

Fan Gong
  • 191
  • 1
  • 3