Weex:Js與Native的交互

介紹

weex的前端實現(xiàn)是通過Js+Css+Weex自定義組件完成的。那么事必存在Js與Native的擴展和交互存在。本文主要是基于weex官網(wǎng)一文完成的。這里記錄一下,方便自己以后回顧。

Adapter

Weex為了尊重開發(fā)者的習慣,提供了幾個適配接口,以方便開發(fā)者對圖片加載庫,網(wǎng)絡加載庫等自由選擇適配。

  1. IWXImgLoaderAdapter圖片適配器。
    weex并沒有實現(xiàn)圖片加載,而是把加載圖片的View和圖片的url通過接口暴露出來,Native的開發(fā)者可以自己來實現(xiàn)圖片的下載,緩存而與Native中的圖片加載框架統(tǒng)一起來,避免重復導入圖片加載庫和圖片庫加載的沖突。
  public class ImageAdapter implements IWXImgLoaderAdapter {
    Context mContext;
    private final static String BASE_URL = "http://99.48.58.53:8080/";
    public ImageAdapter(Context context){
        this.mContext = context;
    }

    /**
        * @param url  圖片地址,即在.we文件中的圖片路徑
       * @param view  圖片控件
       * @param quality  圖片質量:ORIGINAL(原始)、HIGH(高)、NORMAL(正常)、LOW(低)圖片質量按序降低;默認為LOW
       * @param strategy  圖片加載策略,表示圖片是否裁剪(isClipping),銳化(isSharpen),占位符(placeHolder)等。
      */
    @Override
    public void setImage(String url, ImageView view, WXImageQuality quality, WXImageStrategy strategy) {
        // 這里使用Glide作為圖片加載框架
        /**
         * 還要處理下url的地址.
         * 因為在寫weex頁面的時候,我是用的相對路徑來加載圖片的,
         * 這邊傳過來的路徑也是相對的路徑
         */
        String tempurl = BASE_URL;
        if(null!=url) {
            if(url.startsWith("../")){
                tempurl += url.substring(url.indexOf("/")+1); 
           }
            Glide.with(mContext).load(tempurl).into(view);
        }
    }
}

修改圖片加載的適配其實很簡單,無論是Glide還是ImageLoader的配置跟Android Native 開發(fā)的配置是一樣的。
這里主要需要注意的是就是要處理下圖片的url,在開發(fā)頁面的時候一般只會寫相對路徑,因此在做圖片加載的時候一定要把相對路徑修改成網(wǎng)絡路徑。如果是本地加載,那么圖片地址需要注意,在處理的時候能夠辨別出是在drawable還是在mipmap或者assets中。
對于本地圖片的加載其實還有另一種方式是不通過我們自己實現(xiàn)的IMageAdapter的,那就是通過schemelogcal的路徑來區(qū)分本地圖片;如local://test.png,WXImage中的源碼如下:

    public void setSrc(String src) {
        if(src == null){
            return ;
        }

        WXSDKInstance instance = getInstance();
        Uri rewrited = instance.rewriteUri(Uri.parse(src),URIAdapter.IMAGE);

        if(Constants.Scheme.LOCAL.equals(rewrited.getScheme())){
            setLocalSrc(rewrited);
        }else{
            setRemoteSrc(rewrited);
        }
    }

走到setLocalSrc后,會根據(jù)路徑后面的圖片名稱去drawable中查找,并通過image.setImageDrawable設置圖片:

private void setLocalSrc(Uri rewrited){
        Resources resources = getContext().getResources();
        List<String> segments = rewrited.getPathSegments();
        if(segments.size() != 1){
            WXLogUtils.e("Local src format is invalid.");
            return;
        }
        ImageView imageView;
        int id = resources.getIdentifier(segments.get(0),"drawable",getContext().getPackageName());
        if(id != 0 && (imageView = getHostView()) != null){
            imageView.setImageDrawable(ResourcesCompat.getDrawable(resources,id,null));
        }
    }
  1. IWXHttpAdapter網(wǎng)絡下載適配器
    Weex提供了網(wǎng)絡適配器本地的網(wǎng)絡請求適配,開發(fā)可以自行實現(xiàn)網(wǎng)絡請求。而請求的參數(shù),請求頭等Weex通過自定義的WXRequest封裝提供了,請求返回后,則通過OnHttpListener進行回調通知。Weex默認提供的適配器是DefaultWXHttpAdapter,使用的是HttpURLConnection進行網(wǎng)絡請求。
    接口的定義如下:
public interface IWXHttpAdapter{
      void sendRequest(WXRequest request,OnHttpListener listener);
}

通過DefaultWXHttpAdapter的源碼可以了解網(wǎng)絡請求是如何實現(xiàn)的。

