我们了解过Web,对于HTTP协议,我们不是做网站开发,Android端只需要简单的了解基本的原理就可以了。首先由客户端发送请求给服务端,然后服务端返回对应的指令,最后根据返回的指令进行解析和处理。这就是一个简单的网络交互协议。
1.WebView的用法
在做Android开发的时候,我们可能会碰到一些特殊的需求,比如说在应用 程序中加载一个网页,或者插入一些广告啥的,而且需求中又不允许打开系统的浏览器,怎么办?Android已经考虑到这种需要了,所以提供了一个WebView控件,在自己的应用程序中嵌入一个浏览器。这样就可以轻松展示各种网页。
WebView的用法很简单,和一般的控件都一样。
1.新建一个activity_main.xml,然后插入一个WebView 控件
<?xml versi encoding 'utf-8'?><LinearLayout
xmlns:android='http://schemas.android.com/apk/res/android'
android:layout_width='match_parent'
android:layout_height='match_parent' >
<WebView
android:id='@+id/wb_main'
android:layout_width='match_parent'
android:layout_height='match_parent' /></LinearLayout>
2.MainActivity 设置WebView的方法
public class MainActivity extends AppCompatActivity { @Override
protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
WebView wb_main= (WebView) findViewById(R.id.wb_main);
wb_main.getSettings().setJavaScriptEnabled(true);//支持JavaScriptEnable
wb_main.setWebViewClient(new WebViewClient());
wb_main.loadUrl('http://www.baidu.com');
}
}
通过getSetting()可以设置浏览器的属性,这里用了setJavaScriptEnabled()的来让WebView支持JavaScript脚本。然后调用WebView的setWebViewClient()的方法并传入一个实例。最后是希望加载的网页
3.最后一步,记得加上权限
<uses-permission android:name='android.permission.INTERNET'/>
这样就完成了一个简单的加载网页。
2.WebView的方法
2.1 加载url
根据加载的方式不同分为三种:
//方式1. 加载一个网页:
webView.loadUrl('http://www.baidu.com/'); // 加载url页面
//方式2:加载apk包中的html页面
webView.loadUrl('file:///android_asset/test.html'); //方式3:加载手机本地的html页面
webView.loadUrl('content://com.android.htmlfileprovider/sdcard/test.html');
// 另外1、: 加载 HTML 页面的一小段内容
WebView.loadData(String data, String mimeType, String encoding) 如:
webView_main.loadData(data, 'text/html','utf-8');// 参数说明:// 参数1:需要截取展示的内容// 内容里不能出现 ’#’, ‘%’, ‘\’ , ‘?’ 这四个字符,若出现了需用 #, %, ', ? 对应来替代,否则会出现异常// 参数2:展示内容的类型// 参数3:字节码//另外2、:webView_main.loadDataWithBaseURL(null, data, 'text/html', 'utf-8', null);
loadDataWithBaseURL()的作用呢?难道是结合体?因为webView_main.loadData(data, 'text/html','utf-8');//这个方法中虽然设置了字符,但是还是会显示中文乱码。所以建议使用 webView_main.loadDataWithBaseURL(null, data, 'text/html', 'utf-8', null);
2.2 前进后退网页
//是否可以后退Webview.canGoBack()
//后退网页Webview.goBack()//是否可以前进 Webview.canGoForward()//前进网页Webview.goForward()//以当前的index为起始点前进或者后退到历史记录中指定的steps//如果steps为负数则为后退,正数则为前进Webview.goBackOrForward(intsteps)
如果在请求WebView的时候,进入二级的WebView的时候,点击Back键,实际上是整个Activity都结束,调用了finish()方法,所以这个时候需要调用goBack()方法。
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) { if ((keyCode == KEYCODE_BACK) && wb_main.canGoBack()) {
wb_main.goBack(); return true;
} return super.onKeyDown(keyCode, event);
}
或者.
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) { if(event.getKeyCode() == KeyEvent.KEYCODE_BACK){ if(wb_main.canGoBack() ){ //获取浏览记录
WebBackForwardList backForwardList= wb_main.copyBackForwardList(); //这里的判断是为了让页面在有上一个页面的情况下,跳转到上一个html页面,而不是退出当前activity
if(backForwardList.getCurrentIndex()>0){
String historyUrl = backForwardList.getItemAtIndex(backForwardList.getCurrentIndex()-1).getUrl(); if(historyUrl !=url ){
wb_main.goBack(); return true;
}
}
} else{ return true;
}
} return true;
}
2.3 缓存
//清除网页访问留下的缓存//由于内核缓存是全局的因此这个方法不仅仅针对webview而是针对整个应用程序.Webview.clearCache(true);//清除当前webview访问的历史记录//只会webview访问历史记录里的所有记录除了当前访问记录Webview.clearHistory();//这个api仅仅清除自动完成填充的表单数据,并不会清除WebView存储到本地的数据Webview.clearFormData();
1.2 WebView的常用类
1.2.1 WebSetting类
WebView加载网页内容,但是对于HTML文本的Javascript代码却无法加载运行。为了解决这个问题要借助WebSettings类。WebSettings类除了可以设置是否支持Javascript外,还具有set系列方法来设置WebView的属性和状态。WebSettings对象通过WebView对象的getSettings()方法来获取
| 方法 | 描述 |
|---|---|
| setJavaScriptEnabled(boolean flag) | 设置是否支持Javascript |
| setBlockNetworkImage(boolean flag) | 设置是否阻止网络图片加载 |
| setBuiltInZoomControls(boolean enabled) | 将HTML文本内容加载到WebView中 |
| setCacheMode(int mode) | 设置缓存模式 |
| setDefaultFontSize(int size) | 设置默认字体大小 |
| setFixedFontFamily(String font) | 设置固定使用的字体 |
| setDefaultTextEncodingName(String encoding) | 设置解码时默认的字符集 |
| setSupportZoom(boolean support) | 设置是否支持变焦 |
| setAllowFileAccess(boolean allow) | 设置是否允许访问WebView中文件。就是file:///android_asset和file:///android_res路径下的资产和资源文件。默认允许访问。 |
注意:5.1以上默认禁止了https和http混用 这是开启
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
mWebView.getSettings().setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW);
}
2.4 WebViewClient类
WebView解决了支持Javascript的问题。但是新的问题又出来了。当点击WebView中的超链接后,原本希望目标网页在当前WebView中显示,但是却打开了系统浏览器来加载目标网页。为了解决这个问题,要借助WebViewClient类。WebViewClient类专门用来辅助WebView处理各种通知、请求等事件。通过WebView对象调用setWebViewClient()方法来指定一个WebViewClient对象,重写WebViewClient对象中的shouldOverrideUrlLoading()方法,使得当有新连接时,使用当前WebView来显示网页。WebViewClient除此之外,还有其他的方法
| 方法 | 描述 |
|---|---|
| shouldOverrideUrlLoading() | 新的链接在当前WebView中打开 |
| onPageStarted() | 网页开始加载 |
| onPageFinished() | 网页加载完毕 |
| doUpdateVisitedHistory() | 更新访问历史记录的数据库 |
| onLoadResource() | 加载指定Url地址提供的资源 |
| onFormResubmission() | 应用程序重新请求网页数据 |
| onScaleChanged() | WebView发生改变 |
2.5 WebChromeClient类
对于网页中一般的Javascript都可以被WebView加载执行了。但是某些特殊的Javascript语句依然无法执行。例如Javascript语句中的Alert、Confirm、Prompt等对话框。为了解决这个问题,要借助WebChromeClient类。WebChromeClient类专门用来辅助WebView处理Javascript的对话框、网站图标、网站Title、加载进度等。
| 方法 | 描述 |
|---|---|
| onJsAlert() | 处理Javascript中Alert对话框 |
| onJsConfirm() | 处理Javascript中Confirm对话框 |
| onJsPrompt() | 处理Javascript中Prompt对话框 |
| onProgressChanged() | 加载进度条改变 |
| onCloseWindow() | 关闭WebView |
| onCreateWindow() | 创建WebView |
| onReceivedIcon() | Icon图标改变 |
| onReceivedTitle() | 网页Title改变 |
| onRequestFocus() | WebView显示焦点 |
3. Android 和Js的交互
在实际开发过程中,Android与Js的交互都是通过WebView来完成的。WebView是二者之间的桥梁。
Android 调用Js的代码
Js调用Android的代码

