这篇文章不聊具体的技术内容,只是蹭蹭今天 iOS 领域最大的一个热点,关于一些应用收到 Apple 警告的问题。
我今天刚起床的时候,iOS 圈就炸锅了,很多开发者纷纷表示收到了 Apple 的警告邮件,邮件内容在网上随处可看,在这里我就不贴了。大体意思是说该应用使用了一些动态技术,让应用在审核之后出现一些不一样的功能,从而越过审核去实现更新,警告开发者对代码进行一些检查,去掉这样的实现。
实际上这是一个历史悠久,错综复杂,没有一个统一标准的事情。聊这个事情要从一个很古老的项目开始(我们直接略过不谈 Hybrid 架构的应用,就谈 Native 动态化)。
# 「始作俑者」Wax
最早要从 Wax 这个项目开始说,大家都知道 Objective-C 有着非常强大的动态特性。比如说:
- 运行时构造类和方法
- 运行时替换方法的实现
实际上这两个能力是非常恐怖的,他可以让 Cocoa 项目做很多类似黑魔法的事情,简单说就是可以让 Objective-C 像脚本语言那样,文本即代码,无须编译。后来出现了一个叫做 Wax 的项目(这个项目目前由阿里巴巴维护),这个项目打出的口号是用 Lua 来写 iOS 原生应用,当然现实中没有人会这样干,因为写起来实在是太痛苦了。但是鉴于 iOS 应用审核比写 Wax 还痛苦,所以 Wax 成为了做 HotFix 的最佳选择。
这个项目的做法是通过加载 Lua 脚本,动态的生成 Objective-C 的方法,通常用来替换掉出了问题的那个,Lua 脚本是可以动态下发的,所以也就实现了修复线上 bug 的使命。
当然,Wax 用起来是极为痛苦的,尤其是和 Objective-C 的类型转换。
# 后来居上的 JSPatch
iOS 7 的时候 Apple 推出了 JavaScriptCore,这是一个非常有趣的框架,他是 JS 与原生交互的桥梁,让你在原生和 JS 之间穿梭自如,现在 iOS 平台各种动态技术大多都是基于此。
JSCore 推出不久之后,一个更优秀的项目诞生了:由 bang 写的 JSPatch。这个项目无疑从各种角度碾压了 Wax,并且 JS 也比 Lua 更为人熟知,所以也就迅速替代 Wax 成为了热修复的主流选择。
JSPatch 的接入成本非常低,对项目的影响也非常小,不需要引入额外的脚本解释器(因为已经有 JSCore 了),并且 JS 写起来真的比 Lua 要爽很多。
# 异军突起的 React Native 和 Weex
时间继续在走,以 React Native 和 Weex 为代表的各种项目开始冒出来了,他们主要的想法并不是给项目做热修复,而是有更宏大的想法:使用脚本来编写 App 的主要功能。
在 RN 和 Weex 一类的技术里面,JavaScript 是实现原生代码的一种 DSL,通过 Bundle 里面或者下发的 js 文件,原生代码会解析 js 之后做界面渲染的工作。
我个人并没有玩过 RN,但因为在阿里工作过的原因有使用过一段时间 Weex,我个人的感觉是这样的技术驱动力来自于对动态运营的极高要求。
# PY 交易的小程序
技术上并无重大创新但是更为大胆的做法出现了,他直接告诉苹果:我们打算在微信上面加载别的程序,并且起了个名字叫做小程序。小程序推出之后,腾讯和苹果相安无事,我估计这里面是有一些 PY 交易的,事实上从某些角度来说小程序是直接违反 App Store 现存的条款的,但是反正微信就是没事。
# 吊胃口的 DynamicCocoa 和 OCScript
这个其实没有太多好说的,毕竟大家的胃口已经被吊的差不多了,而且按这个样子应该会继续吊下去。
简单说这两个更为激进的方案,希望能够把 JS -> ObjC 这一步都给省了,直接写 ObjC,然后转换到他们自己的一种中间代码,这样的话不需要引入新的学习成本。
PS:作为一行代码都没有就已经 1k 小星星的 repo 来说,DynamicCocoa 这波不亏。
# 动态化的动机在哪里
各种技术的诞生都伴随着各种各样的原因,我们在聊动态化的时候,往往伴随着以下这么几个动机:
- 动态修复线上 bug
- 逃避审核,调用私有方法
- 跨平台开发
- 开发周期太短,运营需求变化太大
很多历史证明跨平台开发(除了游戏以外)基本是比较扯淡的事情,纯粹这样做的应用大多不会有什么特别的优势,逃避审核和调用私有方法方面也只是少数人才会做的事情。那么修复 bug 和应对需求变化,就成了(国内)很多团队研究这些技术的主流原因。
事实上这件事情在国内外是可以形成鲜明的对比的,这是一个怪现象:
- 国内应用热衷于做 HotFix
- 国外应用热衷于做 Code Review
国内的团队总是很急,总是要什么需求就要立刻要,有些甚至是产品经理随意去验证自己的想法,完全不尊重软件研发客观规律的做法。而 App Store 的 Review 是要时间的,所以就开始各种开脑洞想要绕过这个过程。
而很多国外的项目(比如说我现在参与的 Outlook Mobile)完全没有任何动态技术,但是 Code Review 却很严格,开发的周期也比较长,更希望能把问题扼杀在摇篮里。
# 严重之处
其实今天这件事情出来的时候我是表示很震惊的,正如所有 Apple 告诉你的事情一样,这件事情的严重之处在于他的「模糊」,没有人明确的知道 Apple 到底在反对什么,他告诉你很多个可能性,让你自己去找有问题的地方。其实就像中国电影审片一样,没有标准就是最难的标准,甚至有时候会很靠运气。
Apple 在审核条款里面是明确表示不能加载动态的下发脚本,改变应用本身的意图。但是这个定义其实是非常非常含糊的,我认为这不是一个可以明确执行的定义。
- 什么叫脚本?什么叫程序?
- 什么样的程度叫做改变了应用本身的意图?
- 游戏加载脚本是业界通行的做法,Apple 会禁止吗?
- 为什么 WebView 里面加载 js 就可以呢?
- 通过 Web 和 Native 来区分是否是动态加载程序这是对的分类吗?
- 微信小程序到底有什么样的 PY 交易?(逃
总之这件事无论从各种角度来看,都很苹果。
就像飞机上不能携带超过 100ml 的水一样,根本原因是因为安检无法低成本的分辨是否易燃易爆,所以 Apple 非常广泛的发了这样的「震慑」邮件。
# 这样有用吗?
由于 Objective-C 夸张的动态性,其实我们很早就知道,Apple 从技术层面比较难完全防止掉这样事情的发生。
甚至退一步讲,完全不用任何动态技术,也不用任何私有 API,都可以让应用在审核期间看起来和用户用起来是完全不一样的,这种用一个开关来控制的小把戏我想大家都心知肚明。我想 Apple 真正痛恨的应该是这种欺骗,所以他只能尽可能的让这种「变化」还处于他的掌控之中。
毕竟如果一个应用只剩下一个「壳」的话,动态技术可以加载任何内容,App 审核也就形同虚设了,作为一个很有控制欲的公司,这种失控是苹果真正痛恨的。
# 后续发展
从目前来看,Apple 主要针对的是 JSPatch 和 Rollout 一类的热修复框架,这类框架的特点是可以下发后执行任意的 Native Code,而以做 Feature 为主的 React Native 和 Weex 并未被针对。
我个人非常期待这件事的进展,JavaScriptCore 作为一个非常有用的框架,我不希望就这样废掉。甚至我们可以发现,Apple Music 很多地方就是用 JS 实现的,这一点非常有趣。
我希望 Apple 可以在较劲之后找到一个平衡的点,减少自身 SDK 的 bug,加快审核的响应速度,开放一点。
而我们应该做的,就是上线前保证质量,并且祈祷遇到合格的产品经理。(逃
- EOF -