Weex 开发技术

Posted 百果科技研发团队

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Weex 开发技术相关的知识,希望对你有一定的参考价值。

Weex 开发技术

1 前言

 PREFACE

    Weex 是一个使用 Web 开发体验来开发高性能原生应用的框架。Weex 致力于使开发者能基于当代先进的 Web 开发技术,使用同一套代码来构建 androidios 和 Web 应用。具体来讲,在集成了 WeexSD之后,你可以使用 javascript 和现代流行的前端框架来开发移动应用。Weex 的结构是解耦的,渲染引擎与语法层是分开的,也不依赖任何特定的前端框架,目前主要支持 Vue.js 和 Rax 这两个前端框架。Weex 的另一个主要目标是跟进当代先进的 Web 开发和原生开发的技术,使生产力和性能共存。在开发 Weex 页面就像开发普通网页一样;在渲染 Weex 页面时和渲染原生页面一样。对于移动开发者来说,Weex 主要解决频繁发版和多端研发的两大痛点,同时解决了前端语言性差和显示效果受限的问题,Weex 的思想是多个平台,只写一套代码,Weex 的目标在于抹平各个平台的差异性,从而简化应用 开发。 开发者只需要在自己的app中嵌入 Weex 的 SDK,就可以通过编写 html/css/js 来开发native 级别的 Weex 界面,Weex 界面的生成码其实就是一段很小的 js,可以像发布后台代码一样轻松的部署在服务器,然后在 app 中 请求执行。支持 ES6 规范,性能优异,开发简洁标准,体积小巧,跨平台,支持双重热更新。

基本知识

BASIC KNOWLEDGE

最简单的例子

Weex 开发技术

1:在源代码的中,你应该很熟悉了,它在 Weex 平台上也是一个通用容器。但是组件是由 Weex 特有的,它是一个块级的文本容器,可以用来渲染文字。

2:文本只能放在标签里,否则将被忽略。

3:在上面的例子中,和在移动端上渲染出来的都是原生组件,而不是 HTMLElement。

支持多个前端框架

1:前端框架对 Weex 而言只是一个语法层,它们和原生渲染器是解耦的。Weex 并没有强绑定与某个特定的前端框架,而是可以把渲染原生 UI 的 能力赋予某些前端框架。

2:目前 Weex 将 Vue.js 和 Rax 作为其内置的前端框架。Vue.js 和 Rax 都已 经集成进了 Weex SDK,你不需要再额外引入。

Weex 开发技术

一次编写,处处运行

1:Weex 可以只编写一份代码,开发出三端都可用的页面。

2:在多个端中使用相同的源代码可以显著提高开发效率,并简化测试,构建 和发布流程。在此基础上,Weex 可以将前端的打包、测试流程与手机端 监控、发布系统结合起来,提高开发效率。

3:尽管 Weex 多端都是用的同一份代码,但是仍然支持针对特定的平台开发 功能。Weex 提供了 weex.config.env 和 WXEnvironment(它们是相同的) 来获得当前的运行时环境。你可以用 WXEnvironment.platform 来确定代 码运行在哪个平台上。除了平台以外,WXEnvironment 还包含其他环境信息,如 osVersion 和 deviceModel。

Weex 环境搭建

1:安装依赖 node.js(通过 node -v 和 npm -v 查看是否安装成功和当前版本号)

2:安装 Weex:npm install -g weex-toolkit(通过 weex -v查看版本号)    

3:初始化项目:weex create weex-demo(npm install)

4:npm run dev & npm run serve(开启 webpack watch 模式和 HotReload 服务器)

5:weex platform add ios/android(添加特定平台的项目)weex run ios/android

app 集成 Weex 有两种方式

1:源码依赖:能够快速使用 Weex 最新功能,可以根据自己项目的特性进行 相关改进。

2:SDK 依赖:Weex 会在 jcenter 定期发布稳定版本。 我们采用:SDK 依赖

举例 SDK 依赖接入( Android )

1:准备

* 已经安装 JDK 环境,并且 version >= 1.7

* 已经安装 Android SDK 并配置环境变量

Android SDK version 23 (compileSdkVersion in build.gradle)

SDK build tools version 23.0.1 (buildToolsVersion in build.gradle)

2:接入

* 安装 AndroidStudio,创建 Android 工程

* 修改 build.gradle 加入 weex 基础依赖

* 设配 IWXImgLoaderAdapter

* 在 Application 初始化 Weex

* 在需要的入口处通过 WXSDKInstance.render() 开始渲染

组件

1:Weex 在 iOS 和 Android 上都实现了一个渲染引擎,并提供了一套基础的 内置组件。基于这些组件,你可以用 js 封装更多的上层组件。

2:尽管 Weex 中的组件看起来很像 HTML 标签,但你无法使用所有 HTML 标签,只能使用内置组件和自定义组件。

