引言
最近在公司项目及个人项目都用到WebView,重温了一下已经忘了差不多的HTML和JavaScript,因此在这里总结,方便之后的开发。
加载Web页面
从显示Web页面开始,第一步当然是配置网络权限
<uses-permission android:name="android.permission.INTERNET"/>
布局很简单,就只有一个WebView
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent">
<WebView
android:id="@+id/webview"
android:layout_width="match_parent"
android:layout_height="match_parent">
</WebView>
</FrameLayout>
接下来就是java代码,使用load方法加载Url
public class MainActivity extends AppCompatActivity {
private WebView mWebView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mWebView = (WebView) findViewById(R.id.webview);
mWebView.loadUrl("http://www.baidu.com");
}
}
通过以上几个步骤在URL正确的情况下就能显示出与URL对应的Web页面,但默认情况下会启动系统默认的浏览器来显示Web页面,而大部分情况下Web页面应该显示在App内部。对于这个问题可以通过为WebView设置WebViewClient实现,具体代码如下
public class MainActivity extends AppCompatActivity {
private WebView mWebView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mWebView = (WebView) findViewById(R.id.webview);
mWebView.loadUrl("http://www.baidu.com");
mWebView.setWebViewClient(new WebViewClient());
}
}
通过
mWebView.setWebViewClient(new WebViewClient());
将WebView与WebViewClient进行绑定。这样设置之后就可以实现使用WebView在App内部加载Web页面,其中的原理,根据WebViewClient源码中的文档注释就能明白
在没有设置WebViewClient的情况下,Url是交给系统处理的,处理方式一般都是启动系统默认浏览器来加载页面;
在设置WebViewClient的情况下有分为以下两种情况:
shouldOverrideUrlLoading返回 true,表示WebView不处理,交由主机应用程序处理
shouldOverrideUrlLoading返回 false,表示由WebView处理URL
而shouldOverrideUrlLoading在默认情况下是返回false,因此给WebView设置了WebViewClient就能将页面在WebView中显示
WebViewClient
上面提到了WebViewClient,这边就对WebViewClient中的两个常用方法的实践进行一下总结
shouldOverrideUrlLoading
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
return true;
}
@Override
public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
return true;
}
shouldOverrideUrlLoading在作用在前文意见介绍过,但这边有一点需要注意以下
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
return true;
}
这个方法在 Android 7.0 SDK中已经被弃用,用
@Override
public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
return true;
}
代替,但新的API在低版本中是不兼容的,表现的情况就是不被调用,不过旧的API兼容所有版本,所以考虑到兼容性应该使用旧API也就是第二个参数为String url的shouldOverrideUrlLoading
onReceivedError
@Override
public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
super.onReceivedError(view, errorCode, description, failingUrl);
}
在URL错误、网络异常、服务器异常导致页面加载失败的情况下onReceivedError都会被调用,默认情况下,在页面加载失败时会显示系统默认的一个失败页面,系统默认页面与我们App的UI风格是不太可能统一的,所以为了界面的美观可以通过onReceivedError监听WebView加载失败,在onReceivedError中调用WebView的load方法加载自定义的HTML失败页面,这个自定义的HTML失败页面一般放在项目的assets文件夹下,具体代码如下
@Override
public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
super.onReceivedError(view, errorCode, description, failingUrl);
view.loadUrl("file:///android_asset/XXX.html");
}
XXX表示自定义的HTML文件的文件名。onReceivedError(WebView view, int errorCode, String description, String failingUrl) 在Android 6.0 SDK已被弃用,但与shouldOverrideUrlLoading一样高版本的API在低版本中不兼容,所以考虑兼容性还是继续使用。
Java与JavaScript的交互
首先要对WebView进行如下设置
mWebView.setWebChromeClient(new WebChromeClient());
mWebView.getSettings().setJavaScriptEnabled(true);
Java调用JavaScript
mWebView.loadUrl("javascript:Java_Call_JS("+"'test'"+")");
webView调用js的基本格式为webView.loadUrl(“javascript:methodName(parameterValues)”)
javascript:为固定格式,methodName在上述代码中对应的就是Java_Call_JS,Java_Call_JS定义在JavaScript中,可以根据实际的JavaScript方法名进行替换,具体代码会在下文给出
JavaScript调用Java
JavaScript调用Java需要使用到WebView的addJavascriptInterface方法,相关代码如下
html
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<script type="text/javascript">
function Java_Call_JS(message){
alert(message);
}
function JS_Call_Java(text){
window.Android.callJava(text);
}
</script>
</head>
<body>
<input type="button" value="call java" onclick="JS_Call_Java('')">
</body>
</html>
Java
mWebView.addJavascriptInterface(new JavascriptInterface(),"Android");
class JavascriptInterface{
@android.webkit.JavascriptInterface
public void callJava(String text){
Toast.makeText(MainActivity.this,"test",Toast.LENGTH_SHORT).show();
}
}
根据上述两段代码可以总结如下:
在JS中调用Java的基本格式:window.jsInterfaceName.methodName(parameterValues)
在本例中jsInterfaceName就对应Java代码中addJavascriptInterface的第二个参数"Android",methodName对应JavascriptInterface类中的callJava方法,被JavaScript调用的方法需要用__@android.webkit.JavascriptInterface __注解。
最后放上一个完整示例,在HTML页面中点击按钮,调用Java方法,显示Toast;点击Native的按钮调用JavaScript方法,在HTML页面中显示出对话框
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<script type="text/javascript">
function Java_Call_JS(message){
alert(message);
}
function JS_Call_Java(text){
window.Android.callJava(text);
}
</script>
</head>
<body>
<input type="button" value="call java" onclick="JS_Call_Java('JavaScript call Java')">
</body>
</html>
public class MainActivity extends AppCompatActivity {
private WebView mWebView;
private Button mButton;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mWebView = (WebView) findViewById(R.id.webview);
mWebView.loadUrl("file:///android_asset/sample.html");
mWebView.setWebViewClient(new WebViewClient());
mWebView.setWebChromeClient(new WebChromeClient());
mWebView.getSettings().setJavaScriptEnabled(true);
mWebView.addJavascriptInterface(new JavascriptInterface(),"Android");
mButton = (Button) findViewById(R.id.button);
mButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
mWebView.loadUrl("javascript:Java_Call_JS("+"'Java call JavaScript'"+")");
}
);
}
class JavascriptInterface{
@android.webkit.JavascriptInterface
public void callJava(String text){
Toast.makeText(MainActivity.this,"test",Toast.LENGTH_SHORT).show();
}
}
}
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<WebView
android:id="@+id/webview"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
</WebView>
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="call JS"/>
</LinearLayout>
最后
如果文中存在错误或纰漏,请在评论中留言,我会在第一时间进行修改