介紹
weex的前端實現(xiàn)是通過Js+Css+Weex自定義組件完成的。那么事必存在Js與Native的擴展和交互存在。本文主要是基于weex官網(wǎng)一文完成的。這里記錄一下,方便自己以后回顧。
Adapter
Weex為了尊重開發(fā)者的習慣,提供了幾個適配接口,以方便開發(fā)者對圖片加載庫,網(wǎng)絡加載庫等自由選擇適配。
- 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的,那就是通過scheme為logcal的路徑來區(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));
}
}
- 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對界面進行繪制。
- 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">

<text class="opera-menu-item-txt">掃一掃</text>
</div>
<div class="opera-menu-item" onclick="showToastWithMsg">

<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ù)顯示出來。

由于測試的頁面使用的是公司正在開發(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將回調方法保存,之后在需用用到的地方添加調用回調方法。
先就大概這么多吧...