在 web 视图中加载本地 javascript 文件时出现问题
我遇到了一个困扰我好几天的问题。事实证明,这是一个 Android 故障,并且已经提交、确认,希望能在未来的版本中修复。现在我找到了一个适合我的解决方案,并将在下面提供它,但是该解决方案并不完美,因为它涉及编辑电话间隙源。我主要的问题是是否有人可以找到更好的解决方案来解决这个问题。
错误:
当您尝试在 Android 3.0+ 上的 WebView 中加载页面时,会出现问题。问题是,如果该页面引用任何本地 JavaScript 文件,则无法将查询数据附加到 URL。基本上
这有效:
这不起作用:
为什么会有人想要这样做,因为文件显然可以'对查询值不做任何事情吗?对我来说,我有一个phonegap应用程序,它通过JSONP加载设置文件,但是如果未指定设置文件,它默认为本地文件。所以是的,该文件无法处理查询数据,但使用相同的文件格式和加载结构会很好。
解决方案 1(非 PhoneGap)
因此,如果目标 Android 平台是 11(Honeycomb)或更高版本,则有一个简单的解决方案。 (只要您小心并且不使用任何较低 API 级别中不存在的方法,此代码将在 <11 api 上运行,但您仍然需要将 11 设置为目标)
基本上,您将 WebViewClient 添加到WebView利用shouldInterceptRequest方法拦截带有查询数据的本地js文件的加载。
import java.io.IOException;
import java.io.InputStream;
import android.content.res.AssetManager;
import android.webkit.WebResourceResponse;
import android.webkit.WebView;
import android.webkit.WebViewClient;
public class PatchingWebViewClient extends WebViewClient{
AssetManager am;
public PatchingWebViewClient(AssetManager am){
this.am = am;
}
@Override
public WebResourceResponse shouldInterceptRequest (WebView view, String url){
if(url.indexOf("file:///android_asset") == 0 && url.contains("?")){
String filePath = url.substring(22, url.length());
filePath = filePath.substring(0, filePath.indexOf("?"));
try {
InputStream is = am.open(filePath);
WebResourceResponse wr = new WebResourceResponse("text/javascript", "UTF-8", is);
return wr;
} catch (IOException e) {
return null;
}
}else{
return null;
}
}
}
要设置 WebViewClient,您的代码将如下所示:
import android.app.Activity;
import android.os.Bundle;
import android.webkit.WebView;
public class CanWeBreakAWebViewActivity extends Activity {
WebView mWebView;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mWebView = (WebView) findViewById(R.id.webview);
mWebView.getSettings().setJavaScriptEnabled(true);
mWebView.setWebViewClient(new PatchingWebViewClient(this.getAssets()));
mWebView.loadUrl("file:///android_asset/index.html");
}
}
解决方案 2 (PhoneGap)
现在对于 Phonegap 我没有一个干净的解决方案。我的解决方案是下载 Phonegap 源代码并通过添加以下方法来编辑 CordovaWebViewClient:
@Override
public WebResourceResponse shouldInterceptRequest (WebView view, String url){
if(url.indexOf("file:///android_asset") == 0 && url.contains("?")){
String filePath = url.substring(22, url.length());
filePath = filePath.substring(0, filePath.indexOf("?"));
try {
InputStream is = ctx.getAssets().open(filePath);
WebResourceResponse wr = new WebResourceResponse("text/javascript", "Cp1252", is);
return wr;
} catch (IOException e) {
return null;
}
}else{
return null;
}
}
解决方案 3(不存在)
该解决方案希望能够轻松包含类或调整到主要活动,以便您可以使用 Phone Gap但可以只使用代码的 .jar 文件,从而使升级更容易。
I had with an issue that has plagued me for days. It turned out that it was an Android glitch and has been submitted, confirmed, and hopefully will be fixed in a future release. Now I have found a solution that works for me, and will provide it below, however the solution is not perfect as it involves editing the phone gap source. Mainly my question is if someone can find a better solution to this issue.
The Bug:
There is a glitch when you attempt to load a page inside of a WebView on Android 3.0+. The glitch is that if that page references any local javascript files, you cannot append query data to the url. Basically
This works:<script type="text/javascript" src="StaticJS.js"></script>
This does not work:<script type="text/javascript" src="StaticJS.js?var=val"></script>
Why the hell would anyone want to do this since the file obviously can't do anything with the query vals? Well for me I have a phonegap application that loads a settings file via JSONP, however if a settings file is not specified it defaults to a local file. So yeah, the file can't process the query data but it would be nice to use the same file format and loading structure.
Solution 1 (Non-PhoneGap)
So there is an easy solution to this if the target android platform is 11(Honeycomb) or higher. (As long as you are careful and do not use any method that do not exists in any lower API levels this code will run on <11 apis, but you will still have to set 11 as your target)
Basically you add a WebViewClient to the WebView that utilizes the shouldInterceptRequest method to intercept the loading of local js files with query data attached.
import java.io.IOException;
import java.io.InputStream;
import android.content.res.AssetManager;
import android.webkit.WebResourceResponse;
import android.webkit.WebView;
import android.webkit.WebViewClient;
public class PatchingWebViewClient extends WebViewClient{
AssetManager am;
public PatchingWebViewClient(AssetManager am){
this.am = am;
}
@Override
public WebResourceResponse shouldInterceptRequest (WebView view, String url){
if(url.indexOf("file:///android_asset") == 0 && url.contains("?")){
String filePath = url.substring(22, url.length());
filePath = filePath.substring(0, filePath.indexOf("?"));
try {
InputStream is = am.open(filePath);
WebResourceResponse wr = new WebResourceResponse("text/javascript", "UTF-8", is);
return wr;
} catch (IOException e) {
return null;
}
}else{
return null;
}
}
}
To set the WebViewClient, your code would look something like this:
import android.app.Activity;
import android.os.Bundle;
import android.webkit.WebView;
public class CanWeBreakAWebViewActivity extends Activity {
WebView mWebView;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mWebView = (WebView) findViewById(R.id.webview);
mWebView.getSettings().setJavaScriptEnabled(true);
mWebView.setWebViewClient(new PatchingWebViewClient(this.getAssets()));
mWebView.loadUrl("file:///android_asset/index.html");
}
}
Solution 2 (PhoneGap)
Now for Phonegap I don't have a clean solution. My solution is to go and download the Phonegap source and edit the CordovaWebViewClient by adding the following method:
@Override
public WebResourceResponse shouldInterceptRequest (WebView view, String url){
if(url.indexOf("file:///android_asset") == 0 && url.contains("?")){
String filePath = url.substring(22, url.length());
filePath = filePath.substring(0, filePath.indexOf("?"));
try {
InputStream is = ctx.getAssets().open(filePath);
WebResourceResponse wr = new WebResourceResponse("text/javascript", "Cp1252", is);
return wr;
} catch (IOException e) {
return null;
}
}else{
return null;
}
}
Solution 3 (Non-Existent)
This solution would hopefully be some easy to include class or tweak to the main activity so that you can use phone gap but could just use a .jar file of the code, making upgrades easier.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
感谢这篇文章,您向我提供了最新的解决方案,即使用 IceCreamCordovaWebViewClient。
Thanks for this post, you clued me in to the latest solution which is simply to use IceCreamCordovaWebViewClient.
查询数据附加到 javascript 文件(以及其他文件类型,如 css)以防止浏览器缓存。查询数据对文件没有用处,但浏览器将其视为新文件,因为位置已更改(在浏览器看来)并且加载了新副本。
我很高兴你找到了问题的答案,只是想我会就人们为什么使用这种方法给出我的意见。
Query data is appended to javascript files (and other file types like css) to prevent browser caching. The query data is useless to the file but the browser treats it as new because the location is changed (in the eyes of the browser) and it loads a fresh copy.
I'm glad you found an answer to your problem, just thought I'd give my input as to why people use this method.