200821-Android webview内嵌h5基础使用说明

文章目录
  1. I. 内嵌html
    1. 1. 布局
    2. 2. WebView配置
    3. 3. 回退与销毁
  2. II. Android与JS交互
    1. 1. 加载html
    2. 2. js调用android方法
    3. 3. android 调用js方法
  3. III. 长按图片下载
  4. II. 其他
    1. 1. 一灰灰Blog: https://liuyueyi.github.io/hexblog
    2. 2. 声明
    3. 3. 扫描关注

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
// butterknife 方式,也可以直接通过 findViewById 获取
@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 webSettings = webView.getSettings();

//如果访问的页面中要与Javascript交互,则webview必须设置支持Javascript
webSettings.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");//设置编码格式


//重写shouldOverrideUrlLoading()方法,使得打开网页时不调用系统浏览器, 而是在本WebView中显示
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
// 加载assets 资源文件下html
webView.loadUrl("file:///android_asset/bs.html");

// 加载在线的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;
}

/**
* 显示提示信息
*
* @param message
*/
@JavascriptInterface
public void toastMessage(String message) {
Toast.makeText(activity, "通过Natvie传递的Toast:" + message, Toast.LENGTH_LONG).show();
}
}

通过webView.addJavascriptInterface来关联

1
2
// 请注意第二个参数,在js中使用`android.toastMessgae`来实现调用Android的方法
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
// 只需要将第一种方法的loadUrl()换成下面该方法即可
mWebView.evaluateJavascript("javascript:callJS()", new ValueCallback<String>() {
@Override
public void onReceiveValue(String value) {
//此处为 js 返回的结果
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() {
// 自动dismiss
@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 {

/**
* 下载图片,返回图片的地址
*
* @param url
*/
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. 其他

1. 一灰灰Bloghttps://liuyueyi.github.io/hexblog

一灰灰的个人博客,记录所有学习和工作中的博文,欢迎大家前去逛逛

2. 声明

尽信书则不如,以上内容,纯属一家之言,因个人能力有限,难免有疏漏和错误之处,如发现bug或者有更好的建议,欢迎批评指正,不吝感激

3. 扫描关注

一灰灰blog

QrCode

评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×