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.
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;
}
}