唱吧Android Weex集成踩坑实录
Posted ChangbaDev
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了唱吧Android Weex集成踩坑实录相关的知识,希望对你有一定的参考价值。
唱吧android Weex集成踩坑实录
问:Weex是什么?
答:很炫的技术
正经回答:Weex 是一个使用 Web 开发体验来开发高性能原生应用的框架
问:Weex有哪些优点?
答:客户端方便甩锅
正经回答:1、一次编写,处处运行;2、随时上线、随时修复,不需要发版;3、采用web开发体验,开发简洁,体验更佳
问:唱吧为什么要使用Weex?
答:因为Weex流行啊
正经回答:因为1、唱吧有很多需要动态配置的多变的业务页面;2、唱吧有一些需要动态上线和下线的活动页面;3、唱吧需要快速上线验证一些功能;4、唱吧有很多功能体验不够理想的web页面;5、唱吧需要更快速的迭代
从8.7.8开始,唱吧App开始尝试引入Weex开发框架,其目的除了解决一些问题之外,更主要的是提供了一种新的技术手段来满足日益复杂的产品及运营需求,同时也是为产品形态提供一种新的设计思路。随着唱吧8.8.2版本的上线,客户端已经基本完成了Weex框架的集成,5大主界面中的发现页已经实现全Weex开发。
历经了3个版本的开发集成,直到最终上线,客户端踩了很多大大小小的坑。本文着重列举一下唱吧客户端在集成Weex的过程中,踩过哪些坑。
这些坑有一些是Weex开发者大多数会遇到的,我把这类归纳为标准坑;有一些则是唱吧在开发集成过程中新遇到的,我把这些归纳为新发坑。请各位开发大大在坑中躺好,我们开始踩坑之旅。。
标准坑-Weex集成常见坑
堂堂的navigator都不知道怎么setTitle
没错,就像标题里说的一样,最为常用的navigator,如果去看官方文档,就会发现,你连如何设置title都不知道。
其实这个问题是一类坑的代表。在这里只能再次吐槽一下Weex的官方文档,几乎没有API的介绍,导致很多方法都需要通过Demo或者阅读源码才能够知道如果调用。因此,唱吧在决定引入Weex时,就同步的建立了属于自己的knowledgebase,一是为了工程师们能够快速入门,二是为了补充官方文档的不足,三则是记录开发心得。
Tips:开源项目,还是多看看源码更靠谱。。
Android完全集成Weex增加包大小过大
这个问题严格意义上说,并不能算作Weex独有的问题。毕竟Android对于包大小始终很敏感,在引用任何第三方框架的时候,都需要注意这个问题。
Android端引入第三方框架一般有两种方式:1、Gradle引用集成 2、源码直接集成。Weex也是支持以上两种集成方式。与其他第三方框架相同,通过Gradle方式集成方便快捷,但是灵活性较差,不能够修改源码;源码集成则相对复杂一些,但是灵活度很高,可以根据项目需求,选择性集成。
Weex在采用Gradle集成时,会大幅度增加apk包大小,接近10M的大小。对于本身包大小就已经很大的唱吧来说,这个量级的增加是完全不能接受的,所以我们就必须对Weex框架进行裁剪。
通过对Weex源码框架进行分析发现,Android端Weex框架分为两部分:Java层源码;native层源码。Java层源码主要是负责初始化、API对接等功能,而native源码主要负责实现JS Bridge相关功能。通过计算可以发现,Weex框架的大小主要是被native层源码所占用,而native之所以占用了很多空间是因为在build native层源码的时候,为了适配多种arm型号,生成了多份.so文件。而对于唱吧来说,我们现在只需要支持arm v7即可,其他版本的arm并不需要支持。
综上,我们对Weex框架的裁剪,主要是删掉无用版本的.so文件。所以唱吧集成Weex框架采用了源码方式集成,删除了源码中无用的so。通过这种方式成功将引入Weex框架的大小缩减到不足4M。
关于Json解析的问题
众所周知,Weex是由阿里开发维护的一套框架,所以对于Json生成与解析,自然而然使用了同样是阿里开发的fastJson库。然而,并不是所有的app都使用fastJson作为Json的处理库,唱吧原生使用的就是Google的Gson。Weex框架内部很多数据封装都使用了fastJson相关对象,并且没有提供自定义替换方式。所以我们在进行数据封装和传递的时候,不得不做一次Json对象的转换,从Gson转化成fastJson。毕竟对于Json操作还是很耗时的,所以未来还是希望阿里能够多多考虑对这部分进行优化吧~
尴尬的Navigator跳转
客户端开发同学对于Navigator并不陌生,而Weex也很友好的封装了一份Navigator module。但是,在Android端,Weex的Navigator module出现了一个尴尬的事情。 在Weex上使用Navigator跳转的时候,主要采用openUrl或者push的方式,Android端需要做的事情是注IntentFilter,即通过Itent的隐式意图进行跳转,详细见sdk源码中:com.taobao.weex.appfram.navigator.WXNavigatorModule类。
因此,我们对能够加载Weex-js页面的Activity需要在AndroidManifest.xml中进行清单文件的注册,使之能够响应隐式意图。
然而尴尬的事情就出来了:当我们手机中安装了使用weex开发的app的时候,在出发跳转的时候,总是会尴尬的弹出一个应用选择框,用户需要选择使用哪个app来开启即将跳转的页面。而一旦用户手误选择错误,那么就会产生数据加载错误、数据错乱等等一系列错误。
这个问题的核心在于,在源码中weex定义了固定的category,上面的代码片段可见privatefinalstaticStringWEEX="com.taobao.android.intent.category.WEEX";
还真是彻底,private + final,就是不让用户改呀。为了不出现这个尴尬的问题,我们只能copy了一份原生的Navigator,然后将这个值修改为唱吧独有的category。然后在注册module的时候,用我们的Navigator替换掉了原生的,才彻底解决这个问题。
新发坑-唱吧开发中新遇到的坑
ImageAdapter加载圆角抖动问题
集成过Weex的同学都知道,Weex需要客户端自己去实现图片加载的方法,对于Android来说,就是实现ImageAdapter。但是在实现了之后,出现了一个问题:在加载圆角图片时会先显示直角图片,刷新一次后再变成圆角。一般情况下,加载圆角图片是由JS布局实现,并没有在客户端做特殊处理。
根据网上一些踩坑经验来看,这个问题也出现过,问题主要是:weex sdk代码中,在加载图片的时候做了64ms延时造成的,配合在新版本weex sdk解决了这个问题。
但是,我们在按照对应的方法修改后,依旧没有解决这个问题。经过一系列排查后,发现了产生问题的原因。唱吧的网络图片加载使用的是Glide,所以ImageAdapter自然是使用Glide去实现。因为需要实现weex中的WXImageStrategy.ImageListener,所以需要采用Glide回调的方法,监听图片加载成功的事件。最早采用了Glide中load DrawableTarget方式,但是这个时候,Glide会先对imageview set原始图片并显示出来,然后JS的布局才会生效,此时会在界面上先展示方形的图片,在滚动后,会显示圆角图。为了解决这个bug, 就使用了Glide load SimpleTarget方法,这个方法首先获取图片资源,然后JS会优先布局,之后再将处理过的图片资源设置在imageview上。
坑王驾到-几个空格引发的血案
这个坑算是目前为止,Android客户端引入Weex后,踩过的最大的坑了。
这个问题的发现还是在客户端灰度期间,有少部分用户反馈:Weex页面加载白页,整个页面没有加载出来。这个问题一开始并没有引起足够的重视,以为有可能是因为用户网络不好或者类似原因,导致没有加载出来。但是,随着与用户的深入了解才发现,加载不出来的用户,无论怎样,即使卸载重装,依然无法加载出Weex的页面。而通过我们的crash统计和我自己的异常统计埋点,都没有发现任何错误信息。当时的我是完全懵逼的,感觉这个问题根本无从下手。不过,经过反复的分析和对源码的解析,问题锁定在了该页面的JS文件上。幸好在开发之初,就想到了JS Bundle的加载可能会出现问题,所以在我们在源码基础上,扩展了JSExceptionAdapter,将JS Budnle的exception也做了统计,并且以file的形式存在了本地。
拿到了exception file后,我发现,这些显示白页的用户,都是在JS createInstance的时候出现了错误(对应的error code是WXRENDERERRJSCREATE_INSTANC)。根据错误进行反向推测(这个过程很痛苦。。。),最终发现了问题的根源:我们通过vue生成js文件,被Weex当作普通网页进行加载,而此时加载js使用的是原生的chromium。但是部分机型的chromium由于某种原因(Android碎片化。。)被篡改了,导致会有部分方法not found,最终导致create instance失败。而这一切的根源就是因为,我们的js文件并没有被当作Vue去解析。而为什么我们的js会被错误的识别,这个就是真正的坑所在。
我们先来看一下Weex是如何对JS的type进行判断的:
在这里先普及一个小知识,Weex的页面是使用的Vue进行开发,在Vue开发好后,通过webpack进行编译,生成最终JS脚本。而Weex对应的JS脚本在头部会有一个固定的标记:
而在Android客户端,Weex就是通过这个标记来判断这个JS脚本的type的(Weex的bundle type有三种:vue、rax、others):
由上面的代码片段可见(完整代码详见com.taobao.weex.bridge.WXBridgeManager),Weex判断type的方式采用的是简单粗暴的字符串匹配,而且是强匹配。
而我们的Vue在编译成JS脚本的时候,由于webpack配置的失误,导致在“// { "framework": "Vue" }”后面多了一个空格,而“Vue”后面少了一个空格。所以我们的JS脚本就被当作Others type了,由此出现了以上所说的一系列问题。
虽然这个问题最终还是修复了,但是总感觉这种强匹配方式本身就会造成很多的问题,真的是多一个或者少一个空格都不行。真的希望未来Weex能优化这部分,毕竟这种判断方式还是略显粗暴了。。。
说在最后
To be honest,Weex框架是一个很不错的框架,并且经过几年的线上运行,成熟度已经很高了。而且,从更深层次讲,很佩服阿里的工程师们,开发出了这么一套优秀的框架,毕竟从基础架构的开发贡献上来讲,国内整体还无法超越Google、Facebook、微软等公司。虽然Weex还是会有一些不完美的地方,但是随着版本的迭代,相信一切会越来越好。
以上是关于唱吧Android Weex集成踩坑实录的主要内容,如果未能解决你的问题,请参考以下文章
Android 10 踩坑实录 👉 2020-01-20
踩坑实录 Android studio中关于 No cached version of **** available for of处理办法