3.1 Android 调用JS的代码
我们是做安卓开发的,所以在实际的开发过程中,有h5的人会写好对应的方法,然后我们只需要根据它提供给我们的方法,调起js的代码就可以了。这里写一个例子来说明一下。
![]() 调用JS前 |
调用JS后 |
|---|
1.首先在一个布局文件中有这样两个控件。activity_main2.xml.一个Button,一个WebView
<?xml versi encoding 'utf-8'?><LinearLayout xmlns:android='http://schemas.android.com/apk/res/android'
android:layout_width='match_parent'
android:layout_height='match_parent'
android:orientati> <Button
android:id='@+id/button'
android:layout_width='match_parent'
android:layout_height='50dp'
android:text='@string/btn_click'
/>
<WebView
android:id='@+id/webView'
android:layout_width='match_parent'
android:layout_height='match_parent'/></LinearLayout>
2.接下来在assert文件下创建一个html文件。(创建asserts文件,main->New->Folder->Asserts Folder),(创建html文件,可以自己创建一个File文件,然后后缀加上 login.html)
<!DOCTYPE html><html><head>
<meta charset='utf-8'>
<title>Carson_Ho</title>
<script>
function callJS(){
alert('Android调用了JS的callJS方法');
}</script></head></html>
3.接下来就是对布局的一些处理,上图的逻辑很简单,我们在点击按钮的时候出发弹窗,然后根据弹窗吊起Js。
public class Main2Activity extends AppCompatActivity {
WebView mWebView;
Button button; @Override
protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
mWebView =(WebView) findViewById(R.id.webView);
WebSettings webSettings = mWebView.getSettings(); // 设置与Js交互的权限
webSettings.setJavaScriptEnabled(true); // 设置允许JS弹窗
webSettings.setJavaScriptCanOpenWindowsAutomatically(true); // 先载入JS代码
// 格式规定为:file:///android_asset/文件名.html
mWebView.loadUrl('file:///android_asset/login.html');
butt findViewById R.id.button);
button.setOnClickListener(new View.OnClickListener() { @Override
public void onClick(View v) { // 通过Handler发送消息
mWebView.post(new Runnable() { @Override
public void run() { // 注意调用的JS方法名要对应上
// 调用javascript的callJS()方法
mWebView.loadUrl('callJS()');
}
});
}
}); // 由于设置了弹窗检验调用结果,所以需要支持js对话框
// webview只是载体,内容的渲染需要使用webviewChromClient类去实现
// 通过设置WebChromeClient对象处理JavaScript的对话框
//设置响应js 的Alert()函数
mWebView.setWebChromeClient(new WebChromeClient() { @Override
public boolean onJsAlert(WebView view, String url, String message, final JsResult result) {
AlertDialog.Builder b = new AlertDialog.Builder(Main2Activity.this);
b.setTitle('Alert');
b.setMessage(message);
b.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { @Override
public void onClick(DialogInterface dialog, int which) {
result.confirm();
}
});
b.setCancelable(false);
b.create().show(); return true;
}
});
}
}
【注意】永远不要阻塞UI线程,这是开发Android程序的一个真理。虽然是真理,我们却往往不自觉的犯一些错误违背它,一个开发中常犯的错误就是:在UI线程中去等待JavaScript 的回调。Android 4.4中,提供了新的Api来做这件事情。evaluateJavascript() 就是专门来异步执行JavaScript代码的。专门用于异步调用JavaScript方法,并且能够得到一个回调结果。
| 调用方式 | 优点 | 缺点 | 使用场景 |
|---|---|---|---|
| 使用loadUrl() | 方便简洁 | 效率低;无返回值 | 无需返回值,对性能要求低 |
| 使用evaluateJavascript() | 效率高 | 向下兼容差(4.4以上) | Android 4.4以上 |
mWebView.evaluateJavascript(script, new ValueCallback<String>() { @Override
public void onReceiveValue(String value) { //返回Js的结果
}
});
修改代码,既兼容4.4以上,有包括4.4以下
button.setOnClickListener(new View.OnClickListener() { @RequiresApi(api = Build.VERSION_CODES.KITKAT) @Override
public void onClick(View v) { if(Build.VERSION.SDK_INT<19){
mWebView.post(new Runnable() { @Override
public void run() {
mWebView.loadUrl('callJS()');
}
});
}else{ //已经是异步了,无需再开下线程了
mWebView.evaluateJavascript('callJS()', new ValueCallback<String>() { @Override
public void onReceiveValue(String s) {
Log.e(TAG, 'onReceiveValue: '+s );
}
});
}
}
});
3.2 JS调用安卓的代码
在安卓实际开发过程中,JS的一些代码,也可以调用安卓的功能。方法有以下三种:
3.2.1 通过WebView的addJavascriptInterface()进行对象映射
具体的方法:
1.定义一个与JS对象映射关系的Android类,然后定义一个JS需要调用的方法
public class Main3JS extends Object { // 定义JS需要调用的方法
// 被JS调用的方法必须加入@JavascriptInterface注解
@JavascriptInterface
public void ToJs(String msg){
Log.e('tag','JS调用Android的代码');
}
}
2.编写一个html文件,registe.html。定义一个test对象,然后调用Android 映射的对象,最后在点击按钮的时候,其实就是在调用callAndroid()这个函数。
<!DOCTYPE html><html><head>
<meta charset='utf-8'>
<title></title>
<script>
function callAndroid(){ // 由于对象映射,所以调用test对象等于调用Android映射的对象
test.ToJs('js调用了android中的ToJs方法');
}</script></head><body><button type='button' id='button1' > JS点击调用安卓的代码</button></body></html>
3.新建一个Main3Activity文件,布局里面只有一个webView。设置加载JS的方法,然后调用addJavascriptInterface()这个方法,将第一步的Main3J类带入,然后是第二个test对象。
public class Main3Activity extends AppCompatActivity {
WebView mWebView; @Override
protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main3);
mWebView = (WebView) findViewById(R.id.WebView);
WebSettings webSettings = mWebView.getSettings(); // 设置与Js交互的权限
webSettings.setJavaScriptEnabled(true); // 通过addJavascriptInterface()将Java对象映射到JS对象
//参数1:Javascript对象名
//参数2:Java对象名
mWebView.addJavascriptInterface(new Main3JS(this), 'test');//AndroidtoJS类对象映射到js的test对象
// 加载JS代码
// 格式规定为:file:///android_asset/文件名.html
mWebView.loadUrl('file:///android_asset/registe.html');
}
}
最后结果如上图所示。这种方法使用简单,仅将Android对象和JS对象映射即可。但是存在数据泄露的风险。
3.2.2 通过 WebViewClient 的方法shouldOverrideUrlLoading ()回调拦截 url
回调拦截url的原理很简单,Android 通过WebViewClient的回调方法shouldOverrideUrlLoading ()拦截 url,然后解析url,根据设定的url协议调用不同的方法。
具体步骤
1.编写一个html文件,定义一个协议。当Js通过Android 的加载的协议后,就会回调shouldOverrideUrlLoading ()方法。
<!DOCTYPE html><html><head>
<meta charset='utf-8'>
<title></title>
<script>
function callAndroid(){ //定义协议
document.locati;
}</script></head><body><button type='button' id='button1' > JS点击调用安卓的代码</button></body></html>
2.在Main4Activity 中定义webView,然后加载协议,最后调用webview的shouldOverrideUrlLoading ()方法。根据js.html的定义的协议格式:根据scheme(协议格式) & authority(协议名)判断(前两个参数)进行判断。
public class Main4Activity extends AppCompatActivity { private WebView webView; @Override
protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main4);
webView = (WebView) findViewById(R.id.webView);
WebSettings webSettings= webView.getSettings(); //设置加载JS权限
webSettings.setJavaScriptEnabled(true); //设置允许JS弹窗
webSettings.setJavaScriptCanOpenWindowsAutomatically(true); //加载file文件
webView.loadUrl('file:///android_asset/sencodJs.html');
webView.setWebViewClient(new WebViewClient(){ // 一般根据scheme(协议格式) & authority(协议名)判断(前两个参数)
// 'js://webview?locati> @Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
Uri uri = Uri.parse(url); //如果url的协议 = 预先约定的 js 协议
if(uri.getScheme().equals('js')){ // 如果 authority = 预先约定协议里的 webview,即代表都符合约定的协议
if(uri.getAuthority().equals('webview')){ // 执行JS所需要调用的逻辑
System.out.println('js调用了Android的方法'); // 可以在协议上带有参数并传递到Android上// HashMap<String, String> params = new HashMap<>();// Set<String> collecti> AlertDialog.Builder mBuilder= new AlertDialog.Builder(Main4Activity.this);
mBuilder.setTitle('Alert');
mBuilder.setMessage('JS要调用Android的代码');
mBuilder.setCancelable(true);
mBuilder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { @Override
public void onClick(DialogInterface dialogInterface, int i) {
dialogInterface.dismiss();
}
});
mBuilder.create().show();
} return true;
} return super.shouldOverrideUrlLoading(view, url);
}
});
}
}
通过解析协议里面的值来进行调用android里面的代码。这样可以避免数据邪路的风险,但是返回数据麻烦。当用户点击webview中的网页链接的时候,安卓系统默认会启动一个新的应用专门成立url的跳转。如果希望点击链接继续在当前webview中响应,而不是新开Android的系统browser中响应该链接,必须覆盖 WebView的WebViewClient对象. 并重写shouldOverrideUrlLoading方法。
3.2.3 通过 WebChromeClient 的onJsAlert()、onJsConfirm()、onJsPrompt()方法回调拦截JS对话框alert()、confirm()、prompt() 消息
| 方法 | 作用 | 返回值 | 备注 |
|---|---|---|---|
| alert() | 弹出警告框 | 无 | 在文本中加入\n可换行 |
| confirm() | 弹出确认框 | 两个 | 返回布尔值(true,false) |
| prompt() | 弹出输入框 | 任意设置返回值 | 确认:返回输入框中的值;取消返回null |
具体方法
1.首先在three.html中设置点击按钮和调用的js方法
<!DOCTYPE html><html><head>
<meta charset='utf-8'>
<title>Carson_Ho</title>
<script>
function clickprompt(){ // 调用prompt()
var result=prompt('js://webview?arg1=111&arg2=222');
alert('demo ' + result);
} </script></head><!-- 点击按钮则调用clickprompt() --><body><button type='button' id='button1' > 点击调用Android代码</button></body></html>
2.然后在Main5Activity方法中,自顶一个WebView,然后调用WebView的WebChromeClient(),重写里面的回调拦截方法
public class Main5Activity extends AppCompatActivity { private WebView webView; @Override
protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main5);
webView = (WebView) findViewById(R.id.webView);
WebSettings webSettings=webView.getSettings();
webSettings.setJavaScriptEnabled(true);
webSettings.setJavaScriptCanOpenWindowsAutomatically(true);
webView.loadUrl('file:///android_asset/three.html');
webView.setWebChromeClient(new WebChromeClient(){ @Override
public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result) {
Uri uri = Uri.parse(message); if (uri.getScheme().equals('js')) { if (uri.getAuthority().equals('webview')) {
System.out.println('js调用了Android的方法'); // 可以在协议上带有参数并传递到Android上
HashMap<String, String> params = new HashMap<>();
Set<String> collecti //参数result:代表消息框的返回值(输入值)
result.confirm('js调用了Android的方法成功啦');
} return true;
} return super.onJsPrompt(view, url, message, defaultValue, result);
} @Override
public boolean onJsAlert(WebView view, String url, String message, JsResult result) { return super.onJsAlert(view, url, message, result);
} @Override
public boolean onJsConfirm(WebView view, String url, String message, JsResult result) { return super.onJsConfirm(view, url, message, result);
}
});
}
}
![]() 调用前 | ![]() 调用后 |
|---|
github地址:https://github.com/wangxin3119/MyWebViewDemo









































苏公安网备 32011402010933号