美文网首页Android webview
Android与H5交互,以及WebView加载进度条

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

作者: 呱呱_ | 来源:发表于2018-02-23 23:31 被阅读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
    随缘点赞,传播正能量~

    相关文章

      网友评论

        本文标题:Android与H5交互,以及WebView加载进度条

        本文链接:https://www.haomeiwen.com/subject/fjdxxftx.html