一 简介 1 WEBView是用来展示网页的控件,底层是Google的WebKit的引擎。 比起苹果的WebView,webkit一些不足地方: 不能支持Word等文件的预览纯标签加载,并不支持所有标签的加载不支持文件的下载,图片的放大
一 简介
1 WEBView是用来展示网页的控件,底层是Google的WebKit的引擎。
比起苹果的WebView,webkit一些不足地方:
- 不能支持Word等文件的预览
- 纯标签加载,并不支持所有标签的加载
- 不支持文件的下载,图片的放大,都要单独处理
2 其它Web引擎,腾讯的webx5,其功能比WebKit要强大些,支持常见文件格式的预览(word文档,excel表格等),还支持文件的下载。
官方地址: https://x5.tencent.com/tbs/
3 WebView大部分场合还是能满足需求的,用官方Webkit就可以了
二 WebView的使用
1 初始化webview组件
xml里面初始化
获取动态初始化
WebView webView = new WebView(this);llWebview.addView(webView);
2 配置WebSettings
//声明WebSettings子类WebSettings webSettings = webView.getSettings();//如果访问的页面中要与javascript交互,则webview必须设置支持JavascriptwebSettings.setJavaScriptEnabled(true); //支持插件webSettings.setPluginsEnabled(true); //设置自适应屏幕,两者合用webSettings.setUseWideViewPort(true); //将图片调整到适合webview的大小 webSettings.setLoadWithOverviewMode(true); // 缩放至屏幕的大小//缩放操作webSettings.setSupportZoom(true); //支持缩放,默认为true。是下面那个的前提。webSettings.setBuiltInZoomControls(true); //设置内置的缩放控件。若为false,则该WebView不可缩放webSettings.setDisplayZoomControls(false); //隐藏原生的缩放控件//其他细节操作webSettings.setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK); //关闭webview中缓存 webSettings.setAllowFileAccess(true); //设置可以访问文件 webSettings.setJavaScriptCanOpenwindowsAutomatically(true); //支持通过js打开新窗口 webSettings.setLoadsImagesAutomatically(true); //支持自动加载图片webSettings.setDefaultTextEncodingName("utf-8");//设置编码格式
3 加载网页链接或加载标签
加载网页链接
//加载Http链接:http://www.google.com///加载assets链接:file:///Android_asset/test.html//加载本地存储链接:http://www.google.com/webView.loadUrl("http://www.google.com/");
加载标签
String goods_content="我的第一个段落。
";webView.loadDataWitHBaseURL(null, WebUtil.getHtmlData(goods_content), "text/html", "utf-8", null);public static String getHtmlData(String bodyHTML) {String head = "" +" " +"" +"";return "" + head + "" + bodyHTML + "";}
4 设置WebViewClient,来处理通知和请求事件
常规用法,复写shouldOverrideUrlLoading()方法,使得打开网页时不调用系统浏览器, 而是在本WebView中显示
webView.setWebViewClient(new WebViewClient(){ @Override public boolean shouldOverrideUrlLoading(WebView view, String url) { view.loadUrl(url); return true; }});
完整用法
webViewClient = new WebViewClient() { @Overridepublic boolean shouldOverrideUrlLoading(WebView view, String url) {if (Uri.parse(url).getHost().equals("www.baidu.com")) {Intent intent = new Intent(Intent.ACTioN_VIEW, Uri.parse(url));intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);context.startActivity(intent);return true;}return false;}@Overridepublic void onPageStarted(WebView view, String url, Bitmap favicon) {// TODO Auto-generated method stubsuper.onPageStarted(view, url, favicon);Log.i(TAG, "onPageStarted:页面开始加载");}@Overridepublic void onPageFinished(WebView view, String url) {// TODO Auto-generated method stubsuper.onPageFinished(view, url);Log.i(TAG, "onPageStarted:页面加载结束");}@Overridepublic void onLoadResource(WebView view, String url) {// TODO Auto-generated method stubsuper.onLoadResource(view, url);Log.i(TAG, "onLoadResource:加载资源指定的网址");}@Overridepublic WebResourceResponse shouldInterceptRequest(WebView view, String url) {// TODO Auto-generated method stubLog.i(TAG, "shouldInterceptRequest");return super.shouldInterceptRequest(view, url);}@Overridepublic void onReceivedError(WebView view, int errorCode,String description, String failingUrl) {// TODO Auto-generated method stubsuper.onReceivedError(view, errorCode, description, failingUrl);view.loadUrl("file:///android_asset/error.html");Log.i(TAG, "onReceivedError");}@Overridepublic void onFORMResubmission(WebView view, Message dontResend,Message resend) {// TODO Auto-generated method stubsuper.onFormResubmission(view, dontResend, resend);Log.i(TAG, "onFormResubmission");}@Overridepublic void doUpdateVisitedHistory(WebView view, String url,boolean isReload) {// TODO Auto-generated method stubsuper.doUpdateVisitedHistory(view, url, isReload);Log.i(TAG, "doUpdateVisitedHistory");}@Overridepublic void onReceivedSslError(WebView view, SslErrorHandler handler,SslError error) {// view.loadUrl("file:///android_asset/error.html");// TODO Auto-generated method stubsuper.onReceivedSslError(view, handler, error);Log.i(TAG, "onReceivedSslError");}@Overridepublic void onReceivedHttpAuthRequest(WebView view,HttpAuthHandler handler, String host, String realm) {// TODO Auto-generated method stubsuper.onReceivedHttpAuthRequest(view, handler, host, realm);Log.i(TAG, "onReceivedHttpAuthRequest");}@Overridepublic boolean shouldOverrideKeyEvent(WebView view, KeyEvent event) {Log.i(TAG, "shouldOverrideKeyEvent");// TODO Auto-generated method stubreturn super.shouldOverrideKeyEvent(view, event);}@Overridepublic void onScaleChanged(WebView view, float oldScale, float newScale) {// TODO Auto-generated method stubsuper.onScaleChanged(view, oldScale, newScale);Log.i(TAG, "onScaleChanged");}@Overridepublic void onReceivedLoginRequest(WebView view, String realm,String account, String args) {// TODO Auto-generated method stubsuper.onReceivedLoginRequest(view, realm, account, args);Log.i(TAG, "onReceivedLoginRequest"); }});
5 设置WebChromeClient,辅助WebVlew处理/avascrlpt的对话框,网站图标,网站tltle,加载进度等
常规用法,加载页面缓冲进度
webView.setWebChromeClient(new WebChromeClient() {@Overridepublic void onProgressChanged(WebView view, int newProgress) {if (newProgress >=80) {llView.setVisibility(View.GONE);} else {llView.setVisibility(View.VISIBLE);}super.onProgressChanged(view, newProgress);}});
完整用法
webView.setWebChromeClient(new WebChromeClient() {@Overridepublic void onProgressChanged(WebView view, int newProgress) {// TODO Auto-generated method stubsuper.onProgressChanged(view, newProgress);if (newProgress <= 100) {Log.i(TAG, newProgress + "===onProgressChanged===");}}@Overridepublic void onReceivedTitle(WebView view, String title) {// TODO Auto-generated method stubsuper.onReceivedTitle(view, title);Message message = new Message();message.what = 100;message.obj = title;handler.sendMessage(message); }@Overridepublic void onReceivedIcon(WebView view, Bitmap icon) {// TODO Auto-generated method stubsuper.onReceivedIcon(view, icon);Message message = new Message();message.what = 200;message.obj = icon;handler.sendMessage(message);}@Overridepublic void onReceivedTouchIconUrl(WebView view, String url,boolean precomposed) {// TODO Auto-generated method stubsuper.onReceivedTouchIconUrl(view, url, precomposed);Log.i(TAG, "====onReceivedTouchIconUrl====");} @Overridepublic void onRequestFocus(WebView view) {// TODO Auto-generated method stubsuper.onRequestFocus(view);Log.i(TAG, "====onRequestFocus====");}@Overridepublic boolean onJsAlert(final WebView view, String url, String message,JsResult result) {final AlertDialog.Builder builder = new AlertDialog.Builder(view.getContext()); builder.setTitle("对话框").setMessage(message).setPositiveButton("确定", null);builder.setOnKeyListener(new OnKeyListener() {public boolean onKey(DialogInterface dialog, int keyCode,KeyEvent event) {Log.v("onJsAlert", "keyCode==" + keyCode + "event=" + event);return true;}});// 禁止响应按back键的事件builder.setCancelable(false);AlertDialog dialog = builder.create();dialog.show();result.confirm();// 因为没有绑定事件,需要强行confirm,否则页面会变黑显示不了内容。return true;// return super.onJsAlert(view, url, message, result);}@Overridepublic boolean onJsConfirm(final WebView view, String url, String message,final JsResult result) {final AlertDialog.Builder builder = new AlertDialog.Builder(view.getContext());builder.setTitle("对话框").setMessage(message).setPositiveButton("确定", new OnClickListener() {public void onClick(DialogInterface dialog, int which) {result.confirm();}}).setNeutralButton("取消", new OnClickListener() {public void onClick(DialogInterface dialog, int which) {result.cancel();}});builder.setOnCancelListener(new OnCancelListener() {@Overridepublic void onCancel(DialogInterface dialog) {result.cancel();}}); // 屏蔽keycode等于84之类的按键,避免按键后导致对话框消息而页面无法再弹出对话框的问题builder.setOnKeyListener(new OnKeyListener() {@Overridepublic boolean onKey(DialogInterface dialog, int keyCode,KeyEvent event) {Log.v("onJsConfirm", "keyCode==" + keyCode + "event=" + event);return true;}});// 禁止响应按back键的事件// builder.setCancelable(false);AlertDialog dialog = builder.create();dialog.show();return true;}@Overridepublic boolean onJsPrompt(WebView view, String url, String message,String defaultValue, final JsPromptResult result) {final AlertDialog.Builder builder = new AlertDialog.Builder(view.getContext()); builder.setTitle("对话框").setMessage(message); final EditText et = new EditText(view.getContext());et.setSingleLine();et.setText(defaultValue);builder.setView(et).setPositiveButton("确定", new OnClickListener() {public void onClick(DialogInterface dialog, int which) {result.confirm(et.getText().toString());} }).setNeutralButton("取消", new OnClickListener() {public void onClick(DialogInterface dialog, int which) {result.cancel();}}); // 屏蔽keycode等于84之类的按键,避免按键后导致对话框消息而页面无法再弹出对话框的问题builder.setOnKeyListener(new OnKeyListener() {public boolean onKey(DialogInterface dialog, int keyCode,KeyEvent event) {Log.v("onJsPrompt", "keyCode==" + keyCode + "event=" + event);return true;}}); // 禁止响应按back键的事件// builder.setCancelable(false);AlertDialog dialog = builder.create();dialog.show();return true;// return super.onJsPrompt(view, url, message, defaultValue,// result);}});
6 Android调用JS
添加网络权限
编写html文件,放到assets文件里面
function say(value){ callJS(value); }
java文件,android调用js
public class MainActivity extends AppCompatActivity { private WebView webview; private TextView tvAndroid; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); webview = (WebView) findViewById(R.id.webview); tvAndroid = (TextView) findViewById(R.id.tv_android); tvAndroid.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { //Android调用js方法 //Android 4.4以下使用loadUrl,Android 4.4以上evaluateJavascript if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR2) { webview.loadUrl("javascript:callJS('aaa')"); } else { webview.evaluateJavascript("javascript:callJS('aaa')", new ValueCallback() { @Override public void onReceiveValue(String value) {//此处为 js 返回的结果Toast.makeText(MainActivity.this,value,Toast.LENGTH_SHORT).show(); } }); } } }); initWebView(); } public void initWebView() { //启用JS脚本 webview.getSettings().setJavaScriptEnabled(true); // 设置允许JS弹窗 webview.getSettings().setJavaScriptCanOpenWindowsAutomatically(true); //加载网页 webview.loadUrl("file:///android_asset/index.html"); // 由于设置了弹窗检验调用结果,所以需要支持js对话框 // webview只是载体,内容的渲染需要使用webviewChromClient类去实现 // 通过设置WebChromeClient对象处理JavaScript的对话框 //设置响应js 的Alert()函数 webview.setWebChromeClient(new WebChromeClient(){ @Override public boolean onJsAlert(WebView view, String url, String message, JsResult jsResult) { new AlertDialog.Builder(view.getContext()).setMessage(message).setPositiveButton(android.R.string.ok, new AlertDialog.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { jsResult.confirm(); } }).setCancelable(false).create().show(); return true; } }); //覆盖WebView默认使用第三方或系统默认浏览器打开网页的行为,使网页用WebView打开 webview.setWebViewClient(new WebViewClient() { //override public void onReceivedHttpAuthRequest(WebView view, HttpAuthHandler handler, String host, String realm) { handler.proceed("admin", "sunlight"); int d = Log.d("MyWebViewClient", "onReceivedHttpAuthRequest"); } @Override public boolean shouldOverrideUrlLoading(WebView view, String uri) { // TODO Auto-generated method stub //返回值是true的时候控制去WebView打开,为false调用系统浏览器或第三方浏览器 view.loadUrl(uri); return true; } }); }}
效果
注意:
- 启用JS脚本 webview.getSettings().setJavaScriptEnabled(true);
- 设置允许JS弹窗webview.getSettings().setJavaScriptCanOpenWindowsAutomatically(true);
- 4.4以下通过WebView的loadUrl(),4.4以上通过WebView的evaluateJavascript()
- JS代码调用一定要在 onPageFinished() 回调之后才能调用,否则不会调用
7 js调用android方法
方法一:通过WebView的addJavascriptInterface()进行对象映射
html文件
java文件
package com.serial.jsweview;import android.os.Build;import android.os.Bundle;import android.view.View;import android.webkit.JavascriptInterface;import android.webkit.ValueCallback;import android.webkit.WebView;import android.widget.TextView;import android.widget.Toast;import androidx.appcompat.app.AppCompatActivity;public class MainActivity2 extends AppCompatActivity { private WebView webview; private TextView tvAndroid; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main2); webview = (WebView) findViewById(R.id.webview); tvAndroid = (TextView) findViewById(R.id.tv_android); tvAndroid.setText("//继承自Object类,别名是aa,即在html可以直接用aa.showToast(\"哈哈哈\")来调用android方法\n" + "public class MyObject extends Object {\n" + " @JavascriptInterface\n" + " public void showToast(String name){\n" + " Toast.makeText(MainActivity2.this, \"您好!\"+name, Toast.LENGTH_SHORT).show();\n" + " }\n" + "}"); initWebView(); } public void initWebView() { // 设置与Js交互的权限 webview.getSettings().setJavaScriptEnabled(true); //将java对象暴露给JavaScript脚本 //参数1:java对象,里面定义了java方法 //参数2:Java对象在js里的对象名,可以看作第一个参数的别名,可以随便取,即在html可以直接用aa.showToast("哈哈哈")来调用android方法 webview.addJavascriptInterface(new MyObject(), "aa");//AndroidtoJS类对象映射到js的test对象 //加载网页 webview.loadUrl("file:///android_asset/index2.html"); } //继承自Object类,别名是aa,即在html可以直接用aa.showToast("哈哈哈")来调用android方法 public class MyObject extends Object { // 定义JS需要调用的方法 // 被JS调用的方法必须加入@JavascriptInterface注解 @JavascriptInterface public void showToast(String name){ Toast.makeText(MainActivity2.this, "您好!"+name, Toast.LENGTH_SHORT).show(); } }}
方法二:通过 WebViewClient 的shouldOverrideUrlLoading ()方法回调拦截 url
原理:
- Android通过 WebViewClient 的回调方法shouldOverrideUrlLoading ()拦截 url
- 解析该 url 的协议
- 如果检测到是预先约定好的协议,就调用相应方法
html文件
java文件
public class MainActivity3 extends AppCompatActivity { private WebView webview; private TextView tvAndroid; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main2); webview = (WebView) findViewById(R.id.webview); tvAndroid = (TextView) findViewById(R.id.tv_android); initWebView(); } public void initWebView() { // 设置与Js交互的权限 webview.getSettings().setJavaScriptEnabled(true); // 设置允许JS弹窗 webview.getSettings().setJavaScriptCanOpenWindowsAutomatically(true); //步骤1:加载网页 webview.loadUrl("file:///android_asset/index3.html"); // 复写WebViewClient类的shouldOverrideUrlLoading方法 webview.setWebViewClient(new WebViewClient() { @Override public boolean shouldOverrideUrlLoading(WebView view, String url) { // 步骤2:根据协议的参数,判断是否是所需要的url // 一般根据scheme(协议格式) & authority(协议名)判断(前两个参数) //假定传入进来的 url = "js://webview?arg1=111&arg2=222"(同时也是约定好的需要拦截的) Uri uri = Uri.parse(url); // 如果url的协议 = 预先约定的 js 协议 // 就解析往下解析参数 if ( uri.getScheme().equals("js")) { // 如果 authority = 预先约定协议里的 webview,即代表都符合约定的协议 // 所以拦截url,下面JS开始调用Android需要的方法 if (uri.getAuthority().equals("webview")) { // 步骤3: // 执行JS所需要调用的逻辑 Toast.makeText(MainActivity3.this, "您好!js调用了Android的方法", Toast.LENGTH_SHORT).show(); // 可以在协议上带有参数并传递到Android上 HashMap params = new HashMap<>(); Set collection = uri.getQueryParameterNames(); } return true; } return super.shouldOverrideUrlLoading(view, url); } } ); }}
效果
方法三:通过 WebChromeClient 的onJsAlert()、onJsConfirm()、onJsPrompt()方法回调拦截JS对话框alert()、confirm()、prompt()消息
原理:
- Android通过 WebChromeClient 的onJsAlert()、onJsConfirm()、onJsPrompt()方法回调分别拦截JS对话框,得到他们的消息内容,然后解析即可。比如拦截 JS的输入框prompt()方法
- 因为只有prompt()可以返回任意类型的值,操作最全面方便、更加灵活;
- 而alert()对话框没有返回值;confirm()对话框只能返回两种状态(确定 / 取消)两个值
html文件
当使用mWebView.loadUrl("file:///android_asset/javascript.html")加载了上述JS代码后,就会触发回调onJsPrompt(),具体如下:
如果是拦截警告框,即alert(),则触发回调onJsAlert();
如果是拦截确认框,即confirm(),则触发回调onJsConfirm();
java文件
package com.serial.jsweview;import android.net.Uri;import android.os.Bundle;import android.webkit.JsPromptResult;import android.webkit.JsResult;import android.webkit.WebChromeClient;import android.webkit.WebView;import android.webkit.WebViewClient;import android.widget.TextView;import android.widget.Toast;import androidx.appcompat.app.AppCompatActivity;import java.util.HashMap;import java.util.Set;public class MainActivity4 extends AppCompatActivity { private WebView webview; private TextView tvAndroid; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main4); webview = (WebView) findViewById(R.id.webview); tvAndroid = (TextView) findViewById(R.id.tv_android); initWebView(); } public void initWebView() { // 设置与Js交互的权限 webview.getSettings().setJavaScriptEnabled(true); // 设置允许JS弹窗 webview.getSettings().setJavaScriptCanOpenWindowsAutomatically(true); webview.loadUrl("file:///android_asset/index4.html"); webview.setWebChromeClient(new WebChromeClient() { // 拦截输入框(原理同方式2) // 参数message:代表promt()的内容(不是url) // 参数result:代表输入框的返回值 @Override public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result) { // 根据协议的参数,判断是否是所需要的url(原理同方式2) // 一般根据scheme(协议格式) & authority(协议名)判断(前两个参数) //假定传入进来的 url = "js://webview?arg1=111&arg2=222"(同时也是约定好的需要拦截的) Uri uri = Uri.parse(message); // 如果url的协议 = 预先约定的 js 协议 // 就解析往下解析参数 if (uri.getScheme().equals("js")) { // 如果 authority = 预先约定协议里的 webview,即代表都符合约定的协议 // 所以拦截url,下面JS开始调用Android需要的方法 if (uri.getAuthority().equals("webview")) {//// 执行JS所需要调用的逻辑System.out.println("js调用了Android的方法");// 可以在协议上带有参数并传递到Android上HashMap params = new HashMap<>();Set collection = uri.getQueryParameterNames();//参数result:代表消息框的返回值(输入值)result.confirm("js调用了Android的方法成功啦"); } return true; } return super.onJsPrompt(view, url, message, defaultValue, result); } // 拦截JS的警告框 @Override public boolean onJsAlert(WebView view, String url, String message, JsResult result) { return super.onJsAlert(view, url, message, result); } // 拦截JS的确认框 @Override public boolean onJsConfirm(WebView view, String url, String message, JsResult result) { return super.onJsConfirm(view, url, message, result); } } ); }}
效果
总结:
JS调用Android代码的方法有3种:
- 通过WebView的addJavascriptInterface()进行对象映射,存在安全漏洞
- 通过 WebViewClient 的shouldOverrideUrlLoading ()方法回调拦截 url,不存在1的漏洞,但JS获取Android方法的返回值复杂
- 通过 WebChromeClient 的onJsAlert()、onJsConfirm()、onJsPrompt()方法回调拦截JS对话框alert()、confirm()、prompt() 消息。不存在漏洞,需要协议的约定
8 页面返回
@Overridepublic boolean onKeyDown(int keyCode, KeyEvent event) { if ((keyCode == KeyEvent.KEYCODE_BACK) && myWebView.canGoBack()) { myWebView.goBack(); return true; } return super.onKeyDown(keyCode, event);}
9 缓存的配置
WebSettings webSettings = mWebView.getSettings();//优先使用缓存webSettings.setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK); //只在缓存中读取webSettings.setCacheMode(WebSettings.LOAD_CACHE_ONLY);/不使用缓存WwebSettings.setCacheMode(WebSettings.LOAD_NO_CACHE);
10 清除缓存
//清除网页访问留下的缓存,由于内核缓存是全局的因此这个方法不仅仅针对webview而是针对整个应用程序.webview.clearCache(true);//清除当前webview访问的历史记录,只会webview访问历史记录里的所有记录除了当前访问记录.webview.clearHistory (); //这个api仅仅清除自动完成填充的表单数据,并不会清除WebView存储到本地的数据。webview.clearFormData ();
10 webview生命周期
onResume()
WebView为活跃状态时回调,可以正常执行网页的响应。onPause()
WebView被切换到后台时回调, 页面被失去焦点, 变成不可见状态,onPause动作通知内核暂停所有的动作,比如DOM的解析、plugin的执行、JavaScript执行。pauseTimers()
当应用程序被切换到后台时回调,该方法针对全应用程序的WebView,它会暂停所有webview的layout,parsing,javascripttimer。降低CPU功耗。resumeTimers()
恢复pauseTimers时的动作。destroy()
关闭了Activity时回调, WebView调用destory时, WebView仍绑定在Activity上.这是由于自定义WebView构建时传入了该Activity的context对象, 因此需要先从父
容器中移除WebView, 然后再销毁webview。
mRootLayout.removeView(webView);
mWebView.destroy();
跟随Activity的生命周期
@Overrideprotected void onResume() { super.onResume(); //恢复webview的状态(不靠谱) webView.resumeTimers(); //激活webView的状态,能正常加载网页 webView.onResume();}@Overrideprotected void onPause() { super.onPause(); //当页面被失去焦点被切换到后台不可见状态,需要执行onPause //通过onPause动作通知内核暂停所有的动作,比如DOM的解析、plugin的执行、JavaScript执行。 webView.onPause(); //当应用程序(存在webview)被切换到后台时,这个方法不仅仅针对当前的webview而是全局的全应用程序的webview //它会暂停所有webview的layout,parsing,javascripttimer。降低CPU功耗。(不靠谱) webView.pauseTimers();}@Overrideprotected void onDestroy() {super.onDestroy();//在关闭了Activity时,如果Webview的音乐或视频,还在播放。就必须销毁Webview//但是注意:webview调用destory时,webview仍绑定在Activity上//这是由于自定义webview构建时传入了该Activity的context对象//因此需要先从父容器中移除webview,然后再销毁webview:ViewGroup parent = findViewById(R.id.container);parent.removeView(webView);webView.destroy();}
三 防止内存泄漏的注意点
1 在需要的时候在 Activity 中创建,并且使用 getApplicationGContext(),而不要在xml注册。
//mWebView=new WebView(this);mWebView=new WebView(getApplicationContext());LinearLayout linearLayout = findViewById(R.id.xxx);linearLayout.addView(mWebView);
2 并且Activity退出的时候,需要手动释放webview内存
@Overrideprotected void onDestroy() { if (mWebView != null) { mWebView.loadDataWithBaseURL(null, "", "text/html", "utf-8", null); mWebView.clearHistory(); ((ViewGroup) mWebView.getParent()).removeView(mWebView); mWebView.destroy(); mWebView = null; } super.onDestroy();}
3 尽量不要在webview里面开启新进程
比如下面这种
四 其它web框架的选择
1 webview大部分场合是没问题的,但涉及到文件下载,文档浏览等只能自己写js交互,处理相对麻烦。所以也有其它web框架供我们选择
2 第一个就是开头提过的腾讯webx5,相对来说比较强大,但可能个别手机会出现兼容问题
官方网址:https://x5.tencent.com/tbs/
3 还有GitHub常用的webview库,内置文件的处理功能,和加载缓冲样式,也可以直接代替webview
项目地址:https://github.com/Justson/AgentWeb
4 还有专门处理JS交互的一个库DSBridge,分为webx5内核版本和webkit内核版本
项目地址:https://github.com/wendux/DSBridge-Android
使用中webx5内核版本由于规则定义不符合我们要求,而且不能改,就换用了webkit内核版本,目前没出现什么问题
五 手机加载网页空白问题解决方案
1 网页加载空白原因有很多,遇到的可以尝试下面方案,第一个就是联网权限没配置,配置下权限
2 https的ssl证书问题
WebView().setWebViewClient(new WebViewClient(){@Overridepublic void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {handler.proceed();}});
3 尝试加载DOM缓存
webView.getSettings().setDomStorageEnabled(true);
4 Android5.0以上允许加载http和https混合的页面
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { webView.getSettings().setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW);}
5 如果上面尝试都不行,那就有可能不是Webview配置问题,可能是内核版本较低,对于高版本的Web或者JS语法不支持。
如es6经过尝试在Androd6.0系统上会空白,而且切换腾讯Webx5内核也不行。这时候只能让web前端es6转为es5了
即可以尝试h5做低版本适配,ES6转化为ES5的方案
来源地址:https://blog.csdn.net/qq_29848853/article/details/130368448
--结束END--
本文标题: Android之 WebView的使用
本文链接: https://www.lsjlt.com/news/404288.html(转载时请注明来源链接)
有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341
下载Word文档到电脑,方便收藏和打印~
2024-01-21
2023-10-28
2023-10-28
2023-10-27
2023-10-27
2023-10-27
2023-10-27
回答
回答
回答
回答
回答
回答
回答
回答
回答
回答
0