要不是因为苹果,混合应用开发将完胜 Native

在过去的 6 个月里,我一直在开发 Rizer。这是个手机应用,它让用户给各种分类(目前有动物、小孩、食物、搞笑、男人、自然和女人)的照片 PK 赛评分,用户也可以提交自己的照片到这些分类里,让别人评分。照片采用 ELO 算法来排名(就是 电影《社交网络》里介绍FaceMash网站的场景中Eduardo Saverin 在窗户上画的那个公式),评分最高的将出现在 Rizer 的排行榜上。

Rizer 是一个混合应用,采用 Apache Cordova开发, 通过它上面大量的 native 插件来获取用户设备上的重要的原生功能,例如推送通知、用相机拍照以及进行应用内购买。

目前我霸占了男人排行榜😎

一开始,一般用户并不知道 Rizer 是混合应用,这对我来说至关重要。这意味着它必须设计良好,性能出色 (嘿,performant不是个英语单词),不缺少用户会对此类应用期望的任何原生功能,并且当设备失去网络连接时不至于无法使用。幸运的是,根据我的40名亲友做beta测试的反馈,我实现了这个目标(我甚至可能都同意他们的看法了)。

如果你不相信我,或者你已经玩过一阵子混合应用,那么我推荐你去下载 Rizer,给照片比赛评分,看看排行榜上的一些分类,并且如果你有勇气的话,上传一些自己的照片。体验完后你很可能会被混合应用的能力所折服,如果没有,那至少也欣赏了一些可爱的动物和小宝贝。

毫无疑问,转向混合应用是绝大多数应用的正确选择

理解以下三个关键点非常重要:

  • 一个应用的混合版本一定不会跟原生版本一样快,但这无关紧要,只要混合版本足够快。 简单来说,如果你的用户从来不抱怨应用的性能,那么你的应用就是足够快的。作为一个性能狂,知道自己的应用运行得尽可能地快,我理解这种吸引力,但是我们必须小心避免过早发生和过度优化。知道自己的原生应用在页面上渲染 100 张照片比混合应用版本快 8 毫秒,内心可能自我感觉良好,但用户能感觉得到或者在乎吗?不会。

  • 非常耗资源的 3D 游戏或类似的东西,不在我定义的 “应用”范围内。 这种情况下原生应用当然是你的最好选择,因为混合应用想要变快会非常吃力。Canvas 的性能在最近几年已经改善了很多,但是在旧设备上运行耗资源的应用还是会很慢。

  • 设计良好的混合应用,在现代 JavaScript UI 框架上运行,绝对够快。性能差不再是放弃混合方式的借口了。如果你最近尝试做一个混合应用,发现性能不够满意,那你应该认真重新评估一下你选择的设计模式,或者是用了大量像 jQuery 这样不需要的库。学习下现代的 DOM API,如果还没学的话。我们的应用的所有的目标设备都支持它。

混合方式有一些主要的优势:

  • 你可以利用现有的 JS,HTML和CSS技术开发一套代码,可同时运行在 iOS 和 Android 上。这是混合应用最明显的优势,但也不能过分强调。在我的项目中,需要根据运行的平台来写分支代码的次数不超过十次(这只是为了解决一个 iOS 上的 bug,后面再详细说)。代码里的分支看起来像这样:
if (device.platform === "iOS") {
  doRidiculousWorkaround();
} else {
  doThingThatWorksAsExpected();
}

  • 开发阶段在设备上查看变动几乎是瞬时的。整个开发过程中,我在自己的 Galaxy S7 Edge 上测试了所有代码改动。这个手机连上我的电脑,启用 USB 调试模式,运行 Rizer 的 debug 版本。在 Chrome 地址栏输入 chrome://inspect/#devices ,你会看到连接到你的电脑的设备上运行的所有 Chrome 标签页。点击列表里的 Rizer 页面,将会打开一个开发工具窗口,我就可以完整地分析 App 了,就像调试一个普通网站一样。这个功能加上构建系统里的 live reload 工具,我就可以在改动代码后几秒内在设备屏幕上看到更新后的结果了。棒呆。

  • 你可以把更新后的 JS,CSS,HTML,字体文件和图片直接推送给用户,无需重新编译 App 的二进制代码,也无需 App store 的审核。Rizer 使用了 微软的 CodePush 服务(目前免费)以及它的Cordova 插件,每次启动时用来检查更新,说实话没有它我都不知道该怎么做。或者, Ionic 的 Deploy 也可以用同样的方式使用,但是因为它不免费并且我没有用 Ionic,没理由去用它。

  • 你可以选择自己最喜欢的 UI 框架和构建工具。 Rizer 运行在我自己的前端框架 Samson.js上(别去用这个,它没有文档,并且为了满足我个人的需求经常变化),但我本来也可以用 React,Vue 或者 Ionic/Angular 来开发。