public void sendRequest(final WXRequest request, final OnHttpListener listener) {
    if (listener != null) {
      listener.onHttpStart();
    }
    execute(new Runnable() {
      @Override
      public void run() {
        WXResponse response = new WXResponse();
        try {
          HttpURLConnection connection = openConnection(request, listener);
          Map<String,List<String>> headers = connection.getHeaderFields();
          int responseCode = connection.getResponseCode();
          if(listener != null){
            listener.onHeadersReceived(responseCode,headers);
          }

          response.statusCode = String.valueOf(responseCode);
          if (responseCode >= 200 && responseCode<=299) {
            response.originalData = readInputStreamAsBytes(connection.getInputStream(), listener);
          } else {
            response.errorMsg = readInputStream(connection.getErrorStream(), listener);
          }
          if (listener != null) {
            listener.onHttpFinish(response);
          }
        } catch (IOException|IllegalArgumentException e) {
          e.printStackTrace();
          response.statusCode = "-1";
          response.errorCode="-1";
          response.errorMsg=e.getMessage();
          if(listener!=null){
            listener.onHttpFinish(response);
          }
        }
      }
    });

WXSDKInstance中為默認的DefaultWXHttpAdapter實現(xiàn)了一個OnHttpListener,其中在onHttpFinish中實現(xiàn)了一些記錄網(wǎng)絡請求的性能數(shù)據(jù),這個可以通過另一個適配器(IWXUserTrackAdapter
)擴展來獲取這些數(shù)據(jù);之后也通過Response的data對界面進行繪制。

  1. IWXUserTrackAdapter相關性能數(shù)據(jù)
    接口定義如下:
public interface IWXUserTrackAdapter {
  void commit(Context context, String eventId, String type, WXPerformance perf, Map<String, Serializable> params);
}

通過WXPerformance對象就可以獲取到相關的數(shù)據(jù),具體的可以DefaultWXHttpAdapter里實現(xiàn)的onHttpListener,在onHttpFinish中就記錄了部分的性能數(shù)據(jù)。

Native與JS的通信

JS Call Native

JS對Native方法的調用,官網(wǎng) 已經描述得比較清楚了。主要有以下步驟:

  • Native自定義類繼承WXModule類。
  • 供JS調用的方法必須加上@WXModuleAnno的注釋。(通過注解來判斷當前方法是否為擴展方法,并是否運行在UI線程)
  • 擴展方法必須是public類型,weex通過反射來調用方法。
  • 擴展類因為是通過反射的方法獲取,因此不能被混淆,在混淆中添加-keep public class * extends com.taobao.weex.common.WXModule{*;}
  • Module 擴展的方法可以使用int, double,float,String,Map,List類型參數(shù)
  • 完成Module后,一定要在初始化時注冊WXSDKEngine.registerModule("myModule",MyModule.class);否則會報類似錯誤:ReportException :undefined:9: TypeError: Object #<Object> has no method 'printLog'
    舉個簡單例子:
public class ToastModule extends WXModule{
  
    @WXModuleAnno(runOnUIThread = true)
    public void showToast(){
      Toast.makeText(mWXSDKInstance.getContent(),"this is js call native toast",Toast.LENGTH_LONG).show();
    }

    @WXModuleAnno(runOnUIThread = true)
    public void showToastWithMsg(String msg) {
      Toast.makeText(mWXSDKInstance.getContent(),msg,Toast.LENGTH_LONG).show();
    }
}

在weex的頁面,實現(xiàn)如下:

<div class="opera-menu-item" onclick="showMsg">
    ![](../img/scan.png)
    <text class="opera-menu-item-txt">掃一掃</text>
</div>
<div class="opera-menu-item" onclick="showToastWithMsg">
    ![](../img/qrcode.png)
    <text class="opera-menu-item-txt">我的二維碼</text>
</div>
methods:{
        showMsg:function(){
            var mtoast = require('@weex-module/toastModule');
            mtoast.showToast();
        },
        showToastWithMsg:function(){
            var mtoast = require('@weex-module/toastModule');
            mtoast.showToastByMsg('this msg is from js ');
        }
    }

這樣即可實現(xiàn)JS對Native方法的調用。
但是這樣的調用還只是單方面的交互,JS調用Native后就沒有下文了,我們更多的調用可能是調用Native后還有回調,那么回調是如何交互的呢?

事件回調

Native方法需要回調JS的方法時,在module實現(xiàn)的方法里添加一個入?yún)SCallback

@WXModuleAnno(runOnUIThread = false)
public void callTheCallback(JSCallback callback){
  for(int i = 0;i<5;i++){
    Log.i("weex","test call back -->"+i);
  }
  callback.invoke("show toast from callback");
}

Weex頁面的JS中添加方法如下:

callTheCallback:function(){
    var mtoast = require('@weex-module/toastModule');
    mtoast.callTheCallback(function(event){
        mtoast.showToastByMsg('msg from the callback:' + event);
    });
}

這樣就完成了一個回調:JS callTheCallback方法中調用了Native的方法callTheCallback,Native的Callback方法中先是打印了LOG,然后調用了JS的回調方法,并傳了一個字符串參數(shù),JS的回調方法中調用了Native的showToastByMsg將回調方法中參數(shù)顯示出來。

打印Log

由于測試的頁面使用的是公司正在開發(fā)的頁面,所以展示Toast的截圖就不發(fā)出來了。

Native調用JS

方法一: WXSDKInstance提供了一個調用JS的方法

public void fireEvent(String elementRef,final String type,final Map<String,Object> data,final Map<String,Object> domChanges){...}

public void fireEvent(String elementRef,final String type, final Map<String, Object> data){
  fireEvent(elementRef,type,data,null);
}
public void fireEvent(String elementRef, String type){
  fireEvent(ref,type,new HashMap<String, Object>());
}

不過這個方法多用于某個自定義控件進行事件通知。<這個還不太熟,以后再說>
方法二:通過回調
可以在頁面創(chuàng)建成功之后向Native添加回調方法,Native將回調方法保存,之后在需用用到的地方添加調用回調方法。

先就大概這么多吧...

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容