精华内容
参与话题
问答
  • 移动端跨平台技术总结

    千次阅读 2017-03-29 17:41:11
    概述曾经大家以为在手机上可以像桌面那样通过 Web 技术来实现跨平台开发,却因为性能或其他问题而放弃,不得不针对不同平台开发多个版本。...为了方便理解,笔者将跨平台技术分为4大流派: Web 流:也被称为 Hybrid

    概述

    曾经大家以为在手机上可以像桌面那样通过 Web 技术来实现跨平台开发,却因为性能或其他问题而放弃,不得不针对不同平台开发多个版本。这也违背了跨平台开发的初衷。而React Native让跨平台移动端开发在次回到人们的视野中,其成功的原因除了他“一次编写处处运行”,还因为它相比h5等前端技术,有了更接近原生的体验。
    为了方便理解,笔者将跨平台技术分为4大流派:

    • Web 流:也被称为 Hybrid 技术,它基于 Web 相关技术来实现界面及功能
    • 代码转换流:将某个语言转成 Objective-C、Java 或 C#,然后使用不同平台下的官方工具来开发
    • 编译流:将某个语言编译为二进制文件,生成动态库或打包成 apk/ipa/xap 文件
    • 虚拟机流:通过将某个语言的虚拟机移植到不同平台上来运行

    web流

    Web 流,如大家熟知的PhoneGap/Cordova等技术,它将原生的接口封装后暴露给 JavaScript,然后通过系统自带的 WebView 运行,也可以视野自己内嵌Chrome内核。
    Web 流最常被吐槽的就是性能差,渲染速度慢。现在说到 Web 性能差主要说的是 Android 下比较差,在 iOS 下已经很流畅了。
    说到性能差,主要原因是在Android和ios的早期设备中,由于没有实现GPU加速,所以造成每次重绘界面的卡顿。
    而造成渲染慢的第二个原因是:css过于复杂。因为从实现原理上看 Chrome 和 Android View 并没有本质上的差别,但过于复杂的css会加重gpu的负担。那是不是可以通过简化 CSS 来解决?实际上还真有人这么尝试了,比如 Famo.us,它最大的特色就是不让你写 CSS,只能使用固定的几种布局方法,完全靠 JavaScript 来写界面,所以它能有效避免写出低效的 CSS,从而提升性能。
    造成绘制缓慢的第三个原因是,业务需求的复杂,如要实现超长的 ListView商品展示。因为 DOM 是一个很上层的 API,使得 JavaScript 无法做到像 Native 那样细粒度的控制内存及线程,所以难以进行优化,则在硬件较差的机器上会比较明显
    上面三个问题现在都不好解决。其实除了性能之外,Web 流更严重的问题是功能缺失。比如 iOS 8 就新增 4000+ API,而 Web 标准需要漫长的编写和评审过程,而等到web审核通过,即便是Cordova这样的框架自己封装也是忙不过来的。所以为了更好地使用系统新功能,Native是最快的选择。
    虽然前面提到 HTML/CSS 过于复杂导致性能问题,但其实这正是 Web 最大的优势所在,因为 Web 最初的目的就是显示文档,如果你想显示丰富的图文排版,虽然 iOS/Android 都有富文本组件,但比起 CSS 差太远了,所以在很多 Native 应用中是不可避免要嵌 Web 的。

    代码转换流

    不同平台下的官方语言不一样,并且平台对官方语言的支持最好,这就导致同样的逻辑,我们需要写多套代码。比如Android平台用Java,ios用oc或者swift。于是就有人想到了通过代码转换的方式来减少重复的工作量,这就是所以的代码转换流。
    这种方式虽然听起来不是很靠谱,但它却是成本和风险都最小的,因为代码转换后就可以用官方提供的各种工具了,和普通开发区别不大。并且转换后,可以利用原生的优点,这也可以减少兼容的问题。
    目前存在的几种代码转换方式:

    将 Java 转成 Objective-C

    j2objc 能将 Java 代码转成 Objective-C,据说 Google 内部就是使用它来降低跨平台开发成本的,比如 Google Inbox 项目就号称通过它共用了 70% 的代码,效果很显著。
    可能有人会觉得奇怪,为何 Google 要专门开发一个帮助大家写 Objective-C 的工具?还有媒体说 Google 做了件好事,其实吧,我觉得 Google 这算盘打得不错,因为基本上重要的应用都会同时开发 Android 和 iOS 版本,有了这个工具就意味着,你可以先开发 Android 版本,然后再开发 iOS 版本。。。
    既然都有成功案例了,这个方案确实值得尝试,而且关键是会 Java 的人多啊,可以通过它来快速移植代码到 Objective-C 中。

    将 Objective-C 转成 Java

    除了有 Java 转成 Objective-C,还有 Objective-C 转成 Java 的方案,那就是 MyAppConverter,比起前面的 j2objc,这个工具更有野心,它还打算将 UI 部分也包含进来,从它已转换的列表中可以看到还有 UIKit、CoreGraphics 等组件,使得有些应用可以不改代码就能转成功,不过这点我并不看好,对于大部分应用来说并不现实。
    由于目前是收费项目,我没有尝试过,对技术细节也不了解,所以这里不做评价。

    将 Java 转成 C

    Mono 提供了一个将 Java 代码转成 C# 的工具 Sharpen,不过似乎用的人不多,Star 才 118,所以看起来不靠谱。
    还有 JUniversal 这个工具可以将 Java 转成 C#,但目前它并没有发布公开版本,所以具体情况还待了解,它的一个特色是自带了简单的跨平台库,里面包括文件处理、JSON、HTTP、OAuth 组件,可以基于它来开发可复用的业务逻辑。
    比起转成 Objective-C 和 Java 的工具,转成 C# 的这两个工具看起来都非常不成熟,估计是用 Windows Phone 的人少。

    XMLVM

    除了前面提到的源码到源码的转换,还有 XMLVM 这种与众不同的方式,它首先将字节码转成一种基于 XML 的中间格式,然后再通过 XSL 来生成不同语言,目前支持生成 C、Objective-C、JavaScript、C#、Python 和 Java。
    虽然基于一个中间字节码可以方便支持多语言,然而它也导致生成代码不可读,因为很多语言中的语法糖会在字节码中被抹掉,这是不可逆的,以下是一个简单示例生成的 Objective-C 代码,看起来就像汇编:

    XMLVM_ENTER_METHOD("org.xmlvm.tutorial.ios.helloworld.portrait.HelloWorld", "didFinishLaunchingWithOptions", "?")
     XMLVMElem _r0;
     XMLVMElem _r1;
     XMLVMElem _r2;
     XMLVMElem _r3;
     XMLVMElem _r4;
     XMLVMElem _r5;
     XMLVMElem _r6;
     XMLVMElem _r7;
     _r5.o = me;
     _r6.o = n1;
     _r7.o = n2;
     _r4.i = 0;
     _r0.o = org_xmlvm_iphone_UIScreen_mainScreen__();
     XMLVM_CHECK_NPE(0)
     _r0.o = org_xmlvm_iphone_UIScreen_getApplicationFrame__(_r0.o);
     _r1.o = __NEW_org_xmlvm_iphone_UIWindow();
     XMLVM_CHECK_NPE(1)
    ...

    终上所述,虽然代码转换这种方式风险小,但我觉得对于很多小 APP 来说共享不了多少代码,因为这类应用大多数围绕 UI 来开发的,大部分代码都和 UI 耦合,所以公共部分不多,其借鉴性意义不大。

    编译流

    编译流比代码转换流的代码转换更进一步,它直接将某个语言编译为普通平台下能够识别的二进制文件。采用这种方式主要有以下特点:

    优点

    • 可以重用一些实现很复杂的代码,比如之前用 C++ 实现的游戏引擎,重写一遍成本太高
    • 编译后的代码反编译困难

    缺点

    • 转换过于复杂,并且后期定位和修改成本会很高
    • 编译后体积太大,尤其是支持 ARMv8 和 x86等CPU架构的时候

    接下来,我们通过不同的语言来介绍这个流派下不同的技术实现。

    C++方案

    因为目前Android、iOS和Windows Phone都提供了对C++开发的支持。特别是C++ 在实现非界面部分,性能是非常高效的。而如果C++ 要实现非界面部分,还是比较有挑战的。这主要是因为Android 的界面绝大部分是 Java 实现,而在 iOS 和 Windows Phone下可以分别使用C++的超集Objective-C++和 C++/CX来开发。那么要解决用C++开发Android界面,目前主要有两种方案:

    • 通过 JNI 调用系统提供的 Java 方法
    • 自己画 UI

    第一种方式虽然可行,但是代码冗余高,实现过于复杂。那第二种方式呢,比如 JUCE 和 QT就是自己用代码画的。不过在Android 5下就悲剧了,很多效果都没出来,比如按钮没有涟漪效果。根本原因在于它是通过 Qt Quick Controls 的自定义样式来模拟的,而不是使用系统UI组件,因此它享受不到系统升级自动带来的界面优化。
    当然我们可以使用OpenGL来绘制界面,因为EGL+OpenGL本身就是跨平台的。并且目前大多数跨平台游戏底层都是这么做的。
    既然可以基于 OpenGL 来开发跨平台游戏,是否能用它来实现界面?当然是可行的,而且Android 4的界面就是基于OpenGL的,不过它并不是只用 OpenGL 的 API,那样是不现实的,因为 OpenGL API 最初设计并不是为了画 2D 图形的,所以连画个圆形都没有直接的方法,因此Android 4中是通过Skia将路径转换为位置数组或纹理,然后再交给 OpenGL 渲染的。
    然而直接使用OpenGL来做界面的绘制,代价是非常大的,并且目前在各个平台下都会有良好的官方支持。因此对于大多数应用来说自己画UI是很不划算的。

    Xamarin

    Xamarin 可以使用 C# 来开发 Android 及 iOS 应用,它是从 Mono 发展而来的,目前看起来商业运作得不错,相关工具及文档都挺健全。
    因为它在 iOS 下是以 AOT 的方式编译为二进制文件的,所以把它归到编译流来讨论,其实它在 Android 是内嵌了 Mono 虚拟机 来实现的,因此需要装一个 17M 的运行环境。
    在 UI 方面,它可以通过调用系统 API 来使用系统内置的界面组件,或者基于 Xamarin.Forms 开发定制要求不高的跨平台 UI。
    对于熟悉 C# 的团队来说,这还真是一个看起来很不错的,但这种方案最大的问题就是相关资料不足,遇到问题很可能搜不到解决方案,不过由于时间关系我并没有仔细研究,推荐看看这篇文章,其中谈到它的优缺点是:

    优点

    • 开发 app 所需的基本功能全部都有
    • 有商业支持,而且这个项目对 Windows Phone 很有利,微软会大力支持

    缺点

    • 如果深入后会发现功能缺失,尤其是定制 UI,因为未开源使得遇到问题时不知道如何修复
    • Xamarin 本身有些 Bug
    • 相关资源太少,没有原生平台那么多第三方库
    • Xamarin studio 比起 Xcode 和 Android Studio 在功能上还有很大差距

    Objective-C 编译为 Windows Phone

    微软知道自己的 Windows Phone 太非主流,所以很懂事地推出了将 Objective-C 项目编译到 Windows Phone 上运行的工具,目前这个工具的相关资料很少,鉴于 Visual Studio 支持 Clang,所以极有可能是使用 Clang 的前端来编译,这样最大的好处是以后支持 Swift 会很方便,因此我归到编译流。

    Swift – Apportable/Silver

    apportable 可以直接将 Swift/Objective-C 编译为机器码,但它官网的成功案例全部都是游戏,所以用这个来做 APP 感觉很不靠谱。
    所以后来它又推出了 Tengu 这个专门针对 APP 开发的工具,它的比起之前的方案更灵活些,本质上有点类似 C++ 公共库的方案,只不过语言变成了 Swift/Objective-C,使用 Swift/Objective-C 来编译生成跨平台的 SO 文件,提供给 Android 调用。
    另一个类似的是 Silver,不过目前没正式发布,它不仅支持 Swift,还支持 C# 和自创的 Oxygene 语言(看起来像 Pascal),在界面方面它还有个跨平台非 UI 库 Sugar,然而目前 Star 数只有 17,太非主流了,所以不值得研究它。

    Go

    Go做为后端服务开发语言,专门针对多处理器系统应用程序的编程进行了优化,使用Go编译的程序可以媲美C或C++代码的速度,而且更加安全、支持并行进程。Go 从 1.4 版本开始支持开发Android应用(并在1.5 版本支持iOS)。虽然能同时支持Android和ios,但是目前可用的api很少,Go仍然专注于后端语言开发。
    Android的View层完全是基于Java写的,要想用Go来写UI不可避免要调用Java 代码,而这方面Go还没有简便的方式,目前Go调用外部代码只能使用cgo,通过cgo再调用jni,这就不可避免的需要写很多的中间件。而且 cgo 的实现本身就对性能有损失,除了各种无关函数的调用,它还会锁定一个 Go 的系统线程,这会影响其它 gorountine 的运行,如果同时运行太多外部调用,甚至会导致所有 gorountine 等待
    所以使用Go开发跨平台移动端应用目前不靠谱。

    虚拟机流

    除了编译为不同平台下的二进制文件,还有另一种常见做法是通过虚拟机来支持跨平台运行,比如 JavaScript 和 Lua 都是天生的内嵌语言,所以在这个流派中很多方案都使用了这两个语言。
    不过虚拟机流会遇到两个问题:一个是性能损耗,另一个是虚拟机本身也会占不小的体积。

    Java 系

    说到跨平台虚拟机大家都会想到 Java,因为这个语言一开始就是为了跨平台设计的,Sun 的 J2ME 早在 1998 年就有了,在 iPhone 出来前的手机上,很多小游戏都是基于 J2ME 开发的,这个项目至今还活着,能运行在 Raspberry Pi 上。
    前面提到微软提供了将 Objective-C 编译在 Windows Phone 上运行的工具,在对 Android 的支持上我没找到的详细资料,所以就暂时认为它是虚拟机的方式,从 Astoria 项目的介绍上看它做得非常完善,不仅能支持 NDK 中的 C++,还实现了 Java 的 debug 接口,使得可以直接用 Android Studio 等 IDE 来调试,整个开发体验和在 Android 手机上几乎没区别。
    另外 BlackBerry 10 也是通过内嵌虚拟机来支持直接运行 Android 应用,不过据说比较卡。
    不过前面提到 C# 和 Java 在 iOS 端的方案都是通过 AOT 的方式实现的,目前还没见到有 Java 虚拟机的方案,我想主要原因是 iOS 的限制,普通 app 不能调用 mmap、mprotect,所以无法使用 JIT 来优化性能,如果 iOS 开放,或许哪天有人开发一个像微软那样能直接在 iOS 上运行 Android 应用的虚拟机,就不需要跨平台开发了,大家只需要学 Android 开发就够了。

    Titanium/Hyperloop

    Titanium 应该不少人听过,它和 PhoneGap 几乎是同时期的著名跨平台方案,和 PhoneGap 最大的区别是:它的界面没有使用 HTML/CSS,而是自己设计了一套基于 XML 的 UI 框架 Alloy,代码类似下面这个样子:

    app/styles/index.tss
     ".container": {
     backgroundColor:"white"
     },
     // This is applied to all Labels in the view
     "Label": {
     width: Ti.UI.SIZE,
     height: Ti.UI.SIZE,
     color: "#000", // black
     transform: Alloy.Globals.rotateLeft // value is defined in the alloy.js file
     },
     // This is only applied to an element with the id attribute assigned to "label"
     "#label": {
     color: "#999" /* gray */
     }

    前面我们说过由于 CSS 的过于灵活拖累了浏览器的性能,那是否自己建立一套 UI 机制会更靠谱呢?尽管这么做对性能确实有好处,然而它又带来了学习成本问题,做简单的界面问题不大,一旦要深入定制开发就会发现相关资料太少,所以还是不靠谱。

    Titanium 还提供了一套跨平台的 API 来方便调用,这么做是它的优点更是缺点,尤其是下面三个问题:

    API 有限,因为这是由 Titanium 提供的,它肯定会比官方 API 少且有延迟,Titanium 是肯定跟不过来的
    相关资料及社区有限,比起 Android/iOS 差远了,遇到问题都不知道去哪找答案
    缺乏第三方库,第三方库肯定不会专门为 Titanium 提供一个版本,所以不管用什么都得自己封装
    Titanium 也意识到了这个问题,所以目前在开发下一代的解决方案 Hyperloop,它可以将 JavaScript 编译为原生代码,这样的好处是调用原生 API 会比较方便,比如它的 iOS 是这样写的:

     @import("UIKit");
     @import("CoreGraphics");
     var view = new UIView();
     view.frame = CGRectMake(0, 0, 100, 100);

    这个方案和之前的说的Xamarin如出一辙,也是将JavaScript将翻译为Objective-C然后由官方的方案运行。不过这项目开发都快三年了,但至今仍然是试验阶段,显然有点不靠谱。

    NativeScript

    之前说到 Titanium 自定义 API 带来的各种问题,于是就有人换了个思路,比如前段时间推出的 NativeScript,它的方法说白了就是用工具来自动生成 wrapper API,和系统 API 保持一致。
    有了这个自动生成 wrapper 的工具,它就能方便基于系统 API 来开发跨平台组件,以简单的 Button 为例,源码在 cross-platform-modules/ui/button 中,它在 Android 下是这样实现的:

    export class Button extends common.Button {
     private _android: android.widget.Button;
     private _isPressed: boolean;
    public _createUI() {
     var that = new WeakRef(this);
     this._android = new android.widget.Button(this._context);
     this._android.setOnClickListener(new android.view.View.OnClickListener({
     get owner() {
     return that.get();
     },
     onClick: function (v) {
     if (this.owner) {
     this.owner._emit(common.knownEvents.tap);
     }
     }
     }));
     }
     }

    在 iOS 下是这样实现的:

     export class Button extends common.Button {
     private _ios: UIButton;
     private _tapHandler: NSObject;
     private _stateChangedHandler: stateChanged.ControlStateChangeListener;
    constructor() {
     super();
     this._ios = UIButton.buttonWithType(UIButtonType.UIButtonTypeSystem);
    this._tapHandler = TapHandlerImpl.new().initWithOwner(this);
     this._ios.addTargetActionForControlEvents(this._tapHandler, "tap", UIControlEvents.UIControlEventTouchUpInside);
    this._stateChangedHandler = new stateChanged.ControlStateChangeListener(this._ios, (s: string) => {
     this._goToVisualState(s);
     });
     }
    get ios(): UIButton {
     return this._ios;
     }
     }

    可以看到用法和官方 SDK 中的调用方式是一样的,只不过语言换成了 JavaScript,并且写法看起来比较诡异罢了,风格类似前面的 Hyperloop 类似,所以也同样会有语法转换的问题。
    这么做最大的好处就是能完整支持所有系统 API,对于第三方库也能很好支持,但它目前最大缺点是生成的文件体积过大,即便什么都不做,生成的 apk 文件也有 8.4 MB,因为它将所有 API binding 都生成了,而且这也导致在 Android 下首次打开速度很慢。
    从底层实现上看,NativeScript 在 Android 下内嵌了 V8,而在 iOS 下内嵌了自己编译的 JavaScriptCore(这意味着没有 JIT 优化,具体原因前面提到了),这样的好处是能调用更底层的 API,也避免了不同操作系统版本下 JS 引擎不一致带来的问题,但后果是生成文件的体积变大和在 iOS 下性能不如 WKWebView。
    WKWebView 是基于多进程实现的,它在 iOS 的白名单中,所以能支持 JIT。它的使用体验很不错,做到了一键编译运行,而且还有 MVVM 的支持,能进行数据双向绑定。
    在我看来 NativeScript 和 Titanium 都有个很大的缺点,那就是排它性太强,如果你要用这两个方案,就得完整基于它们进行开发,不能在某些 View 下进行尝试,也不支持直接嵌入第三方 View,有没有方案能很好地解决这两个问题?有,那就是我们接下来要介绍的 React Native。

    React Native

    React Native是由FaceBook开源的基于JavaScript和React搭建的一套跨平台开发框架。而在设计之初,React Native采用就是在不同平台下使用平台自带的UI组件。以为它采用JavaScript和React来开发,所以获得了不少前端程序猿的青睐。
    有人说,React Native采用js等前端技术是回归H5,但其实 React Native和Web 扯不上太多关系。ReactNative虽然借鉴了CSS中的Flexbox、navigator、XMLHttpRequest 等Api的写法,但是大部分还是通过原生的组件或者自己封装的组件来开发的。就像FaceBooK的内部软件Facebook Groups,iOS版本很大一部分基于React Native开发,其中用到了不少内部通用组件。
    React Native相比传统Objective-C和UIView,学习成本更低了,熟悉JavaScript 的开发者可以在半天写个使用标准UI界面,而且用XML+CSS 画界面也远比 UIView 中用 Frame 进行手工布局更易读。在加上React Native师出名门,截止目前,React Native已更新到0.4.2版本,并且逐步趋于稳定。由于其更加接近原生的体验,国内一些大厂纷纷加入,诸如阿里、腾讯、美团等纷纷开始自己app想React Native的改造。

    React Native代码:

    @implementation ArticleComponent
    + (instancetype)newWithArticle:(ArticleModel *)article
     {
     return [super newWithComponent:
     [CKStackLayoutComponent
     newWithView:{}
     size:{}
     style:{
     .direction = CKStackLayoutDirectionVertical,
     }
     children:{
     {[HeaderComponent newWithArticle:article]},
     {[MessageComponent newWithMessage:article.message]},
     {[FooterComponent newWithFooter:article.footer]},
     }];
     }
     ...

    很多人觉得跨平台从来都不靠谱,但其实是有的,那就是 Web,这个历史上最成功的例子,就像当年web挤掉pc成为互联网的主流一样,未来的互联网必将是web的时代。

    展开全文
  • 移动跨平台技术方案总结

    千次阅读 2019-01-22 12:39:54
    为了帮助读者更好地学习WEEX,本节将对React Native、Weex和Flutter等主流的跨平台方案进行简单的介绍和对比。 React Native React Native (简称RN)是Facebook于2015年4月开源的跨平台移动应用开发框架,是Facebook...

    “得移动端者得天下”,移动端取代PC端,成为了互联网行业最大的流量分发入口,因此不少公司制定了“移动优先”的发展策略。

    为了帮助读者更好地学习WEEX,本节将对React Native、Weex和Flutter等主流的跨平台方案进行简单的介绍和对比。

    React Native

    React Native (简称RN)是Facebook于2015年4月开源的跨平台移动应用开发框架,是Facebook早先开源的React框架在原生移动应用平台的衍生产物,目前主要支持iOS和安卓两大平台。

    RN使用Javascript语言来开发移动应用,但UI渲染、网络请求等均由原生端实现。具体来说,开发者编写的Javascript代码,通过中间层转化为原生控件后再执行,因此熟悉Web前端开发的技术人员只需很少的学习就可以进入移动应用开发领域,并可以在不牺牲用户体验的前提下提高开发效率。

    作为一个跨平台技术框架,RN从上到下可以分为Javascript层、C++层和Native层。其中,C++层主要用于实现动态连结库(.so),作为中间适配层桥接,实现js端与原生端的双向通信交互,如下图所示是RN在Android平台上的通信原理图。
    在这里插入图片描述

    在RN的三层架构中,最核心的就是中间的C++层,C++层最核心的功能就是封装JavaScriptCore,用于执行对js的解析。同时,原生端提供的各种Native Module(如网络请求,ViewGroup控件模块)和JS端提供的各种JS Module(如JS EventEmiter模块)都会在C++实现的so文件中保存起来,最终通过C++层中的保存的映射实现两端的交互。
    在这里插入图片描述

    在RN开发过程中,大多数情况下开发人员并不需要需要了解RN框架的具体细节,只需要专注JS端的逻辑代码实现即可。但是需要注意的是,由于js代码是运行在独立的JS线程中,所以在js中不能处理耗时的操作,如fetch、图片加载和数据持久化等操作。

    最终,JS代码会被打包成一个bundle文件并自动添加到应用程序的资源目录下,而应用程序最终加载的也是打包后的bundle文件。RN的打包脚本位于“/node_modules/react-native/local-cli”目录下,打包后通过metro模块压缩成bundle文件,而bundle文件只包含打包js的代码,并不包含图片、多媒体等静态资源,而打包后的静态资源会是被拷贝到对应的平台资源文件夹中。

    总的来说,RN使用Javascript来编写应用程序,然后调用原生组件执行页面渲染操作,在提高了开发效率的同时又保留了Native的用户体验。并且,伴随着Facebook重构RN工作的完成,RN也将变得更快、更轻量、性能更好。

    Weex

    作为一套前端跨平台技术框架,Weex建立了一套源码转换以及Native与Js通信的机制。Weex表面上是一个客户端框架,但实际上它串联起了从本地开发、云端部署到分发的整个链路。
    具体来说,在开发阶段编写一个.we文件,然后使用Weex提供的weex-toolkit转换工具将.we文件转换为JS bundle,并将生成的JS bundle上传部署到云端,最后通过网络请求或预下发的方式加载至用户的移动应用客户端。当集成了Weex SDK的客户端接收到JS bundle文件后,调用本地的JavaScript引擎执行环境执行相应的JS bundle,并将执行过程中产生的各种命令发送到native端进行界面渲染、数据存储、网络通信以及用户交互响应。
    在这里插入图片描述
    由上图可知,Weex框架中最核心的部分就是JavaScript Runtime。具体来说,当需要执行渲染操作时,在iOS环境下选择基于JavaScriptCore内核的iOS系统提供的JSContext,在Android环境下使用基于JavaScriptCore内核的JavaScript引擎。

    当JS bundle从服务器下载完成之后,Weex的Android、iOS和H5会运行一个JavaScript引擎来执行JS bundle,同时向各终端的渲染层发送渲染指令,并调度客户端的渲染引擎实现视图渲染、事件绑定和处理用户交互等操作。
    由于Android、iOS和H5等终端最终使用的是native渲染引擎,也就是说使用同一套代码在不同终端上展示的样式是相同的,并且Weex使用native引擎渲染的是native组件,所以在性能上比传统的WebView方案要好很多。

    当然,尽管Weex已经提供了开发者所需要的最常用的组件和模块,但面对丰富多样的移动应用研发需求,这些常用基础组件还是远远不能满足开发的需要,因此Weex提供了灵活自由的扩展能力,开发者可以根据自身的情况定制属于自己客户端的组件和模块,从而丰富Weex生态。

    Flutter

    Flutter是Google开源的移动跨平台框架,其历史最早可以追溯到2015年的Sky项目,该项目可以同时运行在Android、iOS和fuchsia等包含Dart虚拟机的平台上,并且性能无限接近原生。相较于RN和Weex使用Javascript作为编程语言与使用平台自身引擎渲染界面不同,Flutter直接选择2D绘图引擎库skia来渲染界面。

    在这里插入图片描述
    如上图所示,Flutter框架主要由Framework和Engine层组成,而我们基于Framework开发App最终会运行在Engine上。其中,Engine是Flutter提供的独立虚拟机,正是由于它的存在Flutter程序才能运行在不同的平台上,实现跨平台运行的能力。
    与RN和Weex使用原生控件渲染界面不同,Flutter并不需要使用原生控件来渲染界面,而是使用Engine来绘制Widget(Flutter显示单元),并且Dart代码会通过AOT编译为平台的原生代码,实现与平台的直接通信,不需要JS引擎的桥接,也不需要原生平台的Dalvik虚拟机,如图1-5所示。
    同时,Flutter的Widget采用现代响应式框架来构建,而Widget是不可变的,仅支持一帧,并且每一帧上的内容不能直接更新,需要通过Widget的状态来间接更新。在Flutter中,无状态和有状态Widget的核心特性是相同的,视图的每一帧Flutter都会重新构建,通过State对象Flutter就可以跨帧存储状态数据并恢复它。

    在这里插入图片描述
    总的来说,Flutter是目前跨平台开发中最好的方案,它以一套代码即可生成Android和iOS平台两种应用,很大程度上减少了App开发和维护的成本,同时Dart语言强大的性能表现和丰富的特性,也使得跨平台开发变得更加便利。而不足的是,Flutter还处于Alpha阶段,许多功能还不是特别完善,而全新的Dart语言也带来了学习上的成本,如果想要完全替代Android和iOS开发还有比较长的路要走。

    PWA

    PWA,全称Progressive Web App,是Google在2015年提出渐进式的网页技术。PWA结合了一系列的现代Web技术,并使用多种技术来增强Web App的功能,最终可以让网页应用呈现和原生应用相似的体验。

    相比于传统的网页技术,渐进式Web技术是可以横跨Web技术及Native APP开发的技术解决方案,具有可靠、快速且可参与等诸多特点。

    具体来说,当用户从手机主屏幕启动时,不用考虑网络的状态就可以立刻加载出PWA。并且,相比传统的网页加载速度,PWA的加载速度是非常快的,因为PWA使用了Service Worker 等先进技术。除此之外,PWA还可以被添加在用户的主屏幕上,不用从应用商店进行下载即可通过网络应用程序Manifest file提供类似于APP的使用体验。

    作为一种全新Web技术方案,PWA的正常工作需要一些重要的技术组件,它们协同工作并为传统的Web应用程序注入活力,如图1-8所示。

    在这里插入图片描述
    其中,Service Worker表示离线缓存文件,其本质是Web应用程序与浏览器之间的代理服务器,可以在网络可用时作为浏览器和网络间的代理,也可以在离线或者网络极差的环境下使用离线的缓冲文件。

    Manifest则是W3C一个技术规范,它定义了基于JSON的清单,为开发人员提供一个放置与Web应用程序关联的元数据的集中地点。Manifest是PWA 开发中的重要一环,它为开发人员控制应用程序提供了可能。

    目前,渐进式Web应用还处于起步阶段,使用的厂商也是诸如Twitter、淘宝、微博等大平台。不过,PWA作为Google主推的一项技术标准,Edge、Safari和FireFox等主流浏览器也都开始支持渐进式Web应用。因此,可以预见的是,PWA必将成为继移动之后的又一革命性技术方案。

    对比

    在当前诸多的跨平台方案中,RN、Weex和Flutter无疑是最优秀的。而从不同的细节来看,三大跨平台框架又有各自的优点和缺点,可以通过表1-1来查看。

    对比类型 React Native Weex Flutter
    支持平台 Android/IOS Android/IOS/Web Android/IOS
    实现技术 JavaScript JavaScript 原生编码/渲染
    引擎 JS V8 JSCore Flutter Engine
    编程语言 React Vue Dart
    bundle包大小 单一、较大 较小、多页面 不需要
    框架程度 较重 较轻
    社区 活跃、FB维护 不活跃 活跃

    如上表所示,RN、Weex采用的技术方案大体相同,它们都使用JavaScript作为编程语言,然后通过中间层转换为原生的组件后再利用Native渲染引擎执行渲染操作。而Flutter直接使用skia来渲染视图,而Flutter Widget则使用现代响应式框架来构建,和平台没有直接的关系。就目前跨平台技术来看,JavaScript在跨平台开发中可谓占据半壁江山,大有“一统天下”的趋势。
    从性能方面来说,Flutter的性能理论上是最好的,RN和Weex次之,并且都好于传统的WebView方案。但从目前的实际应用来看却并没有太大的差距,特别是和0.5.0版本以上的RN对比性能体验上差异并不明显。
    而从社群和社区的活跃来看,RN和Flutter无疑是最活跃的,RN经过4年多的发展已经成长为跨平台开发的实际领导者,并拥有各类丰富的第三方库和开发群体。Flutter作为最近才火起来的跨平台技术方案,不过目前还处在beta阶段,商用的实例也很少,不过应该看到google的号召力一直是很强,未来究竟如何发展让我们拭目以待。

    示例

    eros-yanxuan

    简介

    eros-yanxuan 是基于 eros 开发的Weex项目,部分页面参考了项目网易严选 weex 版本,欢迎star或fork。

    运行

    确保你本地已经集成了 eros 开发所需的环境

    clone 项目到本地:

    $ git clone https://github.com/xiangzhihong/eros-yanxuan.git
    

    进入目录,下载前端所需的依赖:

    $ cd eros-yanxuan
    $ npm install
    

    iOS SDK

    打开platforms目录下的WeexEros项目,在WeexEros中使用pod添加依赖。

    $ cd platforms/ios/WeexEros
    $ pod update                // 下载 iOS 依赖
    $ open WeexEros.xcworkspace // 自动打开项目
    

    选中模拟器,点击绿色箭头运行 app 即可。

    Android

    对于Android工程来说,使用Android Studio打开platforms目录下的WeexFrameworkWrapper的Android工程,然后使用install.sh安装Android工程的需要依赖包nexus和wxframework。

    具体可以参考自行导入项目,便可运行起来。

    运行

    • 项目根目录下运行 eros dev
    • 关闭调试,拦截器,打开热更新
    • 重新 build app

    效果

    在这里插入图片描述

    Question

    运行过程中出现问题在以下地址解决方法,如果没有找到,可以参考eros快速入门新建一个Weex工程,然后将src和配置文件的代码拷贝过去。 如果还有问题,请加群:515980159

    展开全文
  • make主要用在代码移植性上。跨平台管理编译工作有好几种方法,每种的核心都是一个叫make的程序,这是一个跨平台的工具

    make主要用在代码移植性上。跨平台管理编译工作有好几种方法,每种的核心都是一个叫make的程序,这是一个跨平台的工具。

    Make

    假如你有一个程序叫做bar,它由bar.cpp和main.cpp两个C++源文件以及一个bar.h头文件组成

    main.cpp

    #include "bar.h"
    int main(int argc, char *argv[]) {
        Bar bar;
        bar.SetBar(17);
        bar.PutBar();
    
    }

    bar.h

    #pragma once
    #ifndef  _BAR_00__
    #define  _BAR_00__
    class Bar {
    public:
        void SetBar(int bar);
        void PutBar();
    private:
        int m_bar;
    
    };
    #endif // ! _BAR_00__

    bar.cpp

    #include<stdlib.h>
    #include<stdio.h>
    #include "bar.h"
    void Bar::SetBar(int bar) {
        m_bar = bar;
    }
    void Bar::PutBar() {
        char buf[16];
        snprintf(buf, sizeof(buf) - 1, "% d", m_bar);
        setenv("BAR", buf, 1);
    }

    bar对象维护了一个整数m_bar.m_bar的值由SetBar()决定,而PutBar()函数则把m_bar的值存到环境变量BAR里。

    从创建一个简单脚本build.sh开始,把它编译链接为一个bar应用程序

    #! /bin/sh
    g++ -g -o bar bar.cpp main.cpp

    随后执行

    sh build.sh

    make工具按照一定的依赖规则来执行一组命令,以获得需要的目标或结果。上面例子中,目标就是可执行文件bar,它依赖于源文件bar.cpp和main.cpp,而用来生成可执行文件的命令是

    g++ -o bar bar.cpp main.cpp

    make要求在一个文件里指定目标,依赖关系和命令,通常这个文件的名字是Makefile,下面这个makefile同样可以编译我们的例子

    bar:bar.cpp main.cpp
    g++ -g -o bar bar.cpp main.cpp

    有了Makefile之后,只需要键入下列命令

    make

    然后make就会为我们生成bar程序

    make如何处理shell脚本带来的问题:

    • make没彻底消除可移植性,在windows上,make并不像linux活mac上那样是原生应用程序.
    • makefile并没有解决指定不同编译器编译项目的问题。
    • 命令行参数依然是硬编码
    • make只会在源码的修改时间比可执行文件的修改时间万,才重新编译bar

      如何改进呢,重写makefile如下

    bar:bar.o main.o
       g++ -g -o bar main.o bar.o
    bar.o:bar.cpp bar.h
      g++ -g -c bar.cpp
    main.o:main.cpp bar.h
      g++ -g -c main.cpp

    上面的makefile通过引入两个新目标bar.o和main.o解决了依赖性的问题。现在依赖关系有了明确的目标,例如当bar.cpp和bar.h发生修改时,bar.o应该重新编译。bar自己的依赖关系也发生了变化,它不在依赖于源文件,而是依赖于目标文件。所以touch文件main.cpp后再执行make时,会得到以下结果

    touch main.cpp
    make
    g++ -g -c main.cpp
    g++ -g -o bar bar.o main.o

    注意到make只重新编译了目标main.o和bar,但是编译器和命令行参数仍旧是硬编码。这两个问题都可以用macro来解决

    OBJS=bar.o  main.o
    CXXFLAGS=-g
    barL $(OBJS)
             $(CXX) $(CXXFLAGS) -o $@ $(OBJS)
    bar.o:bar.cpp bar.h
             $(CXX) $(CXXFLAGS) -c bar.cpp
    main.o:main.cpp bar.h
             $(CXX) $(CXXFLAGS) -c main.cpp)

    如果你注意到所有的.o文件其实都只依赖于对应的.cpp文件和bar.h的话,我们可以进一步改进Makefile,通过额外的make机制如模式规则(pattern rules),Makefile可以简化为:

    OBJS=bar.o main.o
    CXXFLAGS= -g
    bar:$(OBJS)
          $(CXX) $(CXXFLAGS) -o $@(OBJS)
    % o:%.cpp
          $(CXX) $(CXXFLAGS) -c $ <
    $(OBJS):bar.h

    问题依然存在,把-g 提取出来放到CXXFLAGS里确实是一大进步,但是依然是Makefile里的硬编码,what’s more terrible,它和编译器脱离开来了,如果CXX不是使用g++,那么-g可能会在别的编译器上有完全不同的意思

    未完待续……

    展开全文
  • 跨平台技术浅析

    千次阅读 2010-04-03 20:32:00
     软件发展到今天,跨平台已经成为了一个不可阻挡的趋势,对现今的几种主要跨平台技术,在这里我们简单的分析一下它们的基本实现原理,在开始之前,我们要先弄明白几个基本的概念。 概念一: 

         今天是假期的第一天,下午与同伴们一起去参观了下南阳汉画馆,感受到了浓烈的科技与艺术气息,这让我灵感阵阵,借助难得的状态,写成此文,以了我几日的心愿。    

         

         软件发展到今天,跨平台已经成为了一个不可阻挡的趋势,对现今的几种主要跨平台技术,在这里我们简单的分析一下它们的基本实现原理,在开始之前,我们要先弄明白几个基本的概念。

        

     概念一:

         语言与其链接库:语言通常会伴随有对应的链接库,没有链接库的语言,几乎什么什么程序也写不出来,打个简单的比方:你用C语言写一个“HELLO Word!!”小程序,你就要用到“stdio”的链接库,如果你没有使用它,将什么也出不来。

     

    概念二:

         平台与链接库:开发平台同样也附带的有对应的链接库,如果一个平台没有链接库,那将是一个没有任何开发空间的平台(此平台没有任何前途...),同样,打个简单的比方,你用Visual C++开发Windows程序,你需要用到GDI32,USER32或MFC等链接库。

     

        搞明白前面的概念,我就好向你们解释跨平台了,我们在一个操作平台上开发的程序,为什么拿到另个平台上重新编译后就不能正常运行了?原因就在于平台的链接库上,比方说,你用C语言搭配Win32链接库(Windows的)开发一个程序,你把它拿到Linux上编译,却无法编译成功,问题就出在Linux没有Win32链接库。

       

       下来我们来看看几种跨平台技术实现的基本原理:

      

     QT:

         QT的是这样做的,用一个链接库将各个主要平台的链接库抽象出一个共通的链接库,实践证明,你用C++搭配QT链接库做的程序,可以在不同的平台上编译后运行。

     

     JAVA:

         JAVA就要比QT先进了,它不但将链接库统一了起来,更将平台也统一了起来,它使用了一层JVM(Java虚拟机),Java的程序不用再重新编译,就可以直接跨平台运行,正因为如此,Java的口号是,“一次编译,到处运行”,但也因为如此,它牺牲了一部分的运行效率。

    (哎~。。。。遗憾。。。。。)。

     

    .NET:

         微软的.NET技术的出现晚于Java,按照事物发展的规律来判断,.NET应该比Java做的更好,事实也确实如此,.NET的眼光更高,甚至想把编程语言的规格也统一起来,可以用一个公式来形象的表示.NET,语言规格+平台+链接库=.NET,其程度可以用包罗万象来形容,但是,这样做的很大缺点在于,统一了.NET平台上的语言规格,导致了各个编程语言的千遍一律,特点不突出,比如,如果Delphi准备移植到.NET平台上,为了符合平台要求,它要改掉许多很有特点的语言特性,这对Delphi来说恐怕非常不好,感觉用削足适履来形容这个弊端最合适。

     

       看到这里,你应该对现在主流的跨平台技术有清楚的了解了,它们的实现方式各具特色,为了实现同一个目标,采用了不同的设计思想,但都实现了平台的跨越,这正是程序设计艺术的体现,不是吗?

          

     

                                                                                                                                                         2010年4月2日(清明节)

     

    展开全文
  • Flutter基础(一)移动开发跨平台技术的百家争鸣

    千次阅读 多人点赞 2019-04-23 12:04:35
    本来这一篇应该介绍如何搭建Flutter开发环境的,但我想在了解Flutter前,不妨了解一下跨平台技术的演进,这样更有助于学习Flutter,也能认清Flutter的优势和本质。这篇文章还有一个目的,就是希望大家是玩技术的人,...
  • 跨平台技术演进及Flutter未来

    千次阅读 多人点赞 2019-10-24 09:11:00
    本文阅读预计约12分钟一、移动跨平台技术演进1. 引言移动互联网发展十余年,伴随着 Android、iOS 等智能手机的不断普及,移动端已逐步取代 PC 端,成为兵家必争...
  • 几种跨平台技术的比较

    千次阅读 2019-07-03 11:44:21
    Cordova的基础是html和js运行在webview容器里面,通过Cordova提供...所以它的效率天生收到限制,而且也受到了各个厂商对webkit内核的好坏;比如之前基于国产某Cloud的程序,在华为手机上显示就不正常,花费了不少精力修改; ...
  • 移动端的跨平台技术已经发展了很多年,涌现出了很多技术,越来越成熟,就像这两年比较火的Flutter,就是跨平台技术的一种。我接触跨平台技术也有几年,收集了很多材料,现在专门在这里汇总,方便查阅。
  • C++跨平台技术 - 线程Thread

    千次阅读 2014-06-13 10:30:27
    跨平台是什么意思呢?先了解一下平台的概念以及平台的差异。我们知道一个VC编译出来的*.exe是不能在Linux运行的,不能运行的原因可以概括为以下几个方面: 1. 文件的结构与格式 可执行程序是按定义好的格式来组织的...
  • webService跨平台与跨语言应用技术

    千次阅读 2017-03-24 16:40:38
    1.webService(又名XML Web Service)定义:是一种语言操作系统的一种应用技术(是一种可以接收从Internet或者Intranet上的其它系统中传递过来的请求,轻量级的独立的通讯技术)。 2.实现原理:通过SOAP在Web上...
  • 跨平台技术的诞生 我是2010年开始从事的Android开发,当时会Android和iOS开发的很少,也不火,所有人都在“摸着河底过河”。项目更没有第三方框架一说,大都是自己写的,不像现在各种的框架满天飞。 随着移动...
  • 移动跨平台开发一步到位

    万人学习 2015-04-15 15:24:28
    基于.NET的移动跨平台开发教程,现在!.NET 不一样了,让你一统三国! 通过Xamarin开发套件,你将可以用 Visual Studio 及 C# 开发各移动平台 (Windows/iOS/Android) 的 App,而且执行效能一样好!让使用 .NET 技术...
  • 技术问答-1 跨平台

    千次阅读 2019-01-25 10:16:09
    1. 什么是跨平台? 我对跨平台的理解就是 Write Once,Run Anywhere 2. 跨平台原理? 跨平台少不了我们的大功臣—JVM(JAVA Virtual Machine) java虚拟机 1) .java文件(java源码)编译之后会生成.class文件(字节码文件...
  • 跨平台PhoneGap技术架构全解析

    千次阅读 2013-08-30 20:42:08
    1.跨平台PhoneGap技术架构一:PhoneGap简介:http://www.cnblogs.com/ever4ever/archive/2012/07/09/2583652.html 2.跨平台PhoneGap技术架构二:PhoneGap底层原理(上):...
  • SuperMap跨平台GIS技术白皮书 v1.0

    千次阅读 2019-02-19 10:57:21
    在20多年的发展中,经过不断地技术创新和迭代,超图实现了全线产品支持跨平台,主要包括组件GIS产品SuperMap iObjects Java和SuperMap iObjects C++ ;桌面GIS产品SuperMap iDesktop Java ;云GIS产品SuperMap ...
  • 移动应用跨平台开发技术方向对比

    千次阅读 2014-09-02 14:34:13
    我们盘点一下近几年移动跨平台开发工具。随着ios、android的成熟,移动应用开发需求剧增。国内外出现大量的移动应用跨平台开发工具...跨平台开发工具从技术上大体分为三类,一、脚本解析型。 二、web模式。三、翻译型。
  • 我们邀请到字节跳动移动平台部 Flutter 架构师袁辉辉,Google Flutter 团队工程师 Justin McCandless,字节跳动移动平台部 Flutter 资深工程师李梦云,阿里巴巴高级技术专家王树彬和大家进行分享交流。 以下是字节...
  • 浅谈WebService跨平台远程调用技术

    千次阅读 2017-10-05 10:26:38
    WebService是一种编程语言和操作系统平台的远程调用技术
  • SuperMap GIS 10i 跨平台GIS技术白皮书

    千次阅读 2019-12-20 10:31:28
    跨平台GIS技术是指基于同一套GIS基础内核,同时支持多种硬件设备和操作系统。跨平台GIS技术从GIS内核级屏蔽不同硬件设备和操作系统、不同处理器架构和不同CPU指令集,以及不同应用程序接口之间的差异。通过提供...

空空如也

1 2 3 4 5 ... 20
收藏数 96,283
精华内容 38,513
关键字:

跨平台技术