3:在框架内部,Weex 使用的是原生系统提供的 Widget 来渲染的。尽管 Weex 强调每个跨平台的一致性,但我们仍然接受平台本身的行为和 UI 差异。 例如 switch 组件 在 Android 和 iOS 上看起来是不同的(在 Web 端的外观模 拟了 iOS)

Weex 开发技术

18 个内置组件

Weex 开发技术

模块

1:对于那些不依赖于 UI 的功能,Weex 推荐将它们包装到模块中,然后使用 weex.requireModule('xxx') 来引入,这是使用 javascript 调用原生功能的一种方法,也可以叫做 API,如网络,存储,粘贴板和页面导航等功能。

2:同样,Weex 也提供了一套基础的内置模块,也支持将已有的原生模块集成到 Weex 中。

13 个内置模块

Weex 开发技术

通用事件

    Weex 提供了通过事件触发动作的能力,例如在用户点击组件时执行 JavaScript。下面列出了可被添加到 Weex 组件上已定义事件动作的属性:

    1:click 事件( input 和 switch 组件目前不支持 click 事件,请使用 change 或 input 事件来代替)

    2:longpress 事件( input 和 switch 组件目前不支持 click 事件,请使用 change 或 input 事件来代替)

    3:appear/disappear 事件(如果一个位于某个可滚动区域内的组件被绑定了 appear 事件,那么当这 个组件的状态变为在屏幕上可见时,该事件将被触发)

    4:Page 事件( viewappear 和 viewdisappear 分别是打开页面,和关闭页面时触发;仅支持 iOS 和 Android,H5 暂不支持;必须绑定到页面的根元素)

