WebView与HTML/JavaScript的交互

在经过各种踩坑之后,才发现Webiew与本地网页间的交互实际上不难,写此文档的目的是为了今后大家在使用WebView上少走弯路,当然,这只是简单的交互方法,WebView的优化还有很长的路要走。
直接说原理显然是枯燥的,还是直接上代码吧,大家一看便知:
Android代码:

 @SuppressLint("JavascriptInterface")
   private void initSetting() {
    WebSettings settings = mWebView.getSettings();
    settings.setJavaScriptEnabled(true);
    settings.setJavaScriptCanOpenWindowsAutomatically(true);
    mWebView.addJavascriptInterface(new JsInterface(), keyToWeb);
    mWebView.loadUrl(htmlURL);
}

Android与JS交互的接口
private class JsInterface {
    //在js中调用window.AndroidWebView.sendInfoToAndroid(name),便会触发此方法。
    @JavascriptInterface
    public void sendInfoToAndroid(String obj) {
        Toast.makeText(MainActivity.this, "" + obj, Toast.LENGTH_SHORT).show();
    }

    @JavascriptInterface
    public String getDataFromAndroid() {
        return message;
    }

}

JS代码:

function change(type) {
    <!--var type = type;-->
    // 很可惜未找到直接弹出Alert的方法,所以只能打Log
    alert("From Web click--提示同时传出去弹吐司--"+type);
    console.log("From Web click--提示同时传出去弹吐司--"+type);
    window.Interface.sendInfoToAndroid(type);
}

 function click_button(){
      var    but = window.Interface.getDataFromAndroid();
            alert("From Android click -----" + but);
            console.log("From Android click -----" + but);
 }

Android中调用JavaScript中的函数:

mWebView.loadUrl("javascript:click_button()");

Javascript中调用Android中的方法:
window.你设置的接口中的标记.安卓对JS暴露的接口中的方法();

var but = window.Interface.getDataFromAndroid();

注意事项:
WebView设置

settings.setJavaScriptEnabled(true);

WebView暴露接口:

mWebView.addJavascriptInterface(new JsInterface(), "Interface");

第一个参数为Object类型的对象,是需要你自定义暴露给JS的接口,第二个参数为字符串类型的标志,用于android与JS互相识别。
WebView调用JS:

mWebView.loadUrl("javascript:click_button()");

JavaScript调用android:

var but = window.Interface.getDataFromAndroid();

出于安全机制考虑,要求暴露给JS的接口必须有 @JavascriptInterface 注解,以预防恶意JS注入。

实际效果:
点击网页按键一
WebView与HTML/JavaScript的交互_第1张图片
点击控件Button–hello
从网页输出的LOG
在这里插入图片描述

之前研究过一段时间的JsBridge,但是时间不够,没咋看懂,有兴趣可以看一下https://github.com/lzyzsd/JsBridge

补充:
//如果webView中需要用户手动输入用户名、密码或其他,则webview必须设置支持获取手势焦点。方法如下:

mWebView.requestFocusFromTouch();

WebView WebSettings 方法说明:

//获取WebSettings
WebSettings settings = mWebView.getSettings();

//设置WebView是否支持使用屏幕控件或手势进行缩放,默认是true,支持缩放
settings.setSupportZoom(false);

//设置WebView是否通过手势触发播放媒体,默认是true,需要手势触发
settings.setMediaPlaybackRequiresUserGesture(false);

//设置WebView是否使用其内置的变焦机制,该机制集合屏幕缩放控件使用,默认是false,不使用内置变焦机制
settings.setBuiltInZoomControls(true);

//设置WebView使用内置缩放机制时,是否展现在屏幕缩放控件上,默认true,展现在控件上
settings.setDisplayZoomControls(false);

//设置WebView是否使用预览模式加载界面
settings.setLoadWithOverviewMode(false);

//设置在WebView内部是否允许访问文件,默认允许访问
settings.setAllowFileAccess(false);

//设置WebView是否保存表单数据,默认true,保存数据
settings.setSaveFormData(false);

//设置WebView中加载页面字体变焦百分比,默认100,整型数
settings.setTextZoom(100);

//设置WebView是否使用viewport,当该属性被设置为false时,加载页面的宽度总是适应WebView控件宽度;
//当被设置为true,当前页面包含viewport属性标签,在标签中指定宽度值生效,
//如果页面不包含viewport标签,无法提供一个宽度值时该方法将被使用
settings.setUseWideViewPort(false);

//设置WebView是否支持多屏窗口,参考WebChromeClient#onCreateWindow,默认false,不支持
settings.setSupportMultipleWindows(true);

//设置WebView底层的布局算法,参考LayoutAlgorithm#NARROW_COLUMNS,将会重新生成WebView布局
settings.setLayoutAlgorithm(WebSettings.LayoutAlgorithm.NORMAL);

//设置WebView标准字体库字体,默认字体“sans-serif”
settings.setStandardFontFamily("sans-serif");

//设置WebView固定的字体库字体,默认“monospace”
settings.setFixedFontFamily("monospace");

//设置WebView字体最小值,默认值8,取值1到72
settings.setMinimumFontSize(8);

//设置WebView是否加载图片资源,默认true,自动加载图片
settings.setLoadsImagesAutomatically(false);

//设置WebView是否以http、https方式访问从网络加载图片资源,默认false
settings.setBlockNetworkImage(true);

//设置WebView是否从网络加载资源,Application需要设置访问网络权限,否则报异常
settings.setBlockNetworkLoads(true);

//设置WebView是否允许执行JavaScript脚本,默认false,不允许
settings.setJavaScriptEnabled(true);