“哇,Sam,那些优势听起来好赞!那有什么缺点吗?”

混合应用方式有一个主要的缺点:

  • 作为开发者,我们仍然需要操心 iOS,也就是说我们不得不忍受苹果的那些狗屎。嘿,还押韵呢。

你可能会困惑。即使选择原生方式,我们仍然要操心 iOS,因此也要忍受苹果的那些狗屎。对吧?

还真是。

无论采用哪种方式,我们都无法避免苹果的这些狗屎:

  • Xcode

  • 配置文件

  • 需要一台 Mac 来编译 App

  • 需要使用 TestFlight 构建 beta 版本

  • App 审核流程 不可否认,app 审核时长已经缩短到平均 2 天,但是当你的 app 像 Rizer 一样被拒 7 次(因为一些愚蠢的理由),你的耐心真的会磨没了。

除了以上几点,混合应用还要处理这坨狗屎:

  • iOS WebView

等等,什么?iOS WebView 真的有那么差劲吗?没错。

两种 WebView 的故事

混合应用里引入的 JavaScript 代码运行在 WebView 中,本质上它就是 app 里附带的原生浏览器。在 Android 上,我们的代码运行在基于 Chromium 的 WebView 里,大多数情况下会完全按照预期运行。在 iOS 上,我们可以选择让代码运行在两种 WebView 中: UIWebView 或 WKWebView.

如何选择这两种 WebViews 很伤脑筋.

UIWebView 在 iOS 2 中引入,当时是唯一的选择,直到 iOS 8 中加入了 WKWebView。UIWebView 与现有的大部分 Cordova 插件兼容性很好,但总体上太过臃肿、缓慢。两者之间 对 HTML 5 的支持情况差异很小, 但由于 WKWebView 使用了 Nitro JavaScript 引擎,性能差距非常大。

Nitishkumar Singh 所说, WKWebView 提供了:

极大减少内存占用,启动更快,JavaScript 即时编译,独立进程渲染,占用更少的存储空间,稳定性更好,更安全,采用最新 web 标准等等。

在 2014 年 iOS 8 发行之前,很多鼓吹 WKWebView 对混合应用的重要性的文章开始冒出来。能够利用 WKWebView 提供的以上优化特性,让混合应用的开发者们兴奋不已。

不幸的是,当 iOS 8 最终发版以后,WKWebView 完全不能兼容现有的混合应用,因为它缺少一些 必备的功能。整整 3 年之后,情况只是稍微改观了一点。

WKWebView 的现状

感谢 Ionic 团队的出色工作,一些自讨苦吃的开发者(包括我自己)开始在他们的混合应用里使用 WKWebView。我会第一个站出来说,当 WKWebView 不出问题的时候,的确非常好用。在我老婆的 iPhone 7 上,Rizer 冷启动并安装 CodePush 更新的速度比在我的 Galaxy S7 Edge 上快多了。但如果它出问题时会怎样?让我们继续探究。

