序言
我所在的公司是一家外包公司,项目很多可是只有我一位Android开发,为了能更有效率的接项目,经理决定让有Vue基础的几位前端开发配合我开发,于是就有了一篇踩坑的文章。
1.Weex是个啥?
Weex是阿里巴巴出品的一套类似React Native的混合开发技术,目标是一套代码,多端运行。(Web,IOS,Android)阿里自家的淘宝客户端上也有使用。能通过加载服务器js文件随时切换UI。
2.咋样用?
1.配置环境
在Android端的配置并不复杂,按教程设置gradle依赖,权限,然后在你的Application初始化
fun initWeexSdk() {
val config = InitConfig.Builder().build()
WXSDKEngine.initialize(this, config)
}
跟教程比少了两个Adapter,但是没关系,后面会讲到怎么用。
接下来就要封装一个简单的BaseWXActivity,继承IWXRenderListener
abstract class BaseWXActivity : BaseActivity(), IWXRenderListener {
var mWXSDKInstance: WXSDKInstance? = null
fun render(pageName: String, path: String) {
mWXSDKInstance?.isTrackComponent = true
mWXSDKInstance?.render(
pageName,
WXFileUtils.loadAsset(path, this@BaseWXActivity),
null,
null,
WXRenderStrategy.APPEND_ASYNC
)
}
protected fun renderPage(path: String) {
initSetting()
renderPage(path, null)
log("render - $path")
}
fun initSetting() {
mWXSDKInstance = WXSDKInstance(this)
mWXSDKInstance?.registerRenderListener(this)
}
override fun onRefreshSuccess(instance: WXSDKInstance?, width: Int, height: Int) {
log("onRefreshSuccess")
}
override fun onException(instance: WXSDKInstance?, errCode: String?, msg: String?) {
log("onException$msg")
}
override fun onViewCreated(instance: WXSDKInstance?, view: View?) {
log("onRenderSuccess")
}
override fun onRenderSuccess(instance: WXSDKInstance?, width: Int, height: Int) {
log("onRenderSuccess")
}
override fun onResume() {
super.onResume()
mWXSDKInstance?.onActivityResume()
}
override fun onPause() {
super.onPause()
mWXSDKInstance?.onActivityPause()
}
override fun onStop() {
super.onStop()
mWXSDKInstance?.onActivityStop()
}
override fun onDestroy() {
super.onDestroy()
mWXSDKInstance?.onActivityDestroy()
}
}
mWXSDKInstance?.registerRenderListener(this)是注册方法
而mWXSDKInstance?.render 则是调用界面的方法,因为我的项目都是导入本地的js文件,所以这里path用了 WXFileUtils.loadAsset
要使用Weex的Activity继承BaseWXActivity,在onCreate中调用initSetting,这样就简单的集成好环境开始正式使用了。
重点
当调用了render方法后,如果创建Weex界面成功,会回调onViewCreated这个方法,这个view就是我们的weex的界面了,你应该在将这个view显示在你的布局里,比如最简单的
override fun onViewCreated(instance: WXSDKInstance?, view: View?) {
setContentView(R.layout.activity_main)
}
2.使用
向你的前端小伙伴要一份资源文件,或者拉下他们的代码
weex项目的目录大概长这样,dist就是我们要使用的资源文件了
将里面的文件拉到android 的 assets 文件夹里
就可以尝试在你的Activity里启动weex页面啦
直接使用
renderPage("***.js")
就能看到要加载的页面了
3.原生咋跟Weex交互捏?
weex提供了三种工具让我们交互
Adapter: 图片,网络等加载相关
Moudle: 交互方法
Component: 组件
1.Adapter
weex不支持直接加载res里面的图片,于是需要一个图片的Adapter让weex可以读取到res资源,以下一个简单示例
class ImageAdapter : IWXImgLoaderAdapter{
override fun setImage(url: String?, view: ImageView?, quality: WXImageQuality?, strategy: WXImageStrategy?) {
if (url == null){
return
}
log("setImgageg$url")
val mUrl = url.replace("-","_").toLowerCase()
val context = MyApplication.mContext!!
val res = context.resources
val i = res.getIdentifier(mUrl.replace("/",""), "drawable", context.packageName)
if (i != 0){
view?.setImageResource(i)
strategy?.imageListener?.onImageFinish(url, view, true, null)
}
}
}
继承IWXImgLoaderAdapter,重写setImage方法,url即是请求的图片地址,为了兼容IOS这里做了点处理,设置view的资源,调用
strategy?.imageListener?.onImageFinish(url, view, true, null)
即可显示资源图片了,当然这里也可以使用Glide Pacasio 等图片缓存框架。
记得实现ImageAdapter 后需要给它注册一下。 initWeexSdk 方法就变成了
fun initWeexSdk() {
val config = InitConfig.Builder()
.setImgAdapter(ImageAdapter())
.build()
WXSDKEngine.initialize(this, config)
}
除了setImgAdapter,还有setHttpAdapter等Adapter,使用上也大同小异。
2.Moudle
Moudle可以理解为Weex跟原生交互的接口模块
首先应该跟你的前端伙伴定一下Api比如
然后创建一个ApiMoudle 继承WXModule 实现相关方法
class ApiMoudle : WXModule(),{
@JSMethod(uiThread = false)
fun getLanguage(callback: JSCallback){
var language = "en"
callback.invoke(language )
}
}
在Android 端的callback叫 JSCallback ,在IOS端叫WXMoudleCallback
调用JSCallback.invoke()即可将值回传到Weex端
完成ApiModule后再注册一下,我们的initWeexSdk就变成
fun initWeexSdk() {
val config = InitConfig.Builder()
.setImgAdapter(ImageAdapter())
.build()
WXSDKEngine.initialize(this, config)
WXSDKEngine.registerModule("swifter", ApiMoudle::class.java)
}
当Weex端调用getLanguage方法,即可通过callback回调拿到我们传进去的值了
3.Component
Weex的组件有时候不一定能满足实际需求,Component就用于引入原生的控件,比如说实现一个原生的折线图
首先要前端定义一下
lineChartView 就是我们的 Component名,data就是回传给我们的JSon数据
定义一个Component继承WXComponent<VIEW>
class LineChartComponent : WXComponent<LineChart>{
lateinit var lineChart: LineChart
@WXComponentProp(name = "data")
fun setData(source: String) {
}
override fun initComponentHostView(context: Context): LineChart {
lineChart = LineChart(context)
return lineChart
}
}
通过WXComponentProp获取传到原生的属性
重写initComponentHostView返回View
接着写完Component后再注册一下即可正常显示我们的View了
fun initWeexSdk() {
val config = InitConfig.Builder().setImgAdapter(ImageAdapter())
.build()
WXSDKEngine.initialize(this, config)
WXSDKEngine.registerModule("swifter", ApiMoudle::class.java)
WXSDKEngine.registerComponent("lineChartView", LineChartComponent::class.java)
}
4.听上去还蛮不错,为啥标题叫入门到放弃捏?
先说结论 小型公司不建议使用Weex作为商用项目
这里特指Android端
1.文档很敷衍
最基本的render的使用,callback的使用都一笔带过,想靠短短两页文档掌握Weex是不可能的,最终还要参考博客和实例。
2.性能
不得不说IOS端Weex的体验还是挺顺滑的,可是到了Android端就不一样了,加载页面时会有可观测的卡顿,一开始使用一个WXActivity多个fragment + 多个weex的形式卡顿特别明显,后来将weex放到fragment 使用一个普通Activity加多个WXFragment才稍微好点。如果你的App也是通过侧边栏切换多个fragment的,不建议用Weex。
我觉得仅仅因为这两点就不建议没有技术深度的小公司使用了。
5.如果我偏要用,有什么躲坑的小经验?
1.用return替代callback
文档都是使用callback来传数据的,但是实际上有些时候需要同步的返回数据,IOS端可以强制callback同步,但是android端没有这个方法,看了下示例才发现原来可以通过直接return的方式返回值。
class ApiMoudle : WXModule(),{
@JSMethod(uiThread = false)
fun getLanguage():String{
return "en"
}
}
2.关于跳转页面
如果你有Weex跳转界面的需求,你会发现在IOS端可以正常跳转,但是Android不生效(没错,IOS才是亲儿子)
方法1:按照教程配置manifest相关
方法2:(推荐)在Moudle中实现一个跳转方法,当weex调用该方法后,原生通过render跳转。
6.有啥补充?
Weex使用起来其实还是比较简单的,但是文档欠缺,坑也有很多。要弄懂它需要花费点时间,见仁见智吧