移动开发Weex原理之带你去蹲坑

前言

 本篇将节操满满的安利Weex(˶‾᷄ ⁻̫ ‾᷅˵),不一样的角度推荐你入坑,官网有的我们不拖泥,这里将给你补充官方没有的,深入到蹲坑给你排忧解难,总会给你点惊喜,内容越后越干,请紧张的往下看。

一、简介

 有对比才有伤害,说到Weex,难免让人联系React Native。虽同为跨平台移动端解决方案,拥JavaScript妄一统天下,单两者的设计理念其实截然不同。

 这里先介绍下两者的差异,给徘徊在 React Native 和 Weex 之间的人,理解更适合哪些场景。

类型React NativeWeex
性能较好较弱
上手难度稍高容易
核心理念ReactVue
框架程度较重较轻
特点适合开发整体App适合单页面
社区丰富,Facebook维护略残念,目前托管apache
支持Android、IOSAndroid、IOS、Web
适应性原生开学习成本低Web开发学习成本低
JS引擎JSCoreV8

 作为两个框架的深度体验者,个人总结出上面的对比,其中可以看出:

  • React Native更适合开发完整的App,因为它的性能较好,第三方插件丰富,社群活跃并且维护较好,文档完整等(本篇主角是Weex好吧魂淡(#゚Д゚))。

  • Weex更适合开发单页面集成,这也是阿里的业务特性。
    当然Weex也可以开发完整的多页面App,同时我也是这么用过,不过效果对比React Native,显然强差人意。

  • Weex胜在容易上手,基于Vue的设计模式,类MVVM的实现,也让前端能更无缝的实现一些高性能的App业务。

  • Weex兼容Android、IOS、Web三端,在单页面的实现上,它有着React Native无法睥睨的先天优势。

  • Weex的社群,个人觉得还是弱,资料不足,文档简单,第三方支持太弱。和React Native一样支持带原生功能的插件开发,但是,支持太少了,这也提高了后期的开发门槛。同时,一个小问题很容易让入初学者,三过门而不入,作为一个发布了两年的框架,还是比较让人吐槽的。

 

二、原理

 这里简要说明下Weex在android下的分层以及原理。

 Weex主要包括三大部分:JS BridgeRenderDom,分别对应WXBridgeManagerWXRenderManagerWXDomManager 。通过WXSDKManager统一管理。其中JS BridgeDom运行在独立的HandlerThread中,而Render运行在UI线程。JS Bridge主要用来和 JS 端实现进行双向通信,比如把js端的dom结构传递给Dom线程。Dom主要是用于负责dom的解析、映射、添加等等的操作,最后通知UI线程更新。而Render负责在UI线程中对dom实现渲染。

 如下图,是生成dom,dom的解析,映射,添加,渲染的流程。

 

 如上可知,因为JS端运行于独立的单线程中,所以为了保证运行的流畅性,一般需要避免在JS端执行耗时操作,比如:网络请求,图片加载等,其实都是在原生端完成,js端执行的是发起一个请求和响应一个结果。同时因为原生端与JS端是通过JS Bridge通讯,所以也需要尽量避免大数据和频繁的通讯,导致响应的延迟。

 原生端的dom的加载解析映射,也是性能的一大瓶颈。一般而言,Weex在Web端生成的,是通过webpack的webConfig打包成单页面的index.web.js文件;而在原生端,一般会通过webpack的weexEntry配置成多页面形式:即每一个需要独立的.vue的页面,最终会被打包成一个.js文件。所以打开每个页面时加载对应的js文件,这很好的减小了需要加载的文件大小,提高了dom的解析效率。最后,Weex默认打的js只包含业务js代码,基础js库已经被包含在weex sdk中,也使得体积会小很多。

三、入门

1、配置环境

 程序员就要从配置环开始,Weex 环境搭建 ,点击链接,只要你要一个稳定的网络,参考官网搭建环境,也就一杯茶的功夫,take it easy。配置好之后,weex create testProject创建一个项目High起来吧。

2、快速入门

 weex的入门还是比较简单的,JavaScript、Vue了解下,即可预约的hello world。

 原生开发也许对vue接触不多,跨界有时候很容易望而却步,其实Vue本身,就是容易上手的框架,类似MVVM的模式(类似Android的DataBinding),很容让人理解上手,简单的说,你只关心数据,然后绑定到显示的控件,就是这么简单。

 一般通过 Vue官网 教程,30分快速撸一发,之后你就直接入门Weex了,对,Weex做的最彻底的就是,你直接使用 vue 写一个Web页面,之后再顺手编译成了 ios 和 android 的原生页面(尽管有些时候你需要在平台适配上花费心思)。

 

 如上图(请忽略那个this( ̄. ̄)),这就是一个极度简化的,用Vue写的Weex页面。效果是从显示Hello World ,一秒变I’m CarGuo,就是这么自信。

 在<template>中排布需要渲染的控件,在<style>中指定控件的样式(当然你也可以直接在<template>中),在<script>中写数据获取和处理逻辑等,是不是很简单, Don’t be shy,Let's fuck it !

 因为需要支持三端,Weex在Vue的基础上阉割了一些标签、css样式和事件,具体可见与 Web 平台的差异

 其中,在Android和IOS上,<text> <image>等标签,其实是被编译为原生控件,这就是上面所说的dom解析,同时你也可以在原生端,自定义控件或者功能模块,然后注册到weex中使用,实际上weex提供的基础控件和功能模块并不多,但却很容易拓展,具体可见 拓展原生端功能

(ps 也不知道阿里是怕做多错多,还是懒)

 说到这里,就需要说一说Weex的原生插件开发支持,这也是官方文档比较没整理好的原因,其实文档是有的:Weex插件开发文档,如Android插件大致流程就是:

  • weex plugin create命令创建插件。
  • 在android目录的library下通过@WeexComponent(控件)、@WeexModule(非UI功能)、@WeexAdapter(weex继承功能拓展)实现第三方支持。
  • 将library发布到maven (当然你也可以直接源码发布到npm)
  • 配置根目录的package.json然后发布到npm

 由此可见,weex可以很方便的提供原生功能的拓展支持,但是由于社群较为薄弱,导致第三方插件缺失,有(hen)些(duo)时候你可能不得不自己着手,开发原生端的功能支持,这就对于跨平台开发而言,特别前端开发而言,就稍(te)显(bie)不友好了。

目瞪狗带

题外话 :说到跨平台开发,也许你听说过cordova这位老大哥,它曾是早期的跨平台开发潮流,cordova提供丰富的原生插件和打包功能:通过webview把前端页面打包成一个App,通过插件提供前端需要的原生接口,交互通过webview的js接口支持。为什么说起它呢,是因为Weex中,你可以看到很多cordova的影子,类似weex platform add androidweex plugin add xxx都有些cordova的味道。如下图,你如今依旧可以在Weex中找,寻找到cordova的存在感。

cordova残留

3、其他推荐

Vuex 和 Vue-Router ,居家旅行必不可少。

  • Vuex类似Redux,如果你没听说Redux不要紧,也不要怂,简单了说,Vuex就是单页面下,帮你管理数据的框架。数据都存在Vuex的store中,你操作store更新数据,然后将store绑定到界面。它的用处在于可以在多个vue组件间,方便的同步数据,更新界面。

  • Vue-Router也是用于单页面下,指定跳到某个页面的管理工具,路由嘛,浅显易懂。

iconfont :矢量图标,少不了iconfont,通过字库生成图标,资源丰富,绝对值得推荐。

weex-ui: weex中难得的良心官方封装库。

eros :eros 不是框架,是基于 weex 封装、面向前端的 vue 写法的一整套 APP 开源解决方案,是由本木医疗大前端团队经过大量实践沉淀而出。。

四、深入填坑

1、ES6、ES7

  说到 Javascript ,ES6、ES7必须了解下。Weex中默认就有对其支持,但是对于async、await等,还需要如下一些简单配置,然后 have fun 。

//命令行安装
npm install --save-dev babel-plugin-transform-runtime

//然后在.babelrc文件中加入
{
"presets": [
"es2015",
"stage-0"
],
"plugins": [ [
"transform-runtime",
{
"helpers": false,
"polyfill": false,
"regenerator": true,
"moduleName": "babel-runtime"
}
]]
}

2、多页面

 Weex默认是单页面效果,也就是Android中一个Activity的概念,而单页面效果在原生上,跳转一多效果就会web了。既然叫native,怎么可能如此too young,所以这个时候,就需要修改默认的webpack,让其支持naive多页面了ı╮(╯▽╰)╭。

 首先,要知道Weex真正运行的是,通过entry.js作为入口文件文件,通过webpack,将.vue文件打包成index.js进行使用。Look,多页面的重点,就是将独立页面的.vue文件,生成多个js文件。

入口js

 如上图,参考entry.js文件,创建一个SecondPageEntry.js,作为SecondPage.vue的入口,用于webpack生成SecondPage.js页面。

 什么?webpack没听说过怎么办,No problem,你只需简单的修改,一知半解完全可以胜任。如下图,我们主要需要修改webpack.common.conf.js文件,

webpack.common.conf.js

 可以看出,webpack.common.conf.js中,其实是区分了webConfig和weexConfig的不同打包方式。如下图,其中weexEntry就是我们需要修改的地方,可以看到本来已经有index和entry.js存在了。

 最后我们需要通过navigator来实现跳转,我们需要知道,要跳转的js文件在哪里,如下代码演示,如何实现navigotor的native跳转,完整兼容三端跳转请移步demo项目。

 //获取当前js文件所在完整路径
 let bundleUrl = this.$getConfig().bundleUrl;
 bundleUrl = String(bundleUrl);
 let nativeBase;
 //android一般位于file://assets目录下
 let isAndroidAssets = bundleUrl.indexOf('file://assets/') >= 0;
 //ios一般位于一般带有file开头,带有WeexDemo.app
 let isiOSAssets = bundleUrl.indexOf('file:///') >= 0 && bundleUrl.indexOf('WeexDemo.app') > 0;
 if (isAndroidAssets) {
     nativeBase = 'file://assets/dist/';
 } else if (isiOSAssets) {
     nativeBase = bundleUrl.substring(0, bundleUrl.lastIndexOf('/') + 1);
 } else {
    let host = 'localhost:8080';
    let matches = /\/\/([^\/]+?)\//.exec(bundleUrl);
    if (matches && matches.length >= 2) {
        host = matches[1];
    }
    nativeBase = 'http://' + host + '/index.html?page=./dist/';
 }
 return nativeBase;

3、样式sass\scss

sass,后期必不可少的利器。

 当你的weex项目不断变大,一些样式共享,公共颜色,大小尺寸等的管理,就是你需要面对的问题。

 这时候sass和scss就可以起到很大的作用。最大优点是,它可编程,支持定义变量,而且不像阉割后的css一样,var()这种写法无法在native下得到支持,这时候sass的效果绝对让你回味无穷。

 使用sass也十分简单,简单配置下webpack,sass的语法也十分容易上手,只需十分钟了解下就可以愉快的享用这块糖了。

  • 先安装sass依赖:
npm install node-sass;
npm install sass-loader; //依赖node-sass
  • 之后webpack.common.conf.js中配置loader,如下图,在两个module处,增加红框配置。

  • 最后用 import 引入的sass文件进行加载,详细可查看demo工程。
//也可以 lang="scss"
<style lang="sass">
//导入写好的文件
@import "./style.scss";
</style>

五、蹲坑

 其实就是问题集锦,记录一些开发过程中遇到的问题,相信你会喜欢:

  • 1、关于vue的<scrpit>标签内,weex.requireModule(包括插件weex-ui)中,在全局获取返回null的原因,是因为entry.js中的router对象,不能用import 和 export default,只能用require 和 module.exports 配合。

  • 2、es6一些语法问题,如async和await,可以用"babel-plugin-transform-runtime",在.babelrc中设置。

{
"presets": [
"es2015",
"stage-0"
],
"plugins": [ [
"transform-runtime",
{
"helpers": false,
"polyfill": false,
"regenerator": true,
"moduleName": "babel-runtime"
}
]]
}
  • 3、export default 和require混合使用的时候,会多一个default对象,比如this.$store.default.state这样才对的问题。

  • 4、自定义的js文件类中,不能使用全局的weex.requireModule

  • 5、使用weex-ui的tabbar结合是,<list>必须有高度,或者overflow属性为scroll才能滑动,而且overflow的位置必须是不会影响其他页面位置。

  • 6、全屏默认height 1334 和 width 750,但是记得减去32大概高度的statusbar。

  • 7、list的loadmore,必须给list设置高度样式,才能在web中正常触发。

  • 8、text的</text>结束标签换行,在debug下可能会出现样式问题。

  • 9、生命周期在web中与android等不同,比如activated等。

  • 10、()=> {}对于this可能获取存在的不同,尽量用function(){}。

  • 11、多页即创建多个类似entry.js的入口文件,在webpack下配置weex的打开生成的js文件,用于navigator跳转,通过url传值。

  • 12、android多页面打开失败

android.os.FileUriExposedException问题:

在你的Application中添加:
if (Build.VERSION.SDK_INT>=18) {
StrictMode.VmPolicy.Builder builder = new StrictMode.VmPolicy.Builder();
StrictMode.setVmPolicy(builder.build());
builder.detectFileUriExposure();
}

ActivityNotFoundException问题:

 <activity
         android:name=".xxxxxx"
         android:label="@string/app_name"
         android:screenOrientation="portrait"
         android:theme="@style/AppTheme.NoActionBar">
     <intent-filter>
         <action android:name="com.taobao.android.intent.action.WEEX"/>

         <category android:name="android.intent.category.DEFAULT"/>
         <category android:name="com.taobao.android.intent.category.WEEX"/>
         <action android:name="android.intent.action.VIEW"/>

         <data android:scheme="http"/>
         <data android:scheme="https"/>
         <data android:scheme="file"/>
         <data android:scheme="wxpage" />
     </intent-filter>
 </activity>
  • 13、多页面生成js时,import的时候,需要指定.vue后缀的。

  • 14、如果是webstorm,记得对.temp dist node_modules platforms几个文件夹,右键设置excluded,避免一直indexing和硬盘资源消耗。

  • 15、@viewappear="onappear" @viewdisappear ="ondisappear" 类似onPause和onResume

  • 16、ios实时看log,可以先增加

-(void)redirectConsoleLog{
#ifdef DEBUG
    NSString *documentDir = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0];
    NSLog(@"documentPath : %@",documentDir);

    //重定向NSLog
    NSString* logPath = [documentDir stringByAppendingPathComponent:@"console.log"];
    freopen([logPath fileSystemRepresentation], "a+", stderr);
#endif
}
//调用
[self redirectConsoleLog];

然后在Devices下,找到对应的模拟器号码,在再Application下,搜索console.log,跟踪执行

tail -f
/Users/your name/Library/Developer/CoreSimulator/Devices/FDEACA11-D84E-4E8F-A6B8-26239559A928/data/Containers/Data/Application/9394D6CC-6B4A-4200-A13D-0CBE6F2BB67A/Documents/console.log

最后

分享移动开发与微信小程序开发该做哪些!其中有哪些关键的技术点!需要下图学习教程的欢迎加入Android开发技术交流群:150923287获取!

欢迎加入Android开发技术交流群:150923287,获取上图中的技术教程! 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值