那些需要奇技淫巧的变通方案或者只能干脆放弃功能的 WKWebView 问题:

  • 不能访问应用根部 www目录以外的文件

  • 各种跨域问题,包括不能从 canvas 里提取图片数据,而这个 canvas 是用本地图片画上去的。 这差点搅黄了 Rizer,因为我需要允许用户裁剪照片和加滤镜效果,两者都需要在 canvas 里操作图片,然后从中提取像素数据。我之所以说 差点搅黄,是因为实际上我在 iOS 上通过代码分支曲线救国,做了下面这种扯淡的事:

  1. 把从设备上获取的照片 fileURL 传给 FileReader API 的 "readAsArrayBuffer" 函数。

  2. 用下面的函数将 "readAsArrayBuffer" 函数返回的 arrayBuffer 转成 base64 字符串:

    function arrayBufferToBase64(arrayBuffer) {
      var binary = '';
      var bytes = new Uint8Array(arrayBuffer);
      var len = bytes.byteLength;
      for (var i = 0; i < len; i++) {
        binary += String.fromCharCode(bytes[i]);
      }
      return window.btoa(binary);
    }
    
    
  3. 在返回的 base64 字符串前面加上 "data:image/jpeg;base64,",以创建 DOM 可读的 "imageDataURL"

  4. 创建一个 Image 对象,加载我们的 imageDataURL 作为它的 "src",当 image 加载完成时,创建一个新的 canvas 元素,把图片画上去。就像这样:

    var image = new Image();
    image.onload = function() {
      var canvas = document.createElement("canvas");
      canvas.width = image.width;
      canvas.height = image.height;
      canvas.getContext("2d").drawImage(image, 0, 0);
      callback(canvas); // No CORS issues
    };
    image.src = imageDataURL;
    
    
  5. 把你的电脑扔出窗外 :)

  • 捉摸不定的垂直滚动行为,以及从我的经历来看完全不可用的水平滚动。有好几次,我老婆打开 Rizer 的排行榜页面后无法滚动照片,必须回到上一个页面并重新打开排行榜页面。这个问题如此严重,我到头来需要去实现 iScroll

  • 完全不支持 getUserMedia。这对 Rizer 来说不是问题,但是它阻止了我开始另一个需要这个特性的项目。都 2017 年了,这完全不可接受。也进一步证明了 Safari 成了新的 IE

  • 无法通过程序控制显示和隐藏键盘

  • 跟稳定版的 Cordova SplashScreen 插件有导致 App 崩溃的冲突

  • 跟稳定版的 Cordova In-App Browser 插件有导致 App 崩溃的冲突

你要知道,运行在 Android 上的混合应用不存在以上任何一个问题。

说真的,我对 Google 提供的应用开发部署流程没有任何不满。Google Play 开发者控制台非常不可思议,有健壮的发布管理,A/B 测试,应用内产品创建,订单管理,应用安装和使用统计,用户反馈收集,并且也没有荒唐的审核流程。锦上添花的是,我们知道混合应用会按照预期来渲染和运行,这要感谢 Android 基于 Chromium 的 WebView。 苹果在这点上落后太多了,以至于我一说起谷歌的产品就像个狂热粉丝。

毫无疑问,Rizer 的开发过程比我想象的更费时,也更令人沮丧……拜苹果所赐。

当我的家人问及 Rizer 的开发进度时,他们可以证明我对苹果和 iOS 有多深的怨念。我一直被这样一个事实打败: 世界上最有价值的公司提供了如此糟糕的开发体验。

我试图找出苹果为什么没有动力去改善混合应用开发的流程并让 Safari 像其他现代浏览器一样功能相当(它不像是没有资源去做这个),或者像其他平台(包括 Windows)一样直接允许使用第三方浏览器。难道他们是想让开发者在 Android 应用之前开发出 iOS 应用,然后 iPhone 或 iPad 用户就没那么想转向 Android 设备,因为他们每天使用的 App 在 Google Play 上没有? 我真心希望不是这样.

好吧,那……选择混合还是原生?

从我的经验来看,选择混合方式引起的所有潜在的卡壳问题,都有变通方案。发现和实现这些方案很麻烦,但的确能解决问题。因为这个原因,我很乐意说混合方式是你下一个 App 的正确选择。开发一个混合应用肯定会让你花费更长时间,但是依然比开发两个独立的原生应用要省时间,并且如果设计合理,对你的用户来说也会足够快。

嘿,或许将来某一天苹果迷途知返,会为我们提供我们应得的开发体验。在那天到来之前,我还是希望这个“混合与原生”之争继续火下去。

原文:If It Weren’t For Apple, Hybrid App Development Would Be The Clear Winner Over Native

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,634评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,951评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,427评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,770评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,835评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,799评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,768评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,544评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,979评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,271评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,427评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,121评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,756评论 3 324
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,375评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,579评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,410评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,315评论 2 352

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 172,039评论 25 707
  • 发现 关注 消息 iOS 第三方库、插件、知名博客总结 作者大灰狼的小绵羊哥哥关注 2017.06.26 09:4...
    肇东周阅读 12,089评论 4 62
  • 吃维C 吃水果 禁油炸,辣椒,重油,烧烤 最晚23点前睡,早起吹吹风 保持好心情,最难的已经熬过去了 2018会好的
    拾七月阅读 114评论 0 0
  • 又走过一座城 想忘却一个人 不料心还是隐隐作疼 习惯了对你俯首称臣 耗费了整个青春 换来的是你一句天真 我以为可以...
    初初遇见阅读 197评论 0 0
  • 当时最受中国赴日留学生重视的,是翻译书籍、杂志等印刷品。所以如此,康、梁的影响不可忽视。按照康有为的说法:“泰西诸...
    小江老丝啊阅读 322评论 0 0