Android的webview,在资产文件夹中加载javascript文件

问题描述:

我见过这个问题已经问了很多次,但仍然无法让我的代码工作。Android的webview,在资产文件夹中加载javascript文件

我想我的WebView加载某些URL(比如www.google.com),然后应用存储在assets/jstest.js一些JavaScript,它包含以下内容:

function test(){ 
document.bgColor="#00FF00"; //turns to green the background color 
} 

这里的地方我尝试加载在JS:

@Override 
public void onPageFinished(WebView view, String url){ 
    view.loadUrl("javascript:(function() { " 
       + " document.bgColor='#FF0000';" //turns to red the background color 
       + " var script=document.createElement('script'); " 
       + " script.setAttribute('type','text/javascript'); " 
       + " script.setAttribute('src', 'file:///android_asset/jstest.js'); " 
       + " script.onload = function(){ " 
       + "  test(); " 
       + " }; " 
       + " document.getElementsByTagName('head')[0].appendChild(script); " 
       + "})()"); 
} 

我知道这里的JavaScript的工作,因为背景颜色居然变成红色,但由于某些原因,它不会加载jstest.js。我认为问题可能出现在文件路径中(我确定其他所有javascript代码都是正确的),但它对我来说看起来是正确的。该文件位于正确的文件夹中。

我错过了什么?

编辑

由于WebResourceResponse类是只与API级别11个可用,这里就是我最终想通了。

public void onPageFinished(WebView view, String url){ 
     String jscontent = ""; 
     try{ 
      InputStream is = am.open("jstest.js"); //am = Activity.getAssets() 
      InputStreamReader isr = new InputStreamReader(is); 
      BufferedReader br = new BufferedReader(isr); 

      String line; 
      while ((line = br.readLine()) != null) { 
       jscontent += line; 
      } 
      is.close(); 
     } 
     catch(Exception e){} 
     view.loadUrl("javascript:(" + jscontent + ")()"); 
    } 

jstest.js只是包含:

function() { 
    document.bgColor="#00FF00"; 
} 

我想同样的事情,加载书签(JavaScript代码在你使用loadURL()调用)到第三方网页。我的小书签还依赖于其他资源(javascript和css文件),它们不会使用file:/// android_asset URL进行加载。

这是因为该页面的安全上下文仍然是,例如,http://www.google.com,并且不允许访问file:URL。如果您提供/覆盖WebChromeClient.onConsoleMessage(),您应该能够看到错误。

我结束了一个杂牌组装电脑,我改变了书签的资产引用一个假的URL方案,如:

asset:foo/bar/baz.js 

,并增加了WebViewClient.shouldInterceptRequest()重写它看起来从这些资产,并加载它们使用AssetManager.open()。

我不喜欢这个问题的一件事是资产:计划对我的视图加载的任何页面上的任何第三方HTML/Javascript都是开放的,让他们可以访问我的应用程序的资产。

我没有尝试的一种替代方法是使用data:URL将子资产嵌入到小书签中,但这可能会变得笨拙。

我更喜欢它,如果有一种方法来操纵安全上下文只是 JS书签我加载loadUrl(),但我找不到像这样的东西。

这里有一个片段:

import android.webkit.WebResourceResponse; 
... 
    private final class FooViewClient extends WebViewClient 
    { 
    private final String bookmarklet; 
    private final String scheme; 

    private FooViewClient(String bookmarklet, String scheme) 
     { 
     this.bookmarklet = bookmarklet; 
     this.scheme = scheme; 
     } 

    @Override 
    public void onPageFinished(WebView view, String url) 
     { 
     view.loadUrl(bookmarklet); 
     } 

    @Override 
    public WebResourceResponse shouldInterceptRequest(WebView view, String url) 
     { 
     if (url.startsWith(scheme)) 
      try 
       { 
       return new WebResourceResponse(url.endsWith("js") ? "text/javascript" : "text/css", "utf-8", 
         Foo.this.getAssets().open(url.substring(scheme.length()))); 
       } 
      catch (IOException e) 
       { 
       Log.e(getClass().getSimpleName(), e.getMessage(), e); 
       } 

     return null; 
     } 
    } 
+0

首先,感谢您的回答! – Jacob 2011-04-14 14:37:10

+0

好的,所以它看起来没有这个问题的“干净”解决方案..我想过编写所有javascript代码insieme loadUrl(),这将工作没有问题,但它肯定不会是最好的选择。 所以,我正在尝试你的kludge,但我似乎无法重写shouldInterceptRequest() - 我无法导入WebResourceResponse类 - 你能帮我张贴一些代码吗? – Jacob 2011-04-14 14:52:15

+0

雅各布,看我的编辑,我添加了一个片段。 – dimitris 2011-04-14 17:20:58

