1. 创建Android 项目
- 打开Android Studio
- 创建一个空的Android项目
- 打开Android虚拟机,这里使用的是Genymotion
2. 添加webview
- 清空layout内容,添加WebView控件
<WebView
android:id="@+id/web"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
- 在
MainActivity
中创建引入webview
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
WebView mweb = findViewById(R.id.web);
mweb.loadUrl("http://www.baidu.com");
}
- 此时运行项目,发现android安装成功,webview也可以打开,但是页面请求失败,需要给APP添加联网权限。
在AndroidManifest.xml
的manifest
标签内添加
<uses-permission android:name="android.permission.INTERNET"/>
- 此时运行项目,发现webview可以打开并且百度页面可以访问了,但是仔细发现webview并不是在自己的APP上打开的,而是弹出系统浏览器。因为webview只是载体,内容的渲染需要使用webviewChromClient类去实现此时需要
setWebViewClient
...
WebView mweb = findViewById(R.id.web);
mweb.setWebViewClient(new WebViewClient());
mweb.loadUrl("http://www.baidu.com");
...
- 运行APP后可以看到webview已经差不多是我们想要的了
3. 设置JavaScript可执行
仔细看会发现,通过上面步骤打开的百度首页跟我们平时看到的广告页面不一样,原因是WebView默认禁止了JS的执行。这也是我觉得百度首页做的比较好的地方,在无JS环境下仍可提供服务。
- 添加
setJavaScriptEnabled
...
mweb.setWebViewClient(new WebViewClient());
mweb.getSettings().setJavaScriptEnabled(true);
mweb.loadUrl("http://www.baidu.com");
...
此时再打开页面,就会发现广告出来了,并且页面很卡。
4. WebView 调用 Android 方法
1. 使用addJavascriptInterface
- 添加JS接口
创建JavaScriptInterFace.java
类,用来写JS调用方法
package com.test.myapplication;
import android.util.Log;
import android.webkit.JavascriptInterface;
public class JavaScriptInterFace {
@JavascriptInterface
public String getValue(String name) {
Log.d("tagee", "getValue:" + name);
return "call back";
}
}
因为安全问题,在Android4.2中JS只能访问带有 @JavascriptInterface
注解的Java函数。
- addJavascriptInterface注入
...
mweb.setWebViewClient(new WebViewClient());
mweb.getSettings().setJavaScriptEnabled(true);
mweb.addJavascriptInterface(new JavaScriptInterFace(), "JSBridge");
// JSBridge 为 webview 中调用的对象名称
mweb.loadUrl("http://www.baidu.com");
...
- 加载本地 html 文件
在app/src/main
目录下面创建目录assets
并新建a.html
文件,写入如下代码
<!doctype html>
<html lang="en">
<head></head>
<body>
<h1 id="h1">123</h1>
<script>
if(window.JSBridge){
alert(JSBridge.getValue('from JS'));
}
</script>
</body>
</html>
修改webview的loadUrl
参数
mweb.addJavascriptInterface(new JavaScriptInterFace(), "JSBridge");
mweb.loadUrl("file:///android_asset/a.html");
此时重新build,可以看到Logcat
打印出from JS
,并且页面弹窗。
2.通过loadUrl()
loadUrl
可以执行JavaScript代码,他有如下特征:
1. 调用`loadUrl`会刷新页面
2. 当参数为要执行的JS代码时,要有document对象,至少得load一个空白页,否则会失效
3. 若返回值为非空字符串,则会将返回值替换页面原本的内容
4. 可以调用html中的js代码,但需要在`onPageFinished`回调之后才能调用,并且注意第三点的影响,防止返回字符串替换文档
如:
...
mweb.addJavascriptInterface(new JavaScriptInterFace(), "JSBridge");
mweb.loadUrl("javascript:aler(123)"); //因当前webview没用加载任何页面,脚本无效
...
mweb.addJavascriptInterface(new JavaScriptInterFace(), "JSBridge");
mweb.loadUrl("file:///android_asset/a.html");
mweb.loadUrl("javascript:'123'"); //此时页面被替换成123
protected void onCreate(Bundle savedInstanceState) {
...
mweb.addJavascriptInterface(new JavaScriptInterFace(), "JSBridge");
mweb.setWebViewClient(new mWebViewClient());
mweb.loadUrl("file:///android_asset/a.html");
}
...
private class mWebViewClient extends WebViewClient{
@Override
public void onPageFinished(WebView view, String url) {
view.loadUrl("javascript:callJS()");//callJS为a.html中定义的方法
super.onPageFinished(view, url);
}
}
实际使用时,Android更多的是调用远程JS代码,即将加载的JS代码路径改成url即可。或则直接拼接JS代码时也会放在闭包中执行,防止替换页面内容。
3. 通过evaluateJavascript()
如果是Android4.4后,推荐使用evaluateJavascript
,比loadUrl
效率更高,并且不会刷新页面。evaluateJavascript
有两个参数,第一个为脚本内容,第二个则是脚本的执行结果。在onPageFinished
调用:
view.evaluateJavascript("javascript:callJS()", new ValueCallback<String>() {
@Override
public void onReceiveValue(String value) {
Log.d("tagee", value);
}
});
4. 通过shouldOverrideUrlLoading()
shouldOverrideUrlLoading
是WebViewClient
对象的一个"生命周期",用拦截URL的请求,监听网页地址的变化,返回ture
或false
来决定webview是否加载URL。
1. 若没有设置 WebViewClient 则由系统(Activity Manager)处理该 url,通常是使用浏览器打开或弹出浏览器选择对话框,即出现上文2.4的情况。
2. 若设置 WebViewClient 且该方法返回 true ,则说明由应用的代码处理该 url,WebView不跳转。
3. 若设置 WebViewClient 且该方法返回 false,则说明由 WebView 处理该 url,即用 WebView 加载该 url。
private class mWebViewClient extends WebViewClient{
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
//此处可以解析url进行处理,
//也可以直接调用view.loadUrl(url); 在当前的webview中跳转到新的url
//若前端直接location.href="js://web?param1=123¶m2=asd"
Uri uri = Uri.parse(url);
if ( uri.getScheme().equals("js")) {
//可以在此处获取页面请求数据并处理
//或则直接跳转activity等
return true;
}
return false;
}
}
值得一提的是以前一直有一个误区,以为使用一个不可见的iframe
标签,再动态改变其src
也可以捕捉url变化达到传值的目的。测试过不可行,包括默认写入和动态创建iframe
4. 通过onJsAlert()、onJsConfirm()、onJsPrompt()
原理和上面一条一样,通过监听页面的弹窗事件,达到传值的目的,不细说了。