Hybrid App开发笔记

本文介绍了HybridApp开发中三种核心交互方式:使用a标签、方法接口和WebViewJavascriptBridge框架,详细展示了每种方法的具体实现步骤和技术细节。

Hybrid App开发笔记

开发模式:

因为尚属初次尝试.结合业务需求.使用【多View混合型】即Native View和Web View独立展示,交替出现的模式.这种模式首要解决的就是点击H5页面进行native界面跳转及数据传递.

主要交互的实现:

一.使用a标签

在用户点击的这个超链接的时候截获该连接.进行分析并获取值,进行下一步的操作.

使用场景:

  • 点击H5功能列表获取数据并进入native页面.
  • 调用java方法(传参不好确定)
js实现:

在html代码中使用固定头开始的a标签:

[a href="mc://mcvc?class=KCGoodCategoryVC&showtype=push&dataString=MCstring&jsid=888888">打开商品分类</a><br]
[a href="mc://mcfunc?func=test">执行本地方法</a><br]
安卓实现:
  1. 定义接收bean和方法接口:

    public class BaseBean implements Parcelable{
    public String showtype;
    public String dataString;
    public String jsid;
    
    public BaseBean() {
    }
    
    public BaseBean(Parcel in) {
        showtype = in.readString();
        dataString = in.readString();
        jsid = in.readString();
    }
    }
    
    
    
    //子类具体实现
    public class KCGoodCategoryVC extends BaseBean {
          protected KCGoodCategoryVC(Parcel in) {
                super(in);
            }
            public KCGoodCategoryVC() {
    
            }
        }
    
    //定义方法接口
    public interface IFunc {
        void test();
        void test1(String var);
    }
    
    //定义方法具体实现
    public class FuncImpl implements IFunc {
        private Context mContext;
        public FuncImpl(Context context) {
                mContext = context;
        }
    
        @Override
        public void test() {
                Toast.makeText(mContext, "利用a标签调用了安卓方法", Toast.LENGTH_SHORT).show();
        }
    
        @Override
        public void test1(String var) {
                Toast.makeText(mContext, "利用a标签调用.var:"+var, Toast.LENGTH_SHORT).show();
        }
    }
    
  2. WebView获取被点击的超链接URL进行分析处理:

    public class KCWebViewClient extends WebViewJavascriptBridge.MyWebViewClient {
          public KCWebViewClient(WebViewJavascriptBridge bridge) {
             super(bridge);
         }
    
        @Override
        public boolean shouldOverrideUrlLoading(WebView view, String url) {
            et.setText(url);
            if (url.startsWith(BASE_HEADER)) {
                String[] value = url.split("\\?");
                String[] val;
                switch (value[0]) {
                    case CLASS_HEADER://解析url获取bean 并传递给相应的activity
                        val = value[1].split("&");
                        String className = val[0].split("=")[1];
                        try {
                            Class clazz = Class.forName("com.fec.h5demo.bean." + className);
                            BaseBean instance = (BaseBean) clazz.newInstance();
                            for (int i = 1; i < val.length; i++) {
                                String[] field = val[i].split("=");
                                Field field1 = clazz.getField(field[0]);
                                field1.set(instance, field[1]);
                            }
                            startActivity(new Intent(MainActivity.this, StartActivity.class).putExtra(StartActivity.EXTRA_KEY, instance));//实际情况中,
                            // 这里是要启动不同的activity或者是不同的操作这里以一个activity代替
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                        break;
                    case FUNC_HEADER:
                        try {
                            FuncImpl func = new FuncImpl(MainActivity.this);//根据url从固定的实现类中调用方法,这种方法存在传参不好确定的问题.有的方法不需要参数,有的需要参数,在这里无法进行确定
                            Class clazz = func.getClass();
                            val = value[1].split("&");
                            Method method = clazz.getDeclaredMethod(val[0].split("=")[1]);
                            method.invoke(func);
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                        break;
                }
            }
            return super.shouldOverrideUrlLoading(view, url);
        }
    }
    

二.使用方法接口交互:

使用Js和安卓支持的方法接口方式调用对方的方法,存在缺点:原生不支持直接回调.如要实现需另外调用其他方法.

使用场景:

  • Js可以直接打开原生的activity,弹出toast等.
  • native也可以控制h5页面的跳转等.
Js实现:
  • 调用native:

      function showToast(){
              var message = document.getElementById("message").value;
              var lengthLong = document.getElementById("length").checked;
              app.makeToast(message, lengthLong);
              return false;
          }
           /*
            把showToast方法重定向给onsubmit == window.app.makeToast()
             */
           window.onload = function(){
               var form = document.getElementById("form");
                form.onsubmit = showToast;
            }
    
  • 给native调用:

    function toastAlert(){
            var msg = document.getElementById('message').value;
            alert(msg);
        }
    
        function actionFromNativeWithParam(arg){
           document.getElementById("log_msg").innerHTML +=
           ("<br\>Native调用了js函数并传递参数:"+arg);
       }
    
  • 跳转activity并传入data:

       function callNative(msg){
            window.app.gotoActivity(msg);
           }
    
    <script>
         var arg1 = "{'type':'mcvc','class':'com.fec.StartActivity','showtype':'push','dataString':'Js传入'}";//使用隐式意图进行跳转
    </script>
    <input type="button" value="调用java方法进行跳转,传值"  onclick="callNative(arg1);"/><br>
    
安卓实现:
  • 调用js:

     String param = et.getText().toString().trim();
       wv.loadUrl("javascript:actionFromNativeWithParam(" + "'" + param + "'" + ")");//传参调用js代码
    
  • 给Js调用:

    //定义方法接口
    public interface IJavaFunc {
        void makeToast(String msg, boolean lengthLong);
        void gotoActivity( String arg);
    }
    
    wv.addJavascriptInterface(new IJavaFunc() {//添加js能够调用的方法接口
            @JavascriptInterface
            @Override
            public void makeToast(String msg, boolean lengthLong) {//被调用后接收Js传递的参数并执行方法体内代码.
                Toast.makeText(MainActivity.this, msg, lengthLong ? Toast.LENGTH_LONG : Toast.LENGTH_SHORT).show();
            }
    @JavascriptInterface
        @Override
        public void gotoActivity(String arg) {//使用json传输数据 
            JsonBean jsonBean = mGson.fromJson(arg, JsonBean.class);
            startActivity(new Intent(jsonBean.getClassX()).putExtra("json", jsonBean)); 
        }
        }, "app");
    
  • 定义JsonBean接收数据,跳转activity时进行传输:

    public class JsonBean implements Parcelable {
        /**
         * type : mcvc
         * class : TestViewController
         * showtype : push
         * dataString : js string
         */
        private String type;
        @SerializedName("class")
        private String classX;
        private String showtype;
        private String dataString;
    
        protected JsonBean(Parcel in) {
            type = in.readString();
            classX = in.readString();
            showtype = in.readString();
            dataString = in.readString();
        }
    

三.使用WebViewJavascriptBridge框架:

An iOS/OSX bridge for sending messages between Obj-C and JavaScript in WKWebViews, UIWebViews & WebViews.(gitHub)

优点如下:

Js实现:
     console.log("user_client.js called!");
       var bridge;
       document.addEventListener('WebViewJavascriptBridgeReady'
        , function(event) {
            bridge=event.bridge;
        bridge.init(function(message, responseCallback) {//初始化默认给java调用的处理方法
            document.getElementById("log_msg").innerHTML +=
           ("<br\>Javascript默认处理方法收到了: "+ message);
           if (responseCallback) {
               responseCallback("js默认处理") ;
           }
        }) ;

        bridge.send('js无回调发送');
        bridge.send('js回调发送', function(responseData) {//发送消息给java并取得回复
           document.getElementById("log_msg").innerHTML +=
           ("<br\>Javascript收到了回答: "+ responseData);
        });

        bridge.registerHandler("showAlert", function(data,responseCallback) {
        alert("alert:"+data);
         responseCallback(data+1);
         });//提供给java调用

        bridge.callHandler("handler1","js发送给handler1",function(responseData){//调用java传送数据并取得回复
           document.getElementById("log_msg").innerHTML +=
           ("<br\>js收到handler1的response:"+responseData);
        });
        }, false)

       function fwcallNative(msg){//启动acivitiy
        bridge.callHandler("gotoActivity",msg,function(responseData){
            document.getElementById("log_msg").innerHTML +=
             ("<br\>js启动activity得到了response:"+responseData);
        });
       }
安卓实现:
  1. 集成框架.
  2. 定义给Js调用的handler:

     bridge = new WebViewJavascriptBridge(this, wv, new UserServerHandler());
    bridge.setCustomWebViewClient(new KCWebViewClient());
    bridge.registerHandler("handler1", new WebViewJavascriptBridge.WVJBHandler() {//定义给Js调用的handler
        @Override
        public void handle(String data, WebViewJavascriptBridge.WVJBResponseCallback jsCallback) {
            if (null != jsCallback) {
                jsCallback.callback("handler1 收到了:" + data);
            }
        }
    });
    bridge.registerHandler("gotoActivity", new WebViewJavascriptBridge.WVJBHandler() {//定义给Js调用的handler
        @Override
        public void handle(String data, WebViewJavascriptBridge.WVJBResponseCallback jsCallback) {
            if (!TextUtils.isEmpty(data)) {
                JsonBean jsonBean = mGson.fromJson(data, JsonBean.class);
                startActivity(new Intent(jsonBean.getClassX()).putExtra("json", jsonBean));
                if (null != jsCallback) {
                    jsCallback.callback("启动了activity:" + jsonBean.getClassX());
                }
            }
        }
    });
    
  3. 向Js发送数据并取得回复:

         bridge.send("呵呵", new WebViewJavascriptBridge.WVJBResponseCallback() {
                @Override
                public void callback(String data) {
                    Log.i("test", "java说:呵呵  js回复说:"+data);
                }
            });
    
  4. 调用Js的方法并取得回复:

     bridge.callHandler("showAlert", "99", new WebViewJavascriptBridge.WVJBResponseCallback() {
                        @Override
                        public void callback(String data) {
                            Log.i("test", "调用js方法回调: "+data);
                        }
                    });//调用js方法
    

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值