Weex-Android 教程 - 从入门到放弃

Updated on with 0 views and 0 comments

序言

我所在的公司是一家外包公司,项目很多可是只有我一位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.使用

向你的前端小伙伴要一份资源文件,或者拉下他们的代码

image.png

weex项目的目录大概长这样,dist就是我们要使用的资源文件了
将里面的文件拉到android 的 assets 文件夹里

image.png

就可以尝试在你的Activity里启动weex页面啦

image.png

直接使用
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比如

image.png

然后创建一个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就用于引入原生的控件,比如说实现一个原生的折线图
首先要前端定义一下
image.png

lineChartView 就是我们的 Component名,data就是回传给我们的JSon数据
定义一个Component继承WXComponent

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。
image.png

我觉得仅仅因为这两点就不建议没有技术深度的小公司使用了。

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使用起来其实还是比较简单的,但是文档欠缺,坑也有很多。要弄懂它需要花费点时间,见仁见智吧

参考资料
Weex文档
Weex同步问题