4

I've been developing* with Cordova (aka Phonegap) for Android for well over a year now and am trying to make my apps available to run in Jelly Bean, but I am getting the following error:

XMLHttpRequest cannot load http://127.0.0.1:40582/[somerandomstring]. Origin null is not allowed by Access-Control-Allow-Origin. at null:1

(and similar errors for any subsequent ajax requesting use of localhost or file://) Just to test, I grant access to everything in the config.xml in the section for Access-Control-Allow-Origin

<access origin="*"/>
<access origin="http://127.0.0.1*"/>

In my research I have discovered the error is related to a setting change that Google made as of Android Jelly Bean. Here is what I found: From: https://git-wip-us.apache.org/repos/asf?p=incubator-cordova-android.git;a=commitdiff;h=07439ff9

-- This is from org.apache.cordova.CordovaWebView

// Jellybean rightfully tried to lock this down. Too bad they didn't give us a whitelist
// while we do this
if (android.os.Build.VERSION.SDK_INT > android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1)
    Level16Apis.enableUniversalAccess(settings);

-- This is also from org.apache.cordova.CordovaWebView

// Wrapping these functions in their own class prevents warnings in adb like:
// VFY: unable to resolve virtual method 285: Landroid/webkit/WebSettings;.setAllowUniversalAccessFromFileURLs
@TargetApi(16)
private static class Level16Apis {
    static void enableUniversalAccess(WebSettings settings) {
         settings.setAllowUniversalAccessFromFileURLs(true);
     }
}

It's nice that Cordova tried to work around the change, but unfortunately this does not work...

In these SO threads here and here I found a common solution, to simply change a setting as follows:

if(android.os.Build.VERSION.SDK_INT > android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) {
    super.appView.getSettings().setAllowUniversalAccessFromFileURLs(true);    
}

Now I get the following warning:

Call requires API level 16 (current min is 8) 
android.webkit.WebSettings#setAllowUniversalAccessFromFileURLs

Here is what I have for the api in my AndroidManifest.xml

<uses-sdk android:minSdkVersion="8" android:targetSdkVersion="16" />

Why is it requiring me to change the minSdkVersion to 16 rather than follow my targetSdkVersion which is 16?

Thoughts?

Notes: I'm currently using Cordova 2.0, Eclipse Indigo SR2 (all updates current), Android SDK (all updates current), on Windows 7 Home (all updates current), Java 7 Update 7.

Community
  • 1
  • 1
mason81
  • 1,730
  • 2
  • 18
  • 33
  • What is the target SDK version in your manifest? – Simon MacDonald Sep 13 '12 at 19:50
  • I think I figured it out. It's not ideal, but at least it works. Thanks for offering your assistance. – mason81 Sep 13 '12 at 19:58
  • 1
    Can you give me a reproduction scenario? I know you worked around it but we don't want this bug in the framework. – Simon MacDonald Sep 14 '12 at 02:29
  • Download Phonegap/Cordova 2.0 from phonegap.com, extract the zip. Copy the "example" project from the lib/Android/ directory to your Eclipse Workspace directory. In Eclipse, got to File->New->Other then in the wizard expand Android and select "Android Project from Existing Code", hit next, browse to the example project, click "Finish". Edit "AndroidManifest.xml" in text editor, add android:targetSdkVersion="16" to the uses-sdk tag. Edit "project.properties" and change the target api to 16. Create AVD running API 16. Run project as app in that AVD. Check logcat to see XMLHttpRequest errors... – mason81 Sep 14 '12 at 13:29
  • The example app still appears to load, but is not fully functional. Also, if you add in any Phonegap/Cordova calls to read/write assets to the app it will fail with the same XMLHttpRequest error as mentioned in the OP above. If you want to see some specific examples I would be happy to email them to you or share them via some other method. – mason81 Sep 14 '12 at 13:33
  • Also, changing the access-origin in the config.xml does not help solve the problem, only setting the "setAllowUniversalAccessFromFileURLs" to true seems to help. I realize this was attempted in org.apache.cordova.CordovaWebView.java, but it doesn't seem to work as intended and I'm not sure why. – mason81 Sep 14 '12 at 13:35
  • For more context, my app loads index.html which includes cordova-2.0.0.js and runs some javascript when onDeviceReady fires which will connect to our server and compare javascript and css assets to see if there are updates available. If there are it will download and save the assets to the app. Once complete the app then loads all necessary assets and displays the welcome screen/page which is now functional... With the bug I mentioned in the OP, it hangs when attempting to check for updates -- due to the XMLHttpRequest error also mentioned in the OP – mason81 Sep 14 '12 at 13:43
  • Thanks for looking into this @SimonMacDonald I appreciate your hard work and dedication to the Phonegap/Cordova project. – mason81 Sep 14 '12 at 13:44
  • Thanks for all the comments. Why don't you just email me a index.html that reproduces the problem so I can take a look. I'm at simon[dot]macdonald[at]gmail[dot]com – Simon MacDonald Sep 14 '12 at 17:03

1 Answers1

13

OK so after a ton of searching, guessing, and checking, I found a workable solution.

I had to create a separate function for the setAllowUniversalAccessFromFileURLs call... That fixed the TargetApi issue but then presented a different one on JellyBean where it wouldn't connect to the file I had in my loadURL call so I had to override the onReceivedError function. Here is my resulting code:

package com.MyUniqueDomain.MyUniquePackage;

import android.annotation.TargetApi;
import android.os.Bundle;
import org.apache.cordova.*;

public class MainActivity extends DroidGap {

    private int retryCount = 0;

    @Override
    public void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);
        super.setStringProperty("loadingDialog", "Please wait -- loading...");
        super.init();
        if(android.os.Build.VERSION.SDK_INT > android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) {
            fixJellyBeanIssues();
        }
        super.loadUrl("file:///android_asset/www/index.html");
    }

    @TargetApi(16)
    protected void fixJellyBeanIssues() {
        System.out.println(super.appView.toString());
        try {
            super.appView.getSettings().setAllowUniversalAccessFromFileURLs(true);
        } catch(NullPointerException e) {
            System.out.println(e.toString());
        }
    }

    // catch an error and if try again 1x or quit
    @Override
    public void onReceivedError( int errorCode, String description, String failingUrl)
    {
        if(retryCount < 3) {
            retryCount++;
            System.out.println("Connection failed, trying again. Retry Count: "+retryCount);
            super.loadUrl("file:///android_asset/www/index.html");
        } else {
            System.out.println("Sorry, it failed three times so I give up.");
            super.loadUrl("file:///android_asset/www/fail.html");
        }
        return;
    }
}
mason81
  • 1,730
  • 2
  • 18
  • 33