AndroidとH 5のインタラクション-フレームワーク編


現在、appの開発は主にnative app、hybrid app、web appの3つの方向に分かれている.個人的には3つのアプリの体験感が徐々に減っているような気がします.
hybrid appとweb appの開発の違いは、前者はフロントエンドに必要なインタフェースを自分で提供し、実現する必要があり、後者はいくつかのフレームワーク(例えばicon、dcloudなど)を借りていることである.実質的にはそれほど悪くないが、前者はもっと柔軟だ.Hybrid App開発におけるH 5とnativeのインタラクションがどのように行われているかまだ分からない場合は、この「AndroidとH 5インタラクション-基礎編」を見終わってもいいと信じています.
 
実はH 5とnativeのインタラクションもいくつかのステップであり、フロントエンドがオリジナルのインタフェースを統一的に呼び出すために、通常、フロントエンドとnative(iosとAndroid)エンドが規範化される.前の文章は主に両者の間でどのようにインタラクションを行うかを紹介していますが、この文章では両者のインタラクションに基づく簡単なパッケージを紹介します.フロントエンドにインタフェースを書く場合は、次のように書く可能性があります.
     /**
     * dec: js       
     * createBy yjzhao
     * createTime 2016/11/15 13:50
     */
    public class NativeApi {

    /**
     *     
     *
     * @param mobile     
     */
    @JavascriptInterface
    public void openPhone(String mobile) {
        ...
    }

    /**
     *          ISP  
     *
     * @param smsto         
     */
    @JavascriptInterface
    public void opneMsg(String smsto) {
        ...
    }
     /**
      *       
      *
      * @param url       URL
      * @param data      
      * @param jsRe       
      */
    @JavascriptInterface
    public void reqProxy(String url, String data, String jsRe) {
        ...
    }

     /**
     *   
     */
    @JavascriptInterface
    public String takePhoto(final String callback) {
        ...
    }

    /**
     *     
     */
    @JavascriptInterface
    public String selectPhoto(final String callback) {
        ...
    }

    /**
     *      
     * @param urls     (     ,  )
     */
    @JavascriptInterface
    public void browsePhoto(String urls){
        ....
    }
    /**
     *     
     *
     * @param url   
     * @return
     */
    @JavascriptInterface
    public String loadFile(String url) {
       ....
    }
}

nativeインタフェースをこのように書くと、フロントエンドjs呼び出しは次のようになる可能性があります.
//    
NativeAPI.openPhone(params);
//    
NativeAPI.opneMsg(params);
//      
NativeAPI.reqProxy(params);
//  
NativeAPI.takePhoto(params);
//    
NativeAPI.selectPhoto(params);
//    
NativeAPI.browsePhoto(params);
//    
NativeAPI.loadFile(params);

もちろんそう書いても大丈夫ですが、面倒だと思いますが、どう思いますか?
Androidインタフェースをこのように書くと、メンテナンスに問題があることに気づきます.第一に、このクラスは肥大化します.第二に、jsがAndroidインタフェースを呼び出すときはjsBrigdeというサブスレッドで実行され、Androidがjsメソッドを呼び出すときはmainスレッドで実行され、jsメソッドをコールバックする必要がある場合は、スレッドの切り替えが必要です.このクラスの各インタフェースメソッドを独立して1つのクラスに書き出し、統一されたインタフェースを介してフロントエンド呼び出しに露出し、jsメソッドを呼び出すときにプライマリスレッドに統一的に切り替えると、より良いのではないでしょうか.
では、どのようにカプセル化しますか?私の考えを紹介します.
Android:
Step 1はjsに統一呼び出しのインタフェースsendMessageを暴露する
 private void addJavascriptInterface(WebView webView) {
    webView.addJavascriptInterface(new Object(){
        @JavascriptInterface
        public void sendMessage(String jsonStr){
            mHandleJsMessage.handle(jsonStr);
        }
      },"native");
  }

Step 2 jsから送られてきたデータを統一的に処理する
 /**
 *    js       
 * @param jsonStr js     
 * @return     
 */
   @TargetApi(Build.VERSION_CODES.KITKAT)
  public  boolean handle(String jsonStr) {
    JsMessage jsMessage = new Gson().fromJson(jsonStr, JsMessage.class);
    String action = jsMessage.getAction();
    jsCallback = jsMessage.getCallback();
    if (null == jsMessage.getAction())
        return false;
    if (HandleAction(jsonStr, action, mActionMap)) return true;
    return false;
  }

