Instagram 的 iOS 原生代码热加载技术

发布于:2018 年 5 月 10 日 18:24

在 Instagram 和 Facebook,React Native 让我们能够以更快的速度推进迭代产品。在模拟器上使用⌘R 快捷键就可以查看更改效果。然而使用原生代码进行开发,每次都需要重新编译、链接、安装、启动等一系列步骤才能查看更改效果。

即便是一个小项目,这样的开发流程也会让开发者感到很繁琐。在我们的项目规模上,结果就是工程师要花费大量的时间来等待电脑完成构建任务,等待的过程中又经常会切换到其他应用,从而浪费了更多的时间。

去年年底我们着手将 React Native 的开发体验带入 Objective-C 原生代码的开发中,目的是让工程师能及时看到代码更改效果。为了实现这一点,我们通过在运行时加载新代码来避免重启应用。

如何重新加载原生代码

为了重新加载原生代码,第一步需要将修改过的代码转换成正在运行的应用可以加载的动态库。这一步操作非常快,该操作以文件为单位进行:只编译有改动的文件,并链接为一个动态库。

iOS 真机设备不允许应用加载其自身 bundle 以外的动态库。同时也不允许应用向其自身 bundle 写文件。因此可加载的动态库必须在应用安装时就已经存在其 bundle 里,因此无法在真机上加载新的动态库。

幸运的是,iOS 模拟器上并没有这些限制。每个模拟器的文件系统其实就是 Mac 文件系统里的一个文件夹。另外,iOS 模拟器中的 dlopen 函数不会按文件位置进行过滤,这使得无论如何都可以直接将动态库写入应用程序的 bundle 中。

我们在程序代码中新增了一个启动方法,该方法会在 debug 模式下生成一个后台任务来监听指定文件夹的内容变化。动态库创建好后会移动到指定文件夹。这会触发应用中设置好的回调,执行以下几个步骤:

  • 加载新的动态库。
  • 确定添加了哪些 Objective-C 类。
  • 查找这些类的原始版本。Objective-C 类本身也是对象,很容易通过名字找到。
  • 使用 Objective-C 运行时 APIs 来替换这些原始类的方法实现为新的实现。这会替换类所有的方法实现,因为我们无法确定哪些方法实现有改动。
  • 将执行结果写回相同目录以便工具读取。

到这里我们的新代码已经在应用中跑起来了,下一次调用这些方法就会执行我们的新代码。当然,这只有在 iOS 模拟器上做开发时可用,真机和生产环境是不可行的。

构建开发体验

重新安装、重启应用来查看更改效果很慢,但简单可靠。在 Xcode 中按下按钮或快捷键,最终,代码的结果会显示在屏幕上。我们在我们的插件工具中做了类似的事情:在 Xcode 的工具栏放置了一个按钮和快捷键来触发加载新的代码。

与重启应用相比我们还有另一个优势:保持应用的当前状态。重启会重置应用回到最初的入口 - 对我们的应用来说是 feeds 首页。负责其他模块的工程师必须重新点击进入到自己的模块才能查看他们的修改是否正确。

然而,新的代码加载后,什么也不会发生:应用之前的状态不会受到影响。幸运的是,在 Facebook 上使用的声明式 iOS UI 框架 ComponentKit 具有执行即时重新布局的有用方法: + [CKComponentDebugController reflowComponents] 。使用 ComponentKit 构建的视图可以在新代码加载后调用该方法,来让布局代码重新执行并,并在屏幕上立即更新。结果就是,使用 ComponentKit 进行布局,工程师可以及时查看布局的修改。以前,工程师需要批量更新并考虑何时需要重启。 现在他们可以交互式地迭代工作。

总结

我们的工具在小组内已变得非常流行,特别是使用 ComponentKit 的工程师。在大型应用中,这使得工程师查看修改结果的速度提升了 20 倍。高性能、与现有开发工具和框架的紧密结合已经让原生代码的加载成了在 Instagram 和 Facebook 的 iOS 工程师平时工作流程中的重要一环。

Nate Stedman 一名来自 Instagram 纽约的 iOS 工程师。

感谢覃云对本文的审校。

阅读数:1447 发布于:2018 年 5 月 10 日 18:24

更多 iOS、语言 & 开发 相关课程,可下载【 极客时间 】App 免费领取 >

评论

发布
暂无评论
  • Android Studio 2.3 支持构建缓存,改进的 Constraint Layout,以及更多新特性

    Google发布了Android Studio 2.3版本,Android Studio是Android开发的官方IDE,该版本为整个开发流程添加了许多新特性。

    2017 年 3 月 15 日

  • 内存优化(上):4GB 内存时代,再谈内存优化

    如今4GB内存的手机都变成了主流。那内存优化是不是变得不重要了?如今有哪些技巧已经淘汰,而我们又要升级什么技能呢?

    2018 年 12 月 6 日

  • Facebook 开源 React Native 以及相应的 IDE:Nuclide

    近日,Facebook开源了能够使用JavaScript开发iOS和Android原生应用的React Native。目前,React Native已实现了对iOS平台的支持,并且Facebook已经使用React Native开发出了多个产品,如iOS平台下的聊天工具Groups等。同时,Facebook还为React Native开发了一款基于Atom的开源IDE。

    2015 年 3 月 31 日

  • ZeroTurnaround 宣布 JRebel for Android 1.0

    ZeroTurnaround发布了JRebel for Android的第一个稳定版本。它是流行插件JRebel的Android版本,允许修改正在运行中的应用程序,而且不必重新部署或重启。JRebel for Android适用于Android Studio,可以从JetBrains插件库下载,支持所有运行Android 4.0及以上版本的手机和平板。ZeroTurnaround提供了为期21天的免费试用,起步价为每年49美元。

    2016 年 1 月 14 日

  • Safari 开始支持 WebRTC

    WebRTC是基于浏览器的实时通信接口,主要支持通过浏览器进行点对点的音频以及视频通信。WebRTC规范由W3C和IETF共同制定。通过这些API,Web开发者可以通过标准的JavaScript API在网页中嵌入视频、音频通信功能。

    2015 年 9 月 11 日

  • Flutter 1.2 发布,带来全新的 Web 开发工具!

    2月27日,在世界移动通信大会上,Flutter团队宣布推出Flutter 1.2。

    2019 年 2 月 27 日

  • 预习篇 · 从 0 开始搭建 Flutter 工程环境

    今天这篇文章要达到的目的是,帮助你完成Flutter开发测试环境的安装配置。

    2019 年 7 月 1 日

  • 导读 | 如何打造高质量的应用?

    既然打造一款高质量的应用那么困难,我们可以先从哪里入手做些什么呢?

    2018 年 11 月 29 日

  • 链接器:符号是怎么绑定到地址上的?

    了解程序运行阶段的动态库链接原理,会让你更多地了解程序在启动时做的事情,同时还能够对你有一些启发。

    2019 年 3 月 21 日

  • RoboVM 1.0 正式版发布,并公布了商用许可协议

    RoboVM是一个能够将Java字节码转换为原生ARM或者x86代码的AOT预编译器/平台,其目标是在iOS设备上使用Java和其他JVM语言。近日,从RoboVM的官网得知,其1.0正式版发布,同时还公布了商用许可协议,该版本实现了所有Java调试线协议JDWP(Java Debug Wire Protocol的缩写)、RAM缓存的支持、HFS+文件压缩等改进。

    2015 年 3 月 24 日