「android」 详细全面的基于vue2.0weex接入过程(android视角) -尊龙游戏旗舰厅官网
本文来自尚妆android团队路飞
发表于尚妆github博客,欢迎订阅!
目前weex已在尚妆旗下的达人店app上线了一个常用的订单管理页面,截止目前android上未发现问题,渲染时间在100-300ms之间。
作为android开发,此文首先会从android的角度为主来记录接入的过程,希望给未接入的同学更方便省时地接入weex提供一点帮助。其中会涉及到预加载,降级,热更新,埋点以及在app不更新的情况下动态配置新页面等问题,这些android和ios都是统一的逻辑,希望和大家一起交流。前端方面可以参考我同事写的《基于vue2.0的weex实践(前端视角)》,ios可以参考我同事写的weex 实践(ios 视角)
其实对于module、component的定义,以及iwximgloaderadapter、iwxhttpadapter等adapter的重写,在playgroud和weexteam里都已经有很好的例子了。
1、gradle依赖
compile 'com.taobao.android:weex_sdk:0.10.0’compile 'com.android.support:support-v4:24.0.0' compile 'com.android.support:appcompat-v7:24.0.0' compile 'com.android.support:recyclerview-v7:24.0.0'compile 'com.squareup.okhttp:okhttp:2.3.0' compile 'com.squareup.okhttp:okhttp-ws:2.3.0'compile 'com.alibaba:fastjson:1.2.8'//(可选)支持调试的依赖,参考https://github.com/weexteam/weex-devtools-android/blob/master/readme-zh.md compile 'com.taobao.android:weex_inspector:0.0.8.5' compile 'com.google.code.findbugs:jsr305:2.0.1' compile 'com.taobao.android:weex_inspector:0.0.8.5'复制代码2、新建weex module
在原来的project上,新建单独的 weex module。代码结构如下:
3、初始化weex
通过类weexmanager来统一管理weex相关的配置,以下是weexmanager里的init函数的主要内容,在application的oncreate里调用:
public void init(application application, iweexservice weexservice) {//通过在线参数控制是否使用weex,configmanager是尚妆的在线参数模块,以后有机会再简单介绍一下if (!configmanager.getboolean(config_weex_enable, true)) {return;}context = application.getapplicationcontext();weexdir = context.getdir(weex_module, context.mode_private);//根据需要注册图片、网络、存储等adapterwxsdkengine.initialize(application,new initconfig.builder().setimgadapter(new frescoimageadapter()).setutadapter(new usertrackadapter()).setstorageadapter(new storageadapter()).sethttpadapter(new okhttpadapter()).seturiadapter(new customuriadapter()).build());this.weexservice = weexservice;//获取本地缓存的weex js配置configlist = wxjsonutils.getlist(shstoragemanager.get(weex_module, weex_config, ""), weexconfig.class);update();try {//页面通用的一些接口wxsdkengine.registermodule("shopbase", shopmodule.class);//主要是a标签的跳转wxsdkengine.registermodule("event", wxeventmodule.class);//模态对话框wxsdkengine.registermodule("shopmodal", modalmodule.class);//用fresco重写图片组件wxsdkengine.registercomponent("image", frescoimagecomponent.class);} catch (wxexception e) {logutils.e(e);}sheventbus.register(modulename.weex, "weexdebughost", new isheventbuscallback- > response)
1)考虑到第一次接入weex,有点担心兼容问题,万一引起崩溃等不确定因素,所以这里做了一个开关。其实每接入一个新的sdk都最好有个控制开关,以避免因为不确定因素导致不稳定。
2)weexdir是js的下载存储路径,为了加快页面打开时间,会对js进行预加载到本地
3) sdk对a标签的处理只调用了"event"的openurl接口,但是却没有注册"event"。所以需要自己实现wxeventmodule,并注册。
4)模态对话框modalmodule的实现参考sdk里的wxmodaluimodule
5)frescoimageadapter和frescoimagecomponent的实现依赖我们开源的shimageview支持webp,支持压缩,支持没有协议的链接(忽略协议可以让浏览器根据页面时http或者https自动选择使用的协议,从而避免了网站改为https的情况下仍然访问http资源而无法访问的问题。)
6)okhttpadapter的实现参考github上zjutkz同学的实现 okhttpadapter,感谢,经过改写,支持没有协议的链接,支持cookie
7)shopmodule是自定义的module,定义通用的一些接口,比如设置title bar是否显示,以及title bar的title;关闭当前页面,分享,错误日志收集等。
8)usertrackadapter用于埋点,另外可以在shopmodule里自定义接口收集埋点、错误信息等。
9)customuriadapter用于支持相对地址,具体实现参见以下:
public class customuriadapter implements uriadapter {@nonnull@overridepublic uri rewrite(wxsdkinstance instance, string type, uri uri) {if (null == uri) {return null;}string url = uri.tostring();if (url.startswith("http")) {return uri;}else if (url.startswith("//")) {if (shstoragemanager.get("app", "https", true)) {url = "https:" url;}else {url = "http:" url;}}else {url = shhost.getmobilehost() url;}return uri.parse(url);} }复制代码4、新建统一的weex页面
这边考虑到以后页面有可能嵌入到其他activity,所以把weex的渲染放入新建的weexfragment。然后新建weexactivity来引用该weexfragment 。所有的单独页面的weex渲染都使用这个weexactivity,非单独页面的使用weexfragment,这样新加页面时,无需重新注册activity。weex处理逻辑统一,方便管理,方便动态配置。通过统一跳转协议跳转到weexactivity,通过intent传入两个参数url和h5。
showjoyshop://page.sh/weex复制代码intent参数:
url:js链接,可以是本地的存储地址/sdcard/com.showjoy.shop/weex/order.js,也可以是线上链接 https://xxxxx/0.4.3/order.js
h5:用来降级的h5页面链接,当渲染失败时,会跳转到该h5页面
5、开始渲染js,失败后降级到h5
首先实例化wxsdkinstance
wxinstance = new wxsdkinstance(activity); wxinstance.registerrenderlistener(this); wxinstance.onactivitycreate(); registerbroadcastreceiver();复制代码1)当前类实现接口iwxrenderlistener,可以参考weexteam里的absweexactivity实现
2)注册的广播是defaultbroadcastreceiver,可以可以参考weexteam里的absweexactivity实现
然后讲一下渲染,支持本地js以及线上js
if (url.startswith("http")) {wxinstance.renderby,url,options,jsoninitdata,commonutils.getdisplaywidth(activity),commonutils.getdisplayheight(activity),wxrenderstrategy.append_async);}else {new thread(new runnable() {@overridepublic void run() {string file = weexutils.readfile(url);handler.sendmessage(handler.obtainmessage(load_local_file, file));}}).start(); }复制代码其中,getpagename()自定义即可,getdisplaywidth和getdisplayheight获取屏幕宽高。
传入本地的存储地址时,先读取文件,然后同个handler在ui线程渲染,如下:
接收load_local_file后handler里的实现:
case load_local_file:if (activity.getlifestate() != lifestate.destory ) {if (wxinstance != null) {string content = (string) msg.obj;if (textutils.isempty(content)) {shjump.open;finishactivity();}else {wxinstance.render((string) msg.obj, null, null);}}}break;复制代码这里getlifestate()是我们自己baseactivity的实现,可以自行判断。shjump和finishactivity都是自己的实现,大家自己实现即可。
渲染回调的实现,按需要处理即可,渲染成功后隐藏loading,view创建后添加view。渲染异常时降级跳转到h5。如下:
override public void onviewcreated(wxsdkinstance instance, view view) {//viewmap.put(weexjsurl, view);addweexview(view); } @override public void onrendersuccess(wxsdkinstance instance, int width, int height) {tohideloading(); } @override public void onrefreshsuccess(wxsdkinstance instance, int width, int height) {tohideloading(); } @override public void onexception(wxsdkinstance instance, string errcode, string msg) {logutils.e("weex exception:", errcode, msg);shjump.openurlforce(activity, h5url);finishactivity(); }复制代码6、多个js在同个页面渲染
为了实现如图的tab,一开始在.vue文件里使用tabbar组件,后来发现在android机型适配上不够好。于是后来就将两个tab做成两个页面,生成两个js文件。首先渲染“我的订单.js”,生成如下的界面。
alt text然后点击“本店订单”时,调用自定义module里的接口loadpage,参数为h5的链接。三端实现接口loadpage,h5直接跳转,而ios和android通过h5链接从weex跳转配置里找到对应的js,重新渲染显示。下面具体做几点说明:
1)定义map wxsdkinstancemap;来存储不同js的wxsdkinstance,定义map viewmap来存储不同js渲染后的view。之所以要存储多个wxsdkinstance,是因为wxsdkinstance不能重复渲染,而且当wxsdkinstance destory后,之前渲染的view里的内容也会被清空。注意在在页面destory时,记得把所有wxsdkinstance都destory就好了。
2)viewmap里的key对应页面的js。点击tab切换页面时,如对应的js已渲染,则直接取出view来显示。
3)上文提到的weex跳转配置,在以下的跳转规则里一同介绍。
跳转规则如下图,如果看不清,可以到新页面放大查看。
app跳转框架主要介绍一下两个配置参数:
- 在参数weexpages配置所有的weex页面。
示例如下:
page: 对应统一跳转的 path
url: 需要渲染的js,
md5: js文件的md5值用于校验,
h5: 渲染失败后的降级方案,
v: 最低支持的版本号
在页面访问h5页面时,拿url跟weexpages里的url进行对比,如果一致就采用weex打开。这里的对比,目前还比较简单粗暴,后续会进行优化,最终目标是只对比?之前的一部分,后面的参数通过intent传入到weex页面,参与weex的渲染。
这样就达到了动态拦截,动态上线weex的目的。
前面讲到为了加快weex打开时间,会预加载js,这里就介绍一下js预加载的实现。
1)每次更新完配置文件,遍历,查看是否存在md5一致的page_xxx.js文件,如果不存在则更新.
2)下载完成后,保存格式为xxx.js,校验md5
- 相同的话,记录文件的最后修改时间;
- 不同的话,删除已下载文件,重新下载,重复校验流程。
3)支持统一跳转协议,page对应目前app端的统一跳转协议里的page,有必要的时候可以替换原来的native页面,解决native页面错误不能及时修复的问题。加载失败的话,打开h5页面。
4)每次打开指定页面的时候,先检查本地是否有对应page文件,再检验最后修改时间是否跟记录的一致
- 一致就加载
- 不一致就用线上url。
问题一:上线后,发现在一些机型渲染失败,public void onexception(wxsdkinstance instance, string errcode, string msg)回调里,errcode返回wx_create_instance_error,msg返回createinstance fail!
解决办法:将apk解压出来后,发现编译出了支持5种abi的包。然而libweexv8.so只在armeabi和x86里有,缺少对其它三种abi的支持,那么如果应用运行于arm64-v8a,x86_64,armeabi-v7a为首选abi的设备上时,就会加载失败了。其实arm64-v8a,armeabi-v7a,x86_64这三个abi,应用并不是必须要做支持,手机一般都会提供自动兼容。所以我们只要把对x86, arm64-v8a,x86_64的支持去掉就可以。如下在主模块的build.gradle的android里的defaultconfig内添加如下内容:
defaultconfig { ndk { abifilters "armeabi", "x86" } }复制代码enter image description here问题二:okhttpadapter里调用onhttpfinish出现解析异常,日志如下:
com.alibaba.fastjson.jsonexception: syntax error, pos 2at com.alibaba.fastjson.parser.defaultjsonparser.parse(defaultjsonparser.java:1300)at com.alibaba.fastjson.parser.defaultjsonparser.parse(defaultjsonparser.java:1210)at com.alibaba.fastjson.json.parse(json.java:109)at com.alibaba.fastjson.json.parse(json.java:100)at com.taobao.weex.http.wxstreammodule.parsejson(wxstreammodule.java:378)at com.taobao.weex.http.wxstreammodule$2.onresponse(wxstreammodule.java:365)at com.taobao.weex.http.wxstreammodule$streamhttplistener.onhttpfinish(wxstreammodule.java:523)at com.showjoy.weex.commons.adapter.okhttpadapter$6.onresponse(okhttpadapter.java:161)at okhttp3.realcall$asynccall.execute(realcall.java:133)at okhttp3.internal.namedrunnable.run(namedrunnable.java:32)at java.util.concurrent.threadpoolexecutor.runworker(threadpoolexecutor.java:1113)at java.util.concurrent.threadpoolexecutor$worker.run(threadpoolexecutor.java:588)at java.lang.thread.run(thread.java:818)复制代码解决方法:catch异常
try {if (null != listener) {listener.onhttpfinish(wxresponse);} } catch (exception e) {logutils.e(e); }复制代码问题三:相对地址以及线上线下环境切换问题。
解决方法:在最新版本已支持相对地址,在.vue文件里链接以及请求地址使用相对地址,h5页面自动选择该页面使用的域名,而在ios和android都做拦截处理,根据当前环境添加相应的域名。
- android 实现uriadapter 注入
- ios 实现wxurlrewriteprotocol 注入
参考链接:
github.com/weexteam/
weex-project.io/doc/
github.com/alibaba/wee…
总结
以上是尊龙游戏旗舰厅官网为你收集整理的「android」 详细全面的基于vue2.0weex接入过程(android视角)的全部内容,希望文章能够帮你解决所遇到的问题。
- 上一篇: redhat6.4执行二进制程序报错:/
- 下一篇: llvm每日谈之二十三 llvm/c