/**
 *    js     action       
 * @param jsonStr js     
 * @param action js  
 * @param map js    
 * @return               
 */
  @TargetApi(Build.VERSION_CODES.KITKAT)
  private boolean HandleAction(String jsonStr, String action, Map> map) {
    for (String mapAction : map.keySet()) {
        if (mapAction.equals(action)) {
            try {
                mJsAction = map.get(mapAction).newInstance();
                if (mJsAction != null) {
                    mJsAction.handleAction(mContext, jsonStr);
                }
            } catch (InstantiationException | IllegalAccessException e) {
                e.printStackTrace();
            }
            return true;
        }
    }
    return false;
  }

Step 3スレッドをメインスレッドに切り替え、処理結果をフロントエンドに戻す
public void callback(final WebView webView, final String callback, final Object result){
    //      
    Observable.create(new ObservableOnSubscribe() {
            @Override
            public void subscribe(ObservableEmitter emitter) throws Exception {
                emitter.onNext("");
            }
        })
        .subscribeOn(Schedulers.trampoline())//               
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe(new Observer() {
            @Override
            public void onSubscribe(Disposable d) {

            }

            @Override
            public void onNext(Object o) {
                if (null==result || null==callback || "".equals(callback))
                    return;
                String resultStr= new Gson().toJson(result);
                String url = "javascript:" + callback + "("+resultStr+")";
                webView.loadUrl(url);
            }

            @Override
            public void onError(Throwable e) {

            }

            @Override
            public void onComplete() {

            }
        });
}

この3つのステップは核心的な考え方で、具体的な実現はここでコードを貼らないで、興味のあるのはソースコードを見ることができて、アドレスの文末は与えます.フロントエンドjsがどのようにカプセル化されているかを見てみましょう.
  ///////////////////////////////
//                  //
///////////////////////////////
;(function($) {
"use strict"//      
  function native(params) {
    params = params||{};
    if (params==="undefind")return;
    if (params.action==="undefind")return;
    //        native   ,  native      
    var Senddata={
        action:params.action,
        callback:"nativeCallback",
        data:params.data,
    }
    window.nativeCallback = function(data) {
        if (params.callback!=="undefind") {
            params.callback(data);
        }
    }
    var sendDataStr=JSON.stringify(Senddata);
    window.native.sendMessage(sendDataStr);
  }
  $.native = native;
})($);

このコードは簡単ではないか.jsがnativeに送信するjsonデータフォーマットは固定されていることに注目すべきである.
{
    "action":"action",
    "callback":"nativeCallback",
    "data":{        native    action            }
}

how to use?
android端子:
  compile 'com.zyj:hybridbridge:0.1.0'//    

1、まずはactivityで初期化
JsBridge.getInstance().init(this, webView)

2.次に処理するアクションおよび対応する処理クラスを追加する
JsBridge.getInstance().addJsAction(JsDeviceInfo.ACTION, JsDeviceInfo.class);

 //JsDeviceInfo     (      JsAction        handleAction()  )
public class JsDeviceInfo extends JsAction {

 //  action       
public static final String ACTION = "deviceinfo";

@Override
protected void handleAction(Activity context, String jsonStr) {
    HandleResult resultEntity =new HandleResult();
    DeviceInfoEntity deviceInfoEntity =new DeviceInfoEntity();
    deviceInfoEntity.setDeviceName("  Android   !");
    resultEntity.setData(deviceInfoEntity);
    //                ,post       js callback  
    RxBus.getInstance().post(resultEntity);
  }
}

フロントエンド:
  function callback(backdata) {
            //native            
        }
  $.native({
            action: "deviceinfo",
            callback: callback
        });

見終わったら先端もnative端も簡単だと思いますか?すべてのactionおよび渡されたパラメータフォーマットはカスタマイズでき、両端が統一されていることを保証するだけでよい.もしあなたが興味があれば、ソースコードはここでHybridBridgeで、startを歓迎して、何か問題があったら、私は改善を維持することができます.
作者:Jesse_zhaoリンク:https://www.jianshu.com/p/02afb387b6b4出典:簡書の著作権は作者の所有である.商業転載は著者に連絡して許可を得てください.非商業転載は出典を明記してください.