美文网首页混编~Android的走向
Android和H5交互一篇就够了

Android和H5交互一篇就够了

作者: 小龙哥的开发日记 | 来源:发表于2017-07-21 16:53 被阅读273次
    1. 1 --- WebView基本配置
    2. 2 ---WebView和H5的交互
    3. 3 --- WebView错误页面处理
    4. 4 ---WebView中的Cookie操作
    5. 5 ---WebView漏洞
    6. 6 ---WebView内存泄漏问题

    文章地址: http://blog.csdn.net/w15321970103/article/details/75635454

    1WebView基本配置

    布局设置


    这里写图片描述

    代码设置

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">
    
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="50dp">
            <Button
                android:layout_width="0dp"
                android:layout_weight="1"
                android:layout_height="match_parent"
                android:id="@+id/btn1"
                android:text="无参调用"/>
            <Button
                android:layout_width="0dp"
                android:layout_weight="1"
                android:layout_height="match_parent"
                android:text="有参调用"
                android:id="@+id/btn2"/>
        </LinearLayout>
        <WebView
            android:id="@+id/wv"
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"
            android:layout_weight="9" />
    </LinearLayout>
    

    初如化控件

            //初始化控件
            Button btn1 = (Button) findViewById(R.id.btn1);
    
            btn1.setOnClickListener(this);
    
            Button btn2 = (Button) findViewById(R.id.btn2);
    
            btn2.setOnClickListener(this);
    
            wv = (WebView) findViewById(R.id.wv);
            //获取webSettings
            WebSettings settings = wv.getSettings();
            //让webView支持JS
            settings.setJavaScriptEnabled(true);
            //加载百度网页
            wv.loadUrl("http://www.baidu.com/");
            //这个时候就能显示百度页面了
    

    2 WebView和H5的交互

    这里写图片描述
    我们自己写一个H5页面 放在assets目录下
    注意 : 如果html文件存于assets:则加前缀:file:///android_asset/
    如果在Sdcard直接使用file:///sdcard/ or file:/sdcard也可以
      //加载本地assets目录下的静态网页
        wv.loadUrl("file:///android_asset/123.html");
        //第一个参数把自身传给js 第二个参数是this的一个名字
        //这个方法用于让H5调用android方法
        wv.addJavascriptInterface(this, "android");
    

    Android调用JS方法

    这里写图片描述
     //这个是button的点击事件
     @Override
        public void onClick(View v) {
            switch (v.getId()) {
                case R.id.btn1:
                    //参数 “javascript:”  +  js方法名
                    wv.loadUrl("javascript:message()");
                    break;
                case R.id.btn2:
                    //在android调用js有参的函数的时候参数要加单引号
                    wv.loadUrl("javascript:message2('" + name + "')");
                    break;
            }
        }
    
    

    JS调用Android方法


    这里写图片描述
        //下面的两个方法是让网页来调的
        //这个注解必须加 因为 兼容问题
        @JavascriptInterface
        public void setMessage() {
            Toast.makeText(this, "我弹", Toast.LENGTH_SHORT).show();
        }
    
        @JavascriptInterface
        public void setMessage(String name) {
            Toast.makeText(this, "我弹弹" + name, Toast.LENGTH_SHORT).show();
        }
    

    H5代码,如果H5看不懂请自行百度

    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="utf-8" />
        <title></title>
    </head>
    <body>
    
    <button id="btn0">调用android无参参数</button>
    <button id="btn1">调用android有参参数</button>
    
    <a href='aa://atguigu/path'>点我试试</a>
    <a href='https://www.baidu.com'>百度</a>
    
    <div id="content"></div>
    
    </body>
    
    <script type="text/javascript">
            var name = "啊福老师 哇哇哇"
            document.getElementById("btn0").onclick = function(){
    //android是传过来的对象名称,setmessage是android中的方法
                android.setMessage();
            };
            document.getElementById("btn1").onclick = function(){
    //android是传过来的对象名称,setmessage是android中的方法
                    android.setMessage(name);
            };
    
            var content = document.getElementById("content");
    
            function message(){
                content.innerHTML = "调用了有参的js函数"
            };
    
            function message2(des){
                content.innerHTML = "调用了"+des;
            };
        </script>
    </html>
    

    第二种交互方式 而是采用scheme + cookie的方式

    --1、Java 调用 js里面的函数、效率低、估计要200ms左右
    而js去调Java的方法、速度很快、50ms左右、所以尽量用js调用Java方法

    --2、Java 调用 js 的函数、没有返回值、调用了就控制不到了

    --3、Js 调用 Java 的方法、返回值如果是字符串、你会发现这个字符串是 native 的、转成 locale 的才能正常使用

    --4、网页中尽量不要使用jQuery、执行起来需要5-6秒、最好使用原生的js写业务脚本、以提升加载速度、改善用户体验

    --5、Android4.2以下的系统存在着webview的js对象注入漏洞…Android API 16 没有正确限制使用webview.addJavaScripteInterface方法,远程攻击者 使用JavaReflectionAPI利用执行任意java对象的方法

    scheme设置:对于要启动的Activity

    //这一章不详细讲解scheme的使用
    <activity android:name=".SecondActivity">
                <intent-filter>
                    <data android:scheme="aa"/>
                    <action android:name="android.intent.action.VIEW"/>
                    <category android:name="android.intent.category.DEFAULT"/>
                    <category android:name="android.intent.category.BROWSABLE"/>
                </intent-filter>
            </activity>
    

    看一下原来的H5代码

    <a href='aa://atguigu/path'>点我试试</a>
    

    注意:

    //Url地址 aa://atguigu/path
    下面的是Activity清单文件的配置
    <data android:scheme="aa" android:host="atguigu" android:path="/path"/>

    上下对比其实和我们的URL地址是一样的
    aa 是 scheme
    host 是主机名称
    path 是路径
    当然还可以配置端口和加参数
    aa://atguigu:8080/path?id = 10

    通过activity配置那么就可以跳转到相应的界面里,如果activity只配置scheme = aa那么只要是aa的Url都是适配的

    wv.setWebViewClient(new WebViewClient() {
    
    //当页面开始加载的时候调用此方法
                @Override
                public void onPageStarted(WebView view, String url, Bitmap favicon) {
                    super.onPageStarted(view, url, favicon);
                  //通过对URl的解析来决定调转到哪个页面
                  //这边只是简单做一些判断当前是否是Scheme跳转
                    if (url.contains("aa")) {
                        Intent intent = new Intent(Intent.ACTION_VIEW,
                                Uri.parse(url));
                        startActivity(intent);
                    }
                }
    

    3WebView错误页面处理

    场景 : 加载webview错误时加载网页的错误页面,体验不好,速度慢,这个时候就需要我们自行处理错误页面

    第一步 先做一个错误的H5页面放在本地,或者加载Activity都可以

    这里写图片描述
    wv.setWebViewClient(new WebViewClient() {
    
         @Override
                public void onReceivedError(WebView view, int errorCode,
                                            String description, String failingUrl) {
                    super.onReceivedError(view, errorCode, description, failingUrl);
                    Log.i(TAG, "onReceivedError: " + errorCode + "  " + description);
                    //判断错误类型
                    if (errorCode == ERROR_UNSUPPORTED_SCHEME) {
                        Log.i(TAG, "onReceivedError: " + "true");
                        
                        //停止加载错误页面,否则会显示原来H5加载的错误页面
                        //再跳到现在的错误页面,体验不好,当然也可以做其它操作
                        view.stopLoading();
                        view.loadUrl("file:///android_asset/error.html");
                    }
                }
    }
    

    4WebView中的Cookie操作

    关于Cookie的介绍在这不再详说

    场景:webView需要保存从网页中获取到的Cookie 在涉及到账户体系的产品中,包含了一种登录状态的传递。比如,在Native(原生)界面的登录操作,进入到Web界面时,涉及到账户信息时,需要将登录状态传递到Web里面,避免用户二次登录。这里就涉及到WebView加载网页时的Cookie操作了。

    通常我们在登录时获取到用户的Cookie信息,然后将其保存到sdcard的WebView缓存文件当中,这样在加载网页时,WebView会自动将当前url的本地Cookie信息放在http请求的request中,传递给服务器

    获取cookie

    //加载百度网站
    wv.loadUrl("http://www.baidu.com");
    
    wv.setWebViewClient(new WebViewClient() {
        @Override
                public void onPageStarted(WebView view, String url, Bitmap favicon) {
                    super.onPageStarted(view, url, favicon);
    
                   CookieManager instance = CookieManager.getInstance();
                   //这样就可以获取到Cookie了
                   String cookie = instance.getCookie(url);
                   Log.i(TAG, "onPageStarted: "+cookie);
                }
    }
    

    设置cookie

            //创建CookieSyncManager 参数是上下文
            CookieSyncManager.createInstance(context);
            //得到CookieManager
            CookieManager cookieManager = CookieManager.getInstance();
            //得到向URL中添加的Cookie的值
            String cookieString;//获取方法不再详述,以项目要求而定
            //使用cookieManager..setCookie()向URL中添加Cookie
            cookieManager.setCookie(url, cookieString);
            CookieSyncManager.getInstance().sync();
    

    5WebView漏洞和内存泄漏

    ① Android API 16 没有正确限制使用webview.addJavaScripteInterface方法,远程攻击者使用 JavaReflectionAPI利用执行任意java对象的方法

    ② webview在布局文件中的使用:webView写在其它容器中时 (先销毁webview再销毁activity)因为 webview是独立进程,最好创建个viewGroup用来放置webview,Activity创建时add进来,在Activity停止时remove掉

    ③使用 jsbridge(详情看下面)

    ④ 在此方法的操作放到后者使用webviewClient.onPageFinished->WebChromeClient.onProgressChanged

    ⑤ 后台耗电问题 :activity不可见时要停用webview

    ⑥ webview硬件加速导致页面渲染问题-白屏展示(关闭硬件加速)

    ⑦动态添加webview,对传入webview中使用的context使用弱引用,动态添加webview意思在布局

    JSBridge

    什么是JsBridge

    WebViewJavascriptBridge是移动UIView和Html交互通信的桥梁,就是实现java和js的互相调用的桥梁。替代了WebView的自带的JavascriptInterface的接口,使得开发者更方便的让js和native灵活交互,使我们的开发更加灵活和安全。

    JSBridge的优点

    Android API 4.4以前,谷歌的webview存在安全漏洞,网站可以通过js注入就可以随便拿到客户端的重要信息,甚至轻而易举的调用本地代码进行流氓行为,谷歌后来发现有此漏洞后,在API 4.4以后增加了防御措施,如果用js调用本地代码,开发者必须在代码申明JavascriptInterface, 列如在4.0之前我们要使得webView加载js只需如下代码:

    mWebView.addJavascriptInterface(new JsToJava(), "myjsfunction");
    

    4.4之后使用时需要在调用Java方法加入@JavascriptInterface注解,如果代码无此申明,那么也就无法使得js生效,也就是说这样就可以避免恶意网页利用js对客户端的进行窃取和攻击。 但是即使这样,我们很多时候需要在js调用本地java代码的时候,要做一些判断和限制,或者有的场景也会做些过滤或者对用户友好提示,甚至更复杂的Hybrid模式下,需要js和native之间进行交互通讯,拍照上传,因此原生的JavascriptInterface 就比较维护了,特此有了基于JavascriptInterface 封装的WebViewJavascriptBridge框架。
    JsBridge: https://github.com/lzyzsd/JsBridge

    相关文章

      网友评论

        本文标题:Android和H5交互一篇就够了

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