//设置WebView运行中的脚本可以是否访问任何原始起点内容,默认true
settings.setAllowUniversalAccessFromFileURLs(false);

//设置Application缓存API是否开启,默认false,设置有效的缓存路径参考setAppCachePath(String path)方法
settings.setAppCacheEnabled(true);

//设置当前Application缓存文件路径,Application Cache API能够开启需要指定Application具备写入权限的路径
settings.setAppCachePath(getApplicationContext().getCacheDir().getAbsolutePath());

//设置脚本是否允许自动打开弹窗,默认false,不允许
settings.setJavaScriptCanOpenWindowsAutomatically(true);

//设置WebView加载页面文本内容的编码,默认“UTF-8”
settings.setDefaultTextEncodingName("UTF-8");

/* 重写缓存被使用到的方法,该方法基于Navigation Type,加载普通的页面,
 * 将会检查缓存同时重新验证是否需要加载,如果不需要重新加载,将直接从缓存读取数据,
 * 允许客户端通过指定LOAD_DEFAULT、LOAD_CACHE_ELSE_NETWORK、LOAD_NO_CACHE、LOAD_CACHE_ONLY其中之一
 * 重写该行为方法,默认值LOAD_DEFAULT
 */
settings.setCacheMode(WebSettings.LOAD_DEFAULT);

/*设置当一个安全站点企图加载来自一个不安全站点资源时WebView的行为,
*android.os.Build.VERSION_CODES.KITKAT* 默认为**MIXED_CONTENT_ALWAYS_ALLOW**,
*android.os.Build.VERSION_CODES.LOLLIPOP*默认为**MIXED_CONTENT_NEVER_ALLOW**,
取值其中之一:MIXED_CONTENT_NEVER_ALLOW、MIXED_CONTENT_ALWAYS_ALLOW、MIXED_CONTENT_COMPATIBILITY_MODE
*/
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
settings.setMixedContentMode(WebSettings.MIXED_CONTENT_COMPATIBILITY_MODE);

WebViewClient类方法说明:

 webView.setWebChromeClient(new WebChromeClient() {    
     @Override   
     public void onProgressChanged(WebView view, int newProgress) {
         //加载的进度
     }
     @Override
     public void onReceivedTitle(WebView view, String title) {   
         //获取WebView的标题
     }
    @Override
    public boolean onJsAlert(WebView view, String url, String message, final JsResult result) {    
        return super.onJsAlert(view, url, message, result);
        //Js 弹框
    }
    @Override
    public boolean onJsConfirm(WebView view, String url, String message, final JsResult result) {   
        AlertDialog.Builder b = new AlertDialog.Builder(IllegalQueryActivity.this);    
        b.setTitle("删除");    
        b.setMessage(message);    
        b.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {        
            @Override        
            public void onClick(DialogInterface dialog, int which) {            
                result.confirm();        
            }    
        });    
        b.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {        
            @Override        
            public void onClick(DialogInterface dialog, int which) {            
                result.cancel();        
            }    
        });    
        b.create().show();    
        return true;
    }
});
webView.setWebViewClient(new WebViewClient() {    
    @Override    
    public boolean shouldOverrideUrlLoading(WebView view, String url) {        
       //需要设置在当前WebView中显示网页,才不会跳到默认的浏览器进行显示
       return true;   
    }    
    @Override    
    public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) {
        super.onReceivedError(view, request, error);
        //加载出错了
    }   
    @Override    
    public void onPageFinished(WebView view, String url) {        
        super.onPageFinished(view, url);
        //加载完成
    }
});
webView.setDownloadListener(new DownLoadListener());//下载监听
private class DownLoadListener implements DownloadListener {   
    @Override   
    public void onDownloadStart(String url, String userAgent, String contentDisposition, String mimetype, long contentLength) {      
    }
}

拦截网页请求URL:
示例网页html
WebView与HTML/JavaScript的交互_第2张图片
使用WebViewClient拦截URL

private class MyWebViewClient extends WebViewClient {
    @Override
    public boolean shouldOverrideUrlLoading(WebView view, String url) {
        Log.i("TAG", "shouldOverrideUrlLoading----1: " + url);
        if (url.startsWith("abc:")) {
            Toast.makeText(MainActivity.this, "" + url, Toast.LENGTH_SHORT).show();
            return true;
        }
        if ((url.toLowerCase().startsWith("http://")) || (url.toLowerCase().startsWith("https://"))) {
            view.loadUrl(url);
            return true;
        }
        return true;
    }
    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    @Override
    public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
        Log.i("TAG", "shouldOverrideUrlLoading----2: " + request.getUrl().toString());
        return super.shouldOverrideUrlLoading(view, request);
    }
}

点击网页按键三和四,日志:
WebView与HTML/JavaScript的交互_第3张图片

拦截回退键,让WebView返回上一页:

@Override  //方法一
public boolean onKeyDown(int keyCode, KeyEvent event) {
    if ((keyCode == KeyEvent.KEYCODE_BACK) && mWebView.canGoBack()) {
        mWebView.goBack();
        return true;
    }
    return super.onKeyDown(keyCode, event);
}
@Override  //方法二 单独处理回退键 >Android 2.0
public void onBackPressed() {
    if (mWebView.canGoBack()) mWebView.goBack();
    super.onBackPressed();
}

通过loadUrl( )方法更改网页显示效果,比如更改某节点样式:

mWebView.loadUrl("javascript:function setTop(){document.querySelector('#head').style.display=\"none\";}setTop();");

通过loadUrl( )向网页传入JavaScript代码,如上面代码就是增加了一个setTop()方法,方法的作用是查找html文档的head节点,更改其style属性的display值使其隐藏;最后再调用这个setTop()方法。

你可能感兴趣的:(Android成长之路)