通用样式

    1:盒模型( Weex 盒模型基于 CSS 盒模型,每个 Weex 元素都可视作一个盒子)。

    2:Flexbox( Weex 布局模型基于 CSS Flexbox,以便所有页面元素的排版能够一致可预测,同时页面布局能 适应各种设备或者屏幕尺寸。Flexbox 包含 flex 容器和 flex 成员项。如果一个 Weex 元素可以容纳其他元素, 那么它就成为 flex 容器)。

    3:定位 position(Weex 支持 position 定位,用法与  CSS position 类似)  

    4:transform(transform 属性向元素应用 2D 转换。该属性允许我们对元素进行旋转、缩放、移动或倾斜)

    5:transition ( v0.16.0+ 您可以在 CSS 中使用  transition 属性来提升您应用的交互性与视觉感受)

    6:伪类( Weex 支持四种伪类:active,focus, disabled,enabled )

    7:线性渐变( Weex 支持线性渐变背景)

    8:阴影( box-shadow )( Weex 支持阴影属性:active,focus,disabled,enabled inset(可选), offset-x,offset-y,blur-radius,color)

    9:其他基本样式:

        * opacity {number}:取值范围为 [0, 1] 区间。默认值是 1,即完全不透明;0 是完全透明;0.5 是 50% 的透明度。)

        * background-color {color}:设定元素的背景色,可选值为色值。

        支持 RGB( rgb(255, 0, 0) )

        RGBA( rgba(255, 0, 0, 0.5) )

        十六进制( #ff0000 )

        精简写法的十六进制( #f00 )

        色值关键字(red)

        默认值是 transparent

拓展知识

EXPAND KNOWLEDGE

拓展

    * Weex 内置 18 个组件(Component)

    * Weex 内置 13 个模块(Module)

    * 如果内置组件或者模块没法满足开发需求,有解决方案吗?应该怎么做呢?

    * Weex 是一个跨平台的解决方案,扩展其内置组件或模块,需要在三端(Android、iOS、Web)中都有相应的实现。

    * 那么 Android,iOS,Web 分别是怎么来拓展的呢?

拓展 - Web

    * Vue.js 本身就是一个独立的前端框架,在浏览器中完全能够不基于 Weex 容 器渲染。因此,针对 Weex 平台扩展 Vue.js 的 Web 端组件,和直接使用 Vue.js 开发一个  Web 组件是一样的。具体的组件编写方法可以参考其官方文档, 另外要使用 .vue 格式的文件编写组件。

    * Weex 将内核切换成 Vue 2.x 之后,在 Web 端扩展 Vue 组件将变得更加容易。

    * 目前 Weex 提供了 weex-vue-render 作为 Vue 2.x Web 端的渲染器。首先引入该库到你的项目里,然后你就可以使用 weex.registerComponent 来进行内置组件扩展了,也可以使用 Vue.component,两者基本上是一致的。

扩展 - Web 组件示例

    * 以扩展为例,首先应该编写组件自身的逻辑:

Weex 开发技术

然后在使用之前,全局注册组件:

Weex 开发技术

    * 在扩展 Weex 组件时,如果只使用了 Weex 提供的内置组件,并且使用的都是 Weex 支持的样式,那么就和普通的自定义组件无异,不需要 Native 端再有相应的实现。

    * 如果你定制组件时不得不用到目前 Weex 不支持的标签和样式,在这种情况下才是真正的 “扩展”了 Weex 的组件,你还需要在 Android 和 iOS 中有相应的实现,不然会导致渲染异常。

扩展 - Web 模块

    * 除了通用组件以外,Weex 还提供了通用的模块,可以方便的调用原生 API。通常来说,注册 Weex 模块要求三端都得有相应的实现,否则会影响其正常的使用。

    * 如果你引入了 weex-vue-render 这个库,那么在全局能获取到 weex 这个变量,其中提供了 registerModule 方法可以注册模块。

    * API 格式: registerModule name: {String} 必选,模块名称。 

    define: {Object} 必选,模块的定义。 

    meta: {Object} 可选,如果你需要将非 iterable 的属性或方法注册到模块对象里,你才需要用到这个参数,将 { registerType: 'assignment' } 作为 meta 参数传入即可。

扩展 - Web 模块示例

Weex 开发技术

拓展 - Android

    * Weex 提供了对 Android 扩展机制,可以根据自己的业务进行定制自己的功能。

    * Component 扩展实现特别功能的 Native 控件。例如:RichTextview, RefreshListview 等。

    * Module 扩展非 UI 的特定功能。例如 sendHttp、openURL 等。

    * Adapter 扩展 Weex 对一些基础功能实现了统一的接口,可实现这些接口来定制自己的业务。例如:图片下载等。

    * Component 扩展类必须继承 WXComponent。

    * Component 对应的设置属性的方法必须添加注解 @WXComponentProp(name=value(value is attr or style of dsl))。

    * Weex sdk 通过反射调用对应的方法,所以 Component 对应的属性方法必须是 public,并且不能被混淆。请在混淆文件中添加代码 

- keep public class * extends com.taobao.weex.ui.component.WXComponent{*;}。

    * Component 扩展的方法可以使用 int,double,float,String,Map,List 类型的参数。

    * 完成 Component 后一定要在初始化时注册 WXSDKEngine.registerComponent("richText", RichText.class)。

扩展 - Android 组件示例

Weex 开发技术
Weex 开发技术

扩展 - Android 模块

    * Module 扩展必须继承 WXModule 类。

    * 扩展方法必须加上 @JSMethod (uiThread = false or true) 注解。Weex 会根据注解来判断当前方法是否要运行在 UI 线程,和当前方法是否是扩展方法。  

    * Weex 是根据反射来进行调用 Module 扩展方法,所以 Module 中的扩展方法必须是 public 类型。

    * 同样因为是通过反射调用,Module 不能被混淆。请在混淆文件中添加代码: -keep public class

    * extends com.taobao.weex.common.WXModule{*;}。

    * Module 扩展的方法可以使用 int,double,float,String,Map,List 类型的参数。

    * 完成 Module 后一定要在初始化时注册 WXSDKEngine.registerModule("myModule", MyModule.class);  否则会报类似错误:ReportException :undefined:9: TypeError: Object #

扩展 - Android 模块示例

Weex 开发技术

拓展 - iOS

    * Weex 提供了对 ios 扩展机制,可以根据自己的业务进行定制自己的功能。  

    * Weex 所有暴露给 JS 的内置 module 或  component API 都是安全和可控的,它们不会去访问系统的私有 API,也不会去做任何 runtime 上的 hack 更不会去改变应用原有的功能定位。

    * 如果需要扩展自定义的 module 或者 component ,一定注意不要将 OC 的 runtime 暴露给 JS,不要将一些诸如 dlopen(),dlsym(),respondsToSelector:,performSelector:,method_exchangeImplementations() 的动态和不可控的方法暴露给 JS,也不要将系统的私有 API 暴露给 JS。

    * 以下示例都以 Objective-C 编写,也支持 swift 编写。

拓展 - iOS 组件

    * 新建一个基类为 WXComponent 的 class,如果此时我们什么都不做,将该组件注册进 WeexSDK  engine,它的功能就跟内置的 div 组件功能是一致的。  

    * 覆盖 WXComponent 中的生命周期方法 loadView 和 viewDidLoad。

    * loadView():一个 component 默认对应于一个 view,如果未覆盖 loadView 提供自定义 view,会使用 WXComponent 基类中的 WXView,WXView 是继承自 UIView 的一个派生 view。假如要实现地图功能,我们需要对应的地图 view,比如系统的 MKMapView。

    * viewDidLoad():对组件 view 需要做一些配置,比如设置 delegate, 可以在 viewDidLoad 生命周期做,如果当前 view 没有添加 subview 的话,不要设置 view 的 frame,WeexSDK 会根据 style 设置。

拓展 - iOS 组件示例

Weex 开发技术

拓展 - iOS 组件示例

Weex 开发技术

拓展 - iOS 模块

Weex 开发技术

拓展 - iOS 模块示例

Weex 开发技术

图片适配

    * 分析:Weex 认为图片的加载可能涉及到图片的下载,本地文件系统的缓存,内存缓存,对于大量的尤其是大图加载,非常复杂,应该留给原生来实现,这样在效果上和效率上都会有优势。

图片适配 - Android

    * 以 Android 为例子:实现 IWXImgLoaderAdapter;

    * 重写方法 void setImage(String url, ImageView view, WXImageQuality quality, WXImageStrategy strategy);

    * 针对安卓项目可以存放图片的位置(drawable,mipmap,assets,file系统)

    * 支持前端写法:

Weex 开发技术
Weex 开发技术

图片适配 - iOS

    * 以 ios 为例子:实现 WXImgLoaderProtocol;

    * 重写方法 

(id)downloadImageWithURL:(NSString *)url 

imageFrame:(CGRect)imageFrame 

userInfo:(NSDictionary *)userInfo 

completed:(void(^)(UIImage *image, NSError *error, BOOL finished))completedBlock

    * 针对 ios 项目存放图片的位置(工程内默认 Image xcassets 或自建文件夹 resouces 或 bundle js,工程外 file 系统);

    * 支持前端写法:

Weex 开发技术
Weex 开发技术
Weex 开发技术

页面跳转适配

    * Weex 中的 navigator.push() 对苹果手机有效,对安卓手机无效,怎么适配? 

    * 分析:每次调用 navigator.push() 都会产生一个 http 请求的调用,格式如下: http:/detail.js?id=666&type=default 。

    * 方案:我们可以在安卓项目的清单文件 AndroidManifest.xml 监听这个 http 请求,进行捕获,把捕获到的 url 传到 Activity,然后再进行解析,解析到目标页面 detail.js 和参数 id=666&type=default,最后再调用 WXSDKInstance.render 进行渲染,从而实现页面跳转和传参。

Weex 开发技术
Weex 开发技术
Weex 开发技术

手机屏幕适配

    * 在 Weex 中,只支持 px 长度单位。并且它将在 JavaScript 运行时和本机渲染器中解析为数字类型(整数)。

    * 不支持类似 em,rem,pt 这样的 CSS 标准中的其他长度单位。

    * Weex 容器默认的宽度 (viewport) 是 750px。

    * 那么我们怎么来适配宽高,字体大小,图片尺寸呢?

Weex 开发技术

手机屏幕适配 - 结论

    * Weex 会根据屏幕的实际宽高,按照宽为 750px 的默认屏幕来适配(进行 缩放)我们定义的宽和高,以及字体大小(默认是 32px ),我们只需要按照 750px 的屏幕来设计和开发,并不需要用代码转换单位来适配。

    * 如何缩放宽高:定义 width = 500px 为例,那么在  1080px 的屏幕上,实际占用 x 满足以下比例:750/1080 = 500/x => x = 720

    * 如何缩放字体:定义 font-size = 32px 为例,那么在 1080px 的屏幕上,实际占用的 x 满足以下比例:750/1080 = 32/x => x =46 (注意是 46px,不是 46dp ) 在页面 https://github.com/apache/incubator-weex/blob/master/android/sdk/src/main/java/com/taobao/weex/dom/WXStyle.java com.taobao.weex.dom.WXStyle#getFontSize 可以看到源码,错误的计算方法:2/2.75 = 32/x => x = 44 (750/2)/(1080/2.75) = 32/x => x = 33。

手机屏幕适配 - 图片

    * 如果我们想在不同的屏幕显示不同分辨率的图片,应该怎么做呢?

    * 我们可以在客户端本地或者远程放多套不同分辨率的图片(2x/3x, hdip/xdip/xxdip/xxxdip)然后在生命周期函数 mounted() 里面根据本设备的 weex.config.env.scale 动态计算应该取加载哪一种分辨率的图片。

Weex 开发技术

总结

SUMMARY

    本文介绍了 Weex 的基本知识,包含组件,模块,以及在 3 端的拓展方法,也介绍了适配屏幕和和图片,Weex是一个轻量级的框架,很容易上手,很容易学会。目前淘宝系很多 app 都在使用。前端小伙伴们快学起来吧!


End

致力于为更多的程序员提供更好的技术



以上是关于Weex 开发技术的主要内容,如果未能解决你的问题,请参考以下文章

Weex开发系列:初识Weex

weex开发weex官方源码

weex 项目开发 weex 与 weexpack 的区别

weex 项目开发 weex + weex-ui

Weex技术剖析

Weex技术剖析