在 Android项 目开发中,WebView 的使用都是必不可少的。在一个基本功能完备的项目中,都会把 WebView 提取成一个公用的 Activity 组件,在需要跳转到 H5 页面的地方启动这个 Activity 并传入相关参数即可。这样的简便快捷的使用,却容易造成开发者对 WebView 相关知识的疏忽。遂成此文,整理一二。
添加WebView
在应用中使用WebView,只需要在layout文件中添加
<WebView
android:id="@+id/main_web_view"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
使用loadUrl方法来加载WebView
WebView webView = (WebView) findViewById(R.id.main_web_view);
webView.loadUrl("http://www.example.com");
在此之前,还要确保应用有Internet权限
<uses-permission android:name="android.permission.INTERNET" />
至此,一个基本的WebView页就完成了。
在WebView中使用JavaScript
默认情况下,WebView是禁用JavaScript的。通过如下代码来为WebView开启JavaScript支持
WebSettings webSettings = webView.getSettings();
webSettings.setJavaScriptEnabled(true);
WebSettings管理着很多很有用的WebView设置项,例如setUserAgentString()等。具体细节可戳 WebSettings Doc.
WebView与JavaScript的交互*
WebView属Android端,所以该交互问题就是Android本地与JS端的交互问题。为了便于梳理,写了如图所示的一个Demo Source code,上半部分白底为WebView,加载本地的一个html页面,内含一个button和一个h1;下半部分是Android上的一个Button。
WebView调用JavaScript的方法
WebView调用JavaScript的方法相对比较简单,如果是无参数方法:
webView.loadUrl("javascript:METHOD")
其中 METHOD 为javascript方法名; 如果方法需要入参,例如下面这个javascript方法:
function testMethod(name) {
...
}
由于javascript为弱类型语言,所以入参并没有指定任何类型;具体类型的处理一般在javascript方法体内。 在webView中调用方法(注意,如果是字符串类型,必须在用单引号包裹,否则javascript无法识别,会提示name为定义):
String name = "Android";
webView.loadUrl("javascript:testMethod('" + name + "')");
JavaScript调用Android端的Java方法
1.创建接口
想要在 JavaScript 中调用相关的 Java 方法,需要在JavaScript端与Android客户端之间建立一个接口。
如下名为WebAppInterface的类,该类提供了一个名为showToast的本地方法,调用Android Toast通知消息,需要入参;该方法为等待JavaScript调用的方法,必须指定为 public 。
注意:如果 targetSdkVersion >= 17 ;必须要在为JS设置的方法加上 ** @JavascriptInterface ** 的注解;如果没有该注解,那么该方法在Android 4.2及以上的系统中是无法被JS访问到的。
public class WebAppInterface {
Context mContext;
/** Instantiate the interface and set the context */
WebAppInterface(Context c) {
mContext = c;
}
/** Show a toast from the web page */
@JavascriptInterface
public void showToast(String toast) {
Toast.makeText(mContext, "Hello," + toast, Toast.LENGTH_SHORT).show();
}
}
2.绑定接口
将该接口绑定到javascript,并指定一个名字,用于在javascript中调用。
webView.addJavascriptInterface(new WebAppInterface(this), "Android");
这样就为运行在WebView中的JavaScript创建了一个名为Android的接口,
3.调用
在javascript中的调用方法如下代码所示,id为btnCallNative的button在点击时后调用名为showAndroidToast的JS方法,并传入参数字符串;showAndroidToast方法体中通过名为Android的接口调用Android端的showToast方法,同时传入参数(注意: ** 没有必要 ** 再在javascript中对 “Android” 进行初始化,步骤2中webView已自动完成此工作):
<script type="text/javascript">
function showAndroidToast(toast) {
Android.showToast(toast);
}
</script>
<button id="btnCallNative" onclick="showAndroidToast('javascript')">
JS call Native
</button>
WebView页面导航处理
当你在WebView中点击其他链接时,系统默认会去启动一个默认浏览器(或弹出选择)去处理这个URL请求。大多数情况下这都不符合需求场景,我们可以通过创建自定义的 ** WebViewClient ** 来修改这个规则,让用户的前进或者后退操作都在这个WebView内进行,或者打开其他程序来处理。
private class MyWebViewClient extends WebViewClient {
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
if (Uri.parse(url).getHost().equals("www.example.com")) {
// This is my web site, so do not override; let my WebView load the page
return false;
}
// Otherwise, the link is not for a page on my site, so launch another Activity that handles URLs
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
startActivity(intent);
return true;
}
}
以上代码定义了一个名为MyWebViewClient的类,继承字WebViewClient,通过重写shouldOverrideUrlLoading方法来进行url路由操作;为了数据安全,建议在app的WebView中只加载该app自有的主机链接;对于其他不能确定安全性的链接在交给系统中其他程序处理。
然后为WebView初始化一个WebViewClient实例:
webView.setWebViewClient(new MyWebViewClient());
WebView历史导航
如果WebView重新加载了其他的URL,那么它会自动累加保存一个页面历史记录。可以通过 goBack() 和 goForward() 方法来进行历史导航。 如下代码,在activity中重写onKeyDown方法来处理返回按键的逻辑,其中 canGoBack() 用来判断是否还有历史页面可以返回,类似的还有 canGoForward()。如果用户按下返回键且存在可返回的历史页面,WebView回退到上一个历史页面。
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
// Check if the key event was the Back button and if there's history
if ((keyCode == KeyEvent.KEYCODE_BACK) && myWebView.canGoBack()) {
myWebView.goBack();
return true;
}
// If it wasn't the Back key or there's no web page history, bubble up to the default
// system behavior (probably exit the activity)
return super.onKeyDown(keyCode, event);
}