Android可以通过webview来内嵌html页面,从而实现灵活的信息展示;最近客串android开发中,正好遇到了这样的一个小场景,所以简单的记录一下Android与html之间的交互,包含以下内容
webview的基本设置
Andriod调用js方法
js调用android方法
图片长按下载
I. 内嵌html 1. 布局 我们这里主要介绍通过原生的WebView
来嵌入Html网页,首先是在布局文件中,添加webview控件
1 2 3 4 5 <WebView android:id ="@+id/wv_detail" android:layout_width ="match_parent" android:layout_height ="match_parent" />
2. WebView配置 在Activity类中,获取WebView
控件
1 2 3 @BindView (R.id.wv_detail)WebView webView;
webview的基本配置参数,比如是否可以缩放,自适应等
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 WebSettings webSettings = webView.getSettings(); webSettings.setJavaScriptEnabled(true ); webSettings.setPluginsEnabled(true ); webSettings.setUseWideViewPort(true ); webSettings.setLoadWithOverviewMode(true ); webSettings.setSupportZoom(true ); webSettings.setBuiltInZoomControls(true ); webSettings.setDisplayZoomControls(false ); webSettings.setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK); webSettings.setAllowFileAccess(true ); webSettings.setJavaScriptCanOpenWindowsAutomatically(true ); webSettings.setLoadsImagesAutomatically(true ); webSettings.setDefaultTextEncodingName("utf-8" ); webView.setWebViewClient(new WebViewClient(){ @Override public boolean shouldOverrideUrlLoading (WebView view, String url) { view.loadUrl(url); return true ; } });
3. 回退与销毁 内嵌html,当存在多个html页面跳转时,如果直接后退,可能的结果就是回到上一个activity,而不是我们预期的回到上一个html页面,因此我们需要处理一下回退事件
1 2 3 4 5 6 7 8 9 10 11 @Override public void onBackPressed () { if (webView == null ) { return ; } if (webView.canGoBack()) { webView.goBack(); return ; } super .onBackPressed(); }
其次在退出activity时,别忘了销毁WebView
1 2 3 4 5 6 7 8 9 10 11 12 @Override protected void onDestroy () { if (webView != null ) { final ViewGroup viewGroup = (ViewGroup) webView.getParent(); if (viewGroup != null ) { viewGroup.removeView(webView); } webView.destroy(); } super .onDestroy(); }
II. Android与JS交互 1. 加载html 基本配置完毕之后,开始加载html页面,主要是借助loadUrl
来实现
1 2 3 4 5 webView.loadUrl("file:///android_asset/bs.html" ); webView.loadUrl("https://mweb.hhui.top/" )
2. js调用android方法 为了实现js调用android方法,我们新建一个桥接类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public class JsBrager { private Activity activity; public JsBrager (Activity activity) { this .activity = activity; } @JavascriptInterface public void toastMessage (String message) { Toast.makeText(activity, "通过Natvie传递的Toast:" + message, Toast.LENGTH_LONG).show(); } }
通过webView.addJavascriptInterface
来关联
1 2 webView.addJavascriptInterface(new JsBrager(this ), "android" );
一个简单的html页面如
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 <head > <meta http-equiv ="content-type" content ="text/html;charset=utf-8" > </head > <body > <center > <h2 > 简单的测试</h2 > </center > <div > <span > <img src ="https://cdn.pixabay.com/photo/2015/05/26/22/33/kindle-785686_960_720.jpg" /> </span > </div > <div > <h3 > Android Html交互:</h3 > <button onclick ="show()" id ='btn' > toast</button > </div > <br /> <script type ="text/javascript" > function show ( ) { android.toastMessage("js 点击" ); } function change_theme (bg, txt ) { var body = document .getElementsByTagName('body' )[0 ]; body.style.background = bg; body.style.color = txt; } function callJS ( ) { return "hello" ; } </script > </body >
3. android 调用js方法 android 调用js方法,也是通过loadUrl
来实现的,需要注意的前缀,以及是否需要传参返回结果
1 2 webview.loadUrl("javascript:change_theme('#ffffff','#000000')" );
如果有返回结果,则可以考虑下面的写法
1 2 3 4 5 6 7 8 mWebView.evaluateJavascript("javascript:callJS()" , new ValueCallback<String>() { @Override public void onReceiveValue (String value) { Toast.makeText(activity, "js回调:" + message, Toast.LENGTH_LONG).show(); } });
III. 长按图片下载
下面实现来自于搜索,忘了具体的来源了(主要还是习惯不好,拷代码,没有拷出处,我的锅)…
一种常见的case,长按图片下载,下面给出基本的额使用套路
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 handler = new Handler() { @Override public void handleMessage (Message msg) { super .handleMessage(msg); String picFile = (String) msg.obj; String[] split = picFile.split("/" ); String fileName = split[split.length - 1 ]; try { MediaStore.Images.Media.insertImage(getApplicationContext().getContentResolver(), picFile, fileName, null ); } catch (FileNotFoundException e) { e.printStackTrace(); } getApplicationContext().sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.parse("file://" + picFile))); Toast.makeText(SquareDetailActivity.this , showContent("图片保存图库成功" ), Toast.LENGTH_LONG).show(); } }; webView.setOnLongClickListener(new View.OnLongClickListener() { @Override public boolean onLongClick (View view) { final WebView.HitTestResult hitTestResult = webView.getHitTestResult(); if (hitTestResult.getType() == WebView.HitTestResult.IMAGE_TYPE || hitTestResult.getType() == WebView.HitTestResult.SRC_IMAGE_ANCHOR_TYPE) { AlertDialog.Builder builder = new AlertDialog.Builder(getContext()); builder.setTitle("提示" ); builder.setMessage("保存图片到本地" ); builder.setPositiveButton(LanguageFormatHelper.formatContent("确认" ), new DialogInterface.OnClickListener() { @Override public void onClick (DialogInterface dialogInterface, int i) { String url = hitTestResult.getExtra(); DownPicUtil.downPic(url, new DownPicUtil.DownFinishListener() { @Override public void getDownPath (String s) { Message msg = Message.obtain(); msg.obj = s; handler.sendMessage(msg); } }); } }); builder.setNegativeButton(LanguageFormatHelper.formatContent("取消" ), new DialogInterface.OnClickListener() { @Override public void onClick (DialogInterface dialogInterface, int i) { } }); AlertDialog dialog = builder.create(); dialog.show(); } return true ; } });
图片下载类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 public class DownPicUtil { public static void downPic (String url, DownFinishListener downFinishListener) { String filePath = Environment.getExternalStorageDirectory().getPath(); File file = new File(filePath + File.separator + "webViewCache" ); if (!file.exists()) { file.mkdir(); } loadPic(file.getPath(), url, downFinishListener); } private static void loadPic (final String filePath, final String url, final DownFinishListener downFinishListener) { Log.e("下载图片的url" , url); new AsyncTask<Void, Void, String>() { String fileName; InputStream is; OutputStream out; @Override protected String doInBackground (Void... voids) { String[] split = url.split("/" ); String newString = split[split.length - 1 ]; if (newString.length() >= 20 ) { fileName = newString.substring(newString.length() - 20 , newString.length() - 1 ); } else { fileName = newString; } File picFile = new File(filePath + File.separator + fileName); if (picFile.exists()) { return picFile.getPath(); } try { URL picUrl = new URL(url); is = picUrl.openStream(); if (is == null ) { return null ; } out = new FileOutputStream(picFile); byte [] b = new byte [1024 ]; int end; while ((end = is.read(b)) != -1 ) { out.write(b, 0 , end); } Log.e("OK??" , "----------" ); if (is != null ) { is.close(); } if (out != null ) { out.close(); } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return picFile.getPath(); } @Override protected void onPostExecute (String s) { super .onPostExecute(s); if (s != null ) { downFinishListener.getDownPath(s); } } }.execute(); } public interface DownFinishListener { void getDownPath (String s) ; } }
II. 其他 一灰灰的个人博客,记录所有学习和工作中的博文,欢迎大家前去逛逛
2. 声明 尽信书则不如,以上内容,纯属一家之言,因个人能力有限,难免有疏漏和错误之处,如发现bug或者有更好的建议,欢迎批评指正,不吝感激
3. 扫描关注 一灰灰blog