也许你可以有资产作为 'HTML/JavaScript的模板'。你可以结合不同的这些文本来源和字符串逻辑来组成你想要加载到WebViewer中的html。然后,您使用.loadData而不是.loadUrl

我正在使用它,它似乎工作得很好。

希望它有帮助!

我认为cordova的iceam cream webview客户端可以做你想做的事情。

如果这是记录在某个地方,那就太好了,但据我所知,它不是。

看看科尔多瓦的Android github上: https://github.com/apache/incubator-cordova-android/blob/master/framework/src/org/apache/cordova/IceCreamCordovaWebViewClient.java

这里是我终于实现了它。我使用的内容://协议,并成立了ContentProvider的处理返回一个文件描述符到系统

这里是我的fileContentProvider:

import java.io.File; 
import java.io.FileNotFoundException; 
import java.io.FileOutputStream; 
import java.io.IOException; 
import java.io.InputStream; 

import org.apache.commons.io.IOUtils; 


import android.content.ContentProvider; 
import android.content.ContentValues; 
import android.database.Cursor; 
import android.net.Uri; 
import android.os.ParcelFileDescriptor; 
import android.util.Log; 

public class FileContentProvider extends ContentProvider { 
    @Override 
    public ParcelFileDescriptor openFile(Uri uri, String mode) { 

     Log.d("FileContentProvider","fetching: " + uri); 

     ParcelFileDescriptor parcel = null; 

     String fileNameRequested = uri.getLastPathSegment(); 
     String[] name=fileNameRequested.split("\\."); 
     String prefix=name[0]; 
     String suffix=name[1]; 
     // String path = getContext().getFilesDir().getAbsolutePath() + "/" + uri.getPath(); 
     //String path=file:///android_asset/"+Consts.FILE_JAVASCRIPT+" 

/*check if this is a javascript file*/ 

     if(suffix.equalsIgnoreCase("js")){ 
     InputStream is = null; 
     try { 
      is = getContext().getAssets().open("www/"+Consts.FILE_JAVASCRIPT); 
     } catch (IOException e1) { 
      // TODO Auto-generated catch block 
      e1.printStackTrace(); 
     } 


     File file = stream2file(is,prefix,suffix); 
     try { 
      parcel = ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY); 
     } catch (FileNotFoundException e) { 
      Log.e("FileContentProvider", "uri " + uri.toString(), e); 
     } 
     } 
     return parcel; 
    } 

    /*converts an inputstream to a temp file*/ 

    public File stream2file (InputStream in,String prefix,String suffix) { 
     File tempFile = null; 
     try { 
      tempFile = File.createTempFile(prefix, suffix); 
     } catch (IOException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } 
     tempFile.deleteOnExit(); 

      FileOutputStream out = null; 
      try { 
       out = new FileOutputStream(tempFile); 
      } catch (FileNotFoundException e) { 
       // TODO Auto-generated catch block 
       e.printStackTrace(); 
      } 

      try { 
       IOUtils.copy(in, out); 
      } catch (IOException e) { 
       // TODO Auto-generated catch block 
       e.printStackTrace(); 
      } 

     return tempFile; 
    } 


    @Override 
    public boolean onCreate() { 
     return true; 
    } 

    @Override 
    public int delete(Uri uri, String s, String[] as) { 
     throw new UnsupportedOperationException("Not supported by this provider"); 
    } 

    @Override 
    public String getType(Uri uri) { 
     throw new UnsupportedOperationException("Not supported by this provider"); 
    } 

    @Override 
    public Uri insert(Uri uri, ContentValues contentvalues) { 
     throw new UnsupportedOperationException("Not supported by this provider"); 
    } 

    @Override 
    public Cursor query(Uri uri, String[] as, String s, String[] as1, String s1) { 
     throw new UnsupportedOperationException("Not supported by this provider"); 
    } 

    @Override 
    public int update(Uri uri, ContentValues contentvalues, String s, String[] as) { 
     throw new UnsupportedOperationException("Not supported by this provider"); 
    } 
} 
在清单

我定义了供应商:

<provider android:name="com.example.mypackage.FileContentProvider" 
      android:authorities="com.example.fileprovider" 
     /> 

这里是JavaScriptø注入到网页视图:

webView.loadUrl("javascript:(function() { " 

      + "var script=document.createElement('script'); " 
      + " script.setAttribute('type','text/javascript'); " 
      + " script.setAttribute('src', 'content://com.example.fileprovider/myjavascriptfile.js'); " 
     /*  + " script.onload = function(){ " 
      + "  test(); " 
      + " }; " 
     */  + "document.body.appendChild(script); " 
      + "})();"); 

,这里是myjavascriptfile.js(举例):

function changeBackground(color) { 
     document.body.style.backgroundColor = color; 
    }