Phonegap/Cordova App breaks in Jelly Bean - Access-Control-Allow-Origin and setAllowUniversalAccessFromFileURLs
我已经与Android的Cordova(aka Phonegap)合作开发*一年多了,并试图使我的应用程序可以在Jelly Bean中运行,但是出现以下错误:
1 | XMLHttpRequest cannot load http://127.0.0.1:40582/[somerandomstring]. Origin null is not allowed by Access-Control-Allow-Origin. at null:1 |
(以及随后请求使用localhost或file://的任何后续ajax的类似错误)
为了进行测试,我授予对Access-Control-Allow-Origin
部分中config.xml中所有内容的访问权限
1 |
在我的研究中,我发现该错误与Google从Android Jelly Bean开始所做的设置更改有关。这是我发现的:
来自:https://git-wip-us.apache.org/repos/asf?p=incubator-cordova-android.git;a=commitdiff;h=07439ff9
-来自org.apache.cordova.CordovaWebView
1 2 3 4 | // 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); |
-这也来自org.apache.cordova.CordovaWebView
1 2 3 4 5 6 7 8 | // 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); } } |
科尔多瓦(Cordova)尝试解决该变化很高兴,但不幸的是,这不起作用...
在这里和这里的这些SO线程中,我找到了一个通用的解决方案,可以简单地如下更改设置:
1 2 3 | if(android.os.Build.VERSION.SDK_INT > android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) { super.appView.getSettings().setAllowUniversalAccessFromFileURLs(true); } |
现在我收到以下警告:
1 2 | Call requires API level 16 (current min is 8) android.webkit.WebSettings#setAllowUniversalAccessFromFileURLs |
这是我在AndroidManifest.xml中的api
1 | <uses-sdk android:minSdkVersion="8" android:targetSdkVersion="16" /> |
为什么要求我将minSdkVersion更改为16,而不是遵循我的targetSdkVersion(16)?
有何想法?
注意:我当前正在Windows 7 Home(所有更新),Java 7 Update 7上使用Cordova 2.0,Eclipse Indigo SR2(当前所有更新),Android SDK(当前所有更新)。
好的,因此经过大量搜索,猜测和检查,我找到了可行的解决方案。
我必须为setAllowUniversalAccessFromFileURLs调用创建一个单独的函数...修复了TargetApi问题,但随后在JellyBean上提出了另一个问题,它无法连接到我在loadURL调用中拥有的文件,因此我不得不覆盖onReceivedError函数。这是我的结果代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | 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; } } |