Android webview

Android与H5交互,以及WebView加载进度条

2018-02-23  本文已影响47人  呱呱_

前言

虽然项目主体是原生Android开发,但是难免会遇到一些H5页面,如:首页Banner的活动推送。我们之所以选择H5来实现,因为它相对灵活,可以多平台运行,从而提高开发效率,节约开发成本。

文章分为两个章节:Android与H5交互、WebView加载进度条。

一、Android与H5交互

Android与H5的简单交互.gif
1、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
随缘点赞,传播正能量~

上一篇下一篇

猜你喜欢

热点阅读