Android与H5交互,以及WebView加载进度条
前言
虽然项目主体是原生Android开发,但是难免会遇到一些H5页面,如:首页Banner的活动推送。我们之所以选择H5来实现,因为它相对灵活,可以多平台运行,从而提高开发效率,节约开发成本。
文章分为两个章节:Android与H5交互、WebView加载进度条。
一、Android与H5交互
Android与H5的简单交互.gif1、WebView加载HTML页面
// 加载一个网页:
webView.loadUrl("http://www.baidu.com/");
// 加载assets文件夹下的test.html页面
webView.loadUrl("file:///android_asset/test.html");
为了点击HTML的内部的链接不跳到外部浏览器,我们还需要setWebViewClient:
// 帮助WebView处理各种通知、请求事件,不写html页面里的链接会跳到外部浏览器哦
mWebView.setWebViewClient(new WebViewClient());
2、本地Java调用js方法
想要调用js方法,就需要让webView支持才可以:
WebSettings webSettings = mWebView.getSettings();
// 设置为可调用js方法
webSettings.setJavaScriptEnabled(true);
若调用的js方法没有返回值,则直接可以调用mWebView.loadUrl("javascript:show()"),其中show是js中的方法;
若有返回值时我们可以调用mWebView.evaluateJavascript()方法:
// 直接访问H5里不带返回值的方法,show()为H5里的方法
mWebView.loadUrl("JavaScript:show()");
// Android调用有返回值js方法,安卓4.4以上才能用这个方法
mWebView.evaluateJavascript("sum(1,2)", new ValueCallback<String>() {
@Override
public void onReceiveValue(String value) {
Log.e(TAG, "js返回的结果为 = " + value);
Toast.makeText(MainActivity.this, "js返回的结果为 = " + value, Toast.LENGTH_LONG).show();
}
});
js代码如下:
<script type="text/javascript">
// 无参无返回值的方法
function show(){
document.getElementById("p").innerHTML="hello world";
}
// 有参有返回值的方法
function sum(a,b){
return a+b;
}
</script>
3、js调用本地Java方法
在Android4.2以上可以直接使用@JavascriptInterface注解来声明,下面是在一个本地Java方法:
public class JsInteration {
// 一定要写,不然H5调不到这个方法
@JavascriptInterface
public String back() {
return "我是java方法的返回值";
}
@JavascriptInterface
public void goNewAct(String str) {
// 也可接收js中的参数
Log.e(TAG, "goNewAct: " + str);
startActivity(new Intent(MainActivity.this, NewActivity.class));
}
}
定义完这个方法后再调用mWebView.addJavascriptInterface()方法:
// 打开js接口給H5调用,参数1为本地类名,参数2为别名;h5用window.别名.类名里的方法名才能调用方法里面的内容
// 例如:window.android.back();
mWebView.addJavascriptInterface(new JsInteration(), "android");
js代码如下:
<script type="text/javascript">
function s(){
// 调用原生的方法,android为约定的别名;back()为原生的方法
var result=window.android.back();
// 将返回结果显示在id为p的控件上
document.getElementById("p").innerHTML=result;
}
function goNewAct(str){
// 打开原生界面,也可以传递参数
window.android.goNewAct(str);
}
</script>
4、WebView监听返回键
当webview包含多个页面的时候,当我们点击返回键的时候,更多时候我们需要的是返回上个页面,而不是直接关闭webview。所以我们需要重写返回键事件:
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if ((keyCode == KeyEvent.KEYCODE_BACK)) {
if (webView.canGoBack()) {
// goBack()表示返回WebView的上一页面
webView.goBack();
return true;
} else {
finish();
return true;
}
}
return false;
}
项目源码在文章末尾给出,已上传至GitHub。
二、WebView加载进度条
在实现基本功能的同时,我们还要注重用户体验,所以加载进度条也就变得不可或缺。本着用户是上帝的原则,还能说些什么(摊手)。。
ProgressWebView.gif
实现思路
首先在自定义的WebView中加入了一个水平方向的ProgressBar,然后为这个ProgressBar设置progressDrawable;创建WebChromeClient 继承 WebChromeClie,监听加载进度的变化onProgressChanged,并做出相应的设置;重写onScrollChanged方法,防止因滑动而造成ProgressBar的移动。
完整代码如下:
public class ProgressWebView extends WebView {
private ProgressBar mProgressBar;
public ProgressWebView(Context context) {
super(context);
}
public ProgressWebView(Context context, AttributeSet attrs) {
super(context, attrs);
// 使用ProgressBar作为加载进度条,当然也可使用其他view作为进度显示
mProgressBar = new ProgressBar(context, null, android.R.attr.progressBarStyleHorizontal);
LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, 8);
mProgressBar.setLayoutParams(layoutParams);
// 获取Drawable资源,并为ProgressBar设置setProgressDrawable
Drawable drawable = ContextCompat.getDrawable(context, R.drawable.web_progress_bar_states);
mProgressBar.setProgressDrawable(drawable);
addView(mProgressBar);
// 辅助WebView处理js的对话框,网站图标,网站title,加载进度等
setWebChromeClient(new WebChromeClient());
}
public class WebChromeClient extends android.webkit.WebChromeClient {
@Override
public void onProgressChanged(WebView view, int newProgress) {
if (newProgress == 100) {
// 加载完成,将进度条隐藏
mProgressBar.setVisibility(GONE);
} else {
if (mProgressBar.getVisibility() == GONE) {
mProgressBar.setVisibility(VISIBLE);
}
// 设置加载进度
mProgressBar.setProgress(newProgress);
}
super.onProgressChanged(view, newProgress);
}
}
@Override
protected void onScrollChanged(int l, int t, int oldl, int oldt) {
// 使进度条始终固定在顶部位置,快速滑动时还是会有影响,日常使用ok
// 使用ViewGroup.LayoutParams滑动会消失,原因不详,求大神告知
LayoutParams lp = (LayoutParams) mProgressBar.getLayoutParams();
lp.x = l;
lp.y = t;
mProgressBar.setLayoutParams(lp);
super.onScrollChanged(l, t, oldl, oldt);
}
}
进度条Drawable这里写的比较简单,当然也可以写的炫酷点。web_progress_bar_states.xm代码如下:
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@android:id/background">
<color android:color="@color/transparent"/>
</item>
<item android:id="@android:id/progress">
<clip>
<shape>
<gradient
android:centerColor="#aaff0000"
android:endColor="#ff0000"
android:startColor="#99ff0000"/>
</shape>
</clip>
</item>
</layer-list>
完整的MainActivity代码:
public class MainActivity extends AppCompatActivity {
private static final String TAG = "--->";
private ProgressWebView mWebView;
@SuppressLint({"JavascriptInterface", "SetJavaScriptEnabled"})
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mWebView = findViewById(R.id.webview);
// 加载本地asset下面的test.html文件
mWebView.loadUrl("file:///android_asset/test.html");
// 加载普通网页
// mWebView.loadUrl("http://image.baidu.com/search/index?tn=baiduimage&ct=201326592&lm=-1&cl=2&ie=gbk&word=%CD%BC%C6%AC&fr=ala&ala=1&alatpl=others&pos=0");
WebSettings webSettings = mWebView.getSettings();
// 打开js支持
webSettings.setJavaScriptEnabled(true);
// 打开js接口給H5调用,参数1为本地类名,参数2为别名;h5用window.别名.类名里的方法名才能调用方法里面的内容,例如:window.android.back()
mWebView.addJavascriptInterface(new JsInteration(), "android");
// 帮助WebView处理各种通知、请求事件,不写html页面里的链接会跳到外部浏览器哦
mWebView.setWebViewClient(new WebViewClient());
// 辅助WebView处理js的对话框,网站图标,网站title,加载进度等,非必须(由于ProgressWebView重写了该方法,这里应该注销,否则自定义无效)
// mWebView.setWebChromeClient(new WebChromeClient());
// 缓存模式(方便测试加载进度条)
webSettings.setCacheMode(WebSettings.LOAD_NO_CACHE);
}
/**
* 自己写一个类,里面是提供给H5访问的方法
*/
public class JsInteration {
/**
* 一定要写,不然H5调不到这个方法
*/
@JavascriptInterface
public String back() {
return "我是java方法的返回值";
}
@JavascriptInterface
public void goNewAct(String str) {
// 可接收js中的参数
Log.e(TAG, "goNewAct: " + str);
Toast.makeText(MainActivity.this, str, Toast.LENGTH_LONG).show();
startActivity(new Intent(MainActivity.this, NewActivity.class));
}
}
/**
* 点击按钮,访问H5里带返回值的方法
*/
@TargetApi(Build.VERSION_CODES.KITKAT)
public void onClick(View v) {
// 直接访问H5里不带返回值的方法,show()为H5里的方法
mWebView.loadUrl("JavaScript:show()");
// 传固定字符串可以直接用单引号括起来
// 访问H5里带参数的方法,alertMessage(message)为H5里的方法
mWebView.loadUrl("javascript:alertMessage('哈哈')");
// 当出入变量名时,需要用转义符隔开
String content = "2333";
mWebView.loadUrl("javascript:alertMessage(\"" + content + "\")");
// Android调用有返回值js方法,安卓4.4以上才能用这个方法
mWebView.evaluateJavascript("sum(1,2)", new ValueCallback<String>() {
@Override
public void onReceiveValue(String value) {
Log.e(TAG, "js返回的结果为 = " + value);
Toast.makeText(MainActivity.this, "js返回的结果为 = " + value, Toast.LENGTH_LONG).show();
}
});
}
}
项目源码:https://github.com/princekin-f/webview
随缘点赞,传播正能量~