在Android WebView中注入外部JS文件并调用它

时间:2011-03-15 13:58:51

标签: javascript android external code-injection

我正在尝试将我的外部JS文件(包含在资产目录中)注入WebView并在之后调用它。

这是我用于注入它的代码:

webView.setWebViewClient(new WebViewClient() {
    @Override
    public void onPageFinished(WebView view, String url) {
        super.onPageFinished(view, url);
        webView.loadUrl("javascript: (function() { "
            + "var script=document.createElement('script');"
            + "script.type='text/javascript';script.src='file://android_asset/js_demo.js';"
            + "document.getElementsByTagName('head').item(0).appendChild(script);"
            + "})()");
        webView.loadUrl("javascript: jsDemo()");
    }
});

当我打印我的网页视图的整个内容时,我可以看到确实插入了src ='file://android_asset/js_demo.js'的脚本标记,但是调用函数jsDemo什么也没做。

注意:函数jsDemo包含在js_demo.js中并且没有任何巧妙,只是更改了某个span的颜色。它工作正常,因为我在浏览器中进行了测试。

我确信我错误地提供了js文件的路径,但我不确定如何更改它以使其工作。任何帮助将不胜感激。

4 个答案:

答案 0 :(得分:2)

为什么不直接读取文件并通过loadUrl("javascript:...)直接执行?

答案 1 :(得分:2)

以下是我最终如何做到这一点。我使用Content://协议并设置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"
        />

这是我注入webview的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;

}

答案 2 :(得分:1)

感谢您的反馈。我尝试了大部分建议,以及我如何为每个网页webkit加载注入.js文件。

  1. 将本地js文件读取为字符串。
  2. 在创建类型为script.text
  3. 的文档元素后,将该字符串附加到text/javascript
  4. 在被覆盖的网络视图javascript: (function() { <programmatically formatted string dynamically creating webpage script element >})()"内调用onPageFinished
  5. 已在Android 4.0.3-4.0.4冰淇淋三明治(API等级15)上验证工作

答案 3 :(得分:0)

“file:”后需要三个斜杠