IOS基础与进阶ios开发iOS开发-高级汇总

写给移动开发者的 React Native 指南

2017-03-13  本文已影响50473人  wingjay

前言

React Native 诞生于 2015 年,名副其实的富二代,主要使命是为父出征,与 Apple 和 Google 抗衡,为开发者带去一套跨平台、动态更新的 Javascript 框架,口号是:Learn once, write anywhere:Build mobile apps with React。在试图推翻 Android 和 iOS 压制的同时,还提携了一把自家兄弟:React。

从诞生之日 React Native 就充满了期待和争议。期待是无数开发者希望不用忍受频繁发版的噩梦,也不用同时为两个平台开发业务逻辑几无差别的两个 App;争议是 React Native 真的能以一己之力救大众于水火吗?React Native 在跨平台时还能保持良好的用户体验吗?

当然我们知道,这种问题向来都是仁者见仁,智者见智。比起一味的疑惑、争论,还不如来好好看看这货究竟是个啥?甚至自己动手来玩一把。

本文主要针对两类读者:

目录

一、React Native 好在哪

下面我们来看下 Hybrid 及 React Native 等开发模式包含了哪些常规移动开发所不具备的优势。

1. 跨平台+动态更新

传统的客户端开发模式是怎样的呢?

Android 与 iOS Team 分别编写客户端代码,打包,分发到 Play Store 和 Apple Store,通过更新 JSON 数据来更新页面。

不过,当客户端发生严重问题而服务器上无法 quick fix 时,就不得不重新发版。

对国外 Android 市场而言还好,因为能通过 Play Store 快速更新;国内 Android 市场则由于分发渠道太杂,很难及时把新版本立即推送给所有用户,当然这也是为何热修复技术在国内盛行而国外冷清的原因;而 Apple Store 则需要一定的审核时间,而且最近又在抓 iOS 热修复框架如 JsPatch、Rollout 等。

相比而言,Hybrid 和 RN/Weex 模式除了能下发 Json 数据来刷新界面内容,更能直接下发业务逻辑代码,直接实现整体 App 的更新。而且,它们不用在乎 Android 和 iOS 两个平台,因为一份 JS 代码写好后,把 JS Bundle 放在服务器上,所有的客户端立即更新。

2. 代码复用

一般而言,同一款产品的 Android 和 iOS 两端除 UI 有些许不同外,多数业务逻辑几乎完全一致,这便造成了人力的浪费。

而最近 Instagram 的官博 React Native at Instagram 一文中已经提到,利用 RN (React Native 缩写,下同) 开发的 feature 可以实现 85% - 99% 的代码复用率。这意味着我们可以用更少的人力成本来达到相同的效果。

3. RN vs Weex

实现上面的效果有两种开发框架:混合开发框架 Cordova 和基于 Javascript 的 React-Native、Weex 框架。

下面我从自己的实践经验出发做些比较,也欢迎读者提出自己看法。

最开始觉得 RN 的学习成本比较大,所以首先考虑了 Weex 框架,据说是阿里巴巴良心出品。不过在尝试后不得不选择了放弃,原因有这几点:

**Issue is for bug report, not for Q&A**

当然,我是很希望国内也能推出优质的开源项目来和国外大厂抗衡的,不过真正优质的大型开源项目往往除了开发者的个人能力,和公司的战略和制度关系也很大。

4. RN vs Hybrid

这里的 Hybrid 开发主要针对 Cordova 框架,其实在放弃 Weex 之后我们还是没考虑 RN,而是转过去了解 Cordova,不过做了大致了解后也放弃了。主要硬伤有两点:

性能和用户体验是移动 App 的命根子。

因此,综合考虑下来,我们还是决定相信 Facebook 并采用 RN。

5. RN 劣势

上面我提到了 RN 的一些优势,不过作为开发者更加需要明确其劣势,我总结了下大概有以下几点劣势:

二、React Native 运行机制

对于一个用 RN 搭建的移动 App,在启动后会从服务器下载最新的 JS Bundle 文件,然后由本地 JavascriptCore 引擎对 JS 文件进行解析,并利用 Bridge 映射到对应的 Native 方法和 UI 控件。得到的效果是:

  1. 同样的 RN 代码,下发到 Android 和 iOS 不同平台中,会自动调用对应 Native 的 UI 控件,保证了各平台用户体验的连贯性;
  2. 开发者就算是移动端小白,只要有 Web 基础,通过编写一套 RN 端代码就可以同时完成 Android 与 iOS App 的开发;
  3. 由于可以利用 JS bundle 同时下发数据和业务逻辑,这意味着你可以像 Web 开发一样,实时迭代更新你的移动端 App,无需在了解各自平台的热修复技术;
  4. Native Modules,这是 RN 强大的一个扩展性,允许你通过简单的代码就能实现在 JS 里直接调用你自己的 Native 方法;
  5. Native Components,如果你自己实现了一些复杂的 Native UI 组件,而这些组件尚未被 RN 支持,你可以利用 Native Components 快速把原生组件引入到 RN 中并可以直接在 JS 里更新这些组件的状态。

三、RN 开发环境搭建

首先 IDE 方面,RN 推荐了一些工具:

本人的话目前采用的是 Sublime,因为个人常用 Sublime,而且第三方插件很丰富,轻量方便。下面简单说下配置,感兴趣的小伙伴可以看下。

  1. Babel 用来高亮 React JSX 语法,支持 ES6,而 React-Native 就是搭建在 React.js 基础上的;
  2. React-Native-Snippets 可以快速生成 RN 的一些模版代码;
  3. ESLint 超级强大的 Lint 工具,支持 ES6、JSX 语法检查,而且还有 React 和 RN 的插件,比纯粹的 JSXHint/JSLint 都强大;

当然,用 Atom 的小伙伴自然要首先考虑 Nuclide

四、引入 React Native

引入 RN 有两种方法:从零构建;集成到已有项目。

1. Build from Scratch

先说第一种,从零开始构建,比较简单,遵循官方文档 Getting Started 基于你自己的操作系统和平台一步步安装相关的依赖,然后利用如下命令:

react-native init AwesomeProject

你就创建好一个 RN 工程项目了,结构如下:

RN 目录结构

里面有四个文件夹:

2. 集成到已有项目

有很多公司是希望在现有 App 的基础上集成 RN 来开发一些特定的 Feature,这种情况就不能参考上面的方法了。在 RN 的官方文档里有一节 Integration with Existing Apps , 只需要按照一步步做即可。

以 Android 为例,大概要做以下几步:

  1. 添加 gradle 依赖:compile "com.facebook.react:react-native:+" // From node_modules.
  2. 创建空的 Activity ,指定 JS bundle 和入口 Component 名字即会自动在这个 Activity 里去加载 JS bundle 文件;
  3. 在 Activity 里监听 onBackPressed 事件,用来与 JS 端协作处理返回键点击事件。
  4. 启动 server,运行 App 即可。

总之需要说明的是,即使是移动端小白,也可以遵循文档里的指示完成这一步。接下来的大部分时间只要关心 JS 端开发就行了。

五、Javascript、React 及 ES6、JSX 语法

我们知道 RN 采用了 React 和 ES6 的语法,所以我们必须先对这些语法有一定了解才能去读 RN 的代码。

关于 Javascript,我推荐 W3School 里的 JS语法 和 MDN 里的 JS手册,大家只要对一些基础语法做些了解就可以。

关于 React,我推荐 阮一峰 写的 React 入门实例教程,基本上把文章读一遍,再自己动手写一遍,就能理会到 React 的大致用法了。

关于 ES6ES7JSX等,感兴趣的可以看一下 RN 文档中 Javascript Environment 里提到的支持的方法,需要时再来查询也可以。也可以看 Babel 出的 Learn ES2015 手册

这里有一个很不错的 GitHub 项目,帮助你通过交互性的例子来快速上手语法知识:React Native Express

六、UI 层

简单熟悉了 React 语法后,基本能正常阅读 RN 的示例代码了。

正式开发 App 的第一步当然就是写 UI 界面了,由于 RN 已经封装好了一套 JS 的 UI 组件,这些组件会自动在 Android/iOS 端调用对应的原生 UI 组件,因此我们只需要熟悉这些 UI 组件的用法及属性、回调方法即可。

我们可以在文档的 Components 看到不少组件,比如View, Text, Button, Image, Switch, 还有我们用的最多的 ScrollViewListView

在读文档时,我们可以先通过一边写代码一边读文档的方式进行,RN 非常贴心,直接在 Web 里嵌入了模拟器,我们只要修改编辑框里的代码,立即就能在右边的模拟器看到效果。这极大的降低了我们的学习成本。


Text Component

另外,在学习一个组件时,我们要区分哪个属性是某个平台特有的。比如下面两个 Text 的属性:textBreakStrategy 只会在 Android 上生效,而 adjustsFontSizeToFit 只可以用在 iOS 上。

Platform Specific Properties

然后,如果你希望在 Android 和 iOS 里显示不同的内容怎么办呢?RN 里有一节是Platform Specific Code,可以有如下几种形式来进行区分:

if (Platform.OS === 'ios') {
  // stuff for ios
} else {
  // stuff for android
}

除此之外,UI 组件的用法学习就很类似常规的 Html 标签了,只要知道其使用方式即可,甚至需要用的时候再来查文档也行。

七、网络请求层

学完上面的我们已经能够写出 UI 界面了,而且这套界面已经能够在不同平台上转化成各自平台的 Native UI 了。然后,我们就需要去网络层请求真实数据了。

RN 里提供了 Fetch API 来进行实现。举个例子,你想要通过 GET 方法去请求数据并转化成 JSON,可以通过如下代码实现:

fetch('https://facebook.github.io/react-native/movies.json')
      .then((response) => response.json())
      .then((responseJson) => {
        return responseJson.movies;
      })
      .catch((error) => {
        console.error(error);
      });

熟悉 Reactive 编程的伙伴应该对这样的语法不陌生,比如 Android 上的 RxJava; iOS 上的 RxSwift;Web 上的 RxJS。上面 function 的功能就是:请求网址 https://facebook.github.io/react-native/movies.json,把返回的 Response 转化成 JSON object,取出 JSON object 里的 movies 字段。同时,如果发生 error 会被 catch 住。

当然,上面是最基本的 GET 请求,Fetch API 还支持自定义 Headers,更换 Method,添加 Body 等。

fetch('https://mywebsite.com/endpoint/', {
  method: 'POST',
  headers: {
    'Accept': 'application/json',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    firstParam: 'yourValue',
    secondParam: 'yourOtherValue',
  })
})

上面构建了一个基本的 POST 请求,添加了自己的 Headers:AcceptContent-Type,添加了 Body。

因此看下来,RN 里的网络请求不仅具备了 Reactive 编程的简洁,也能自定义常规的 Http 请求,写法简单。

除了 Fetch API 之外,RN 还内置了 XMLHttpRequest API(俗称 AJAX),而且支持TCP 全双工通信方式 WebSocket

八、Debugging 调试

调试是很多程序员非常关注的一个环节,因为 RN 是用 JS 写完后到 Native 解释成 Native 方法来执行的,因此如果能快速调试 JS 代码是非常重要的一环。

最开始 RN 的调试功能比较弱,不过现在的 Debugging 功能在我看来还是很不错的。一般来讲可以有以下几个调试方式:

1. In-App 报错

RN 里默认集成了 In-App 的错误提示方式,即在 App 运行过程中会弹出全屏的报错信息呈现给你,而你也可以通过阅读具体的错误信息快速找到错误原因。通过点击这个错误信息里的某一行,会立即自动打开对应的代码。


In-App Error
2. Console.log

在开发 Client 时,我们一般都会用 Log.log() 来打印一些运行时变量的值,然后实时查看打印出来的 log 来调试,在 RN 也一样,你只要在 JS 里写一句 console.log('this is log data'),就会自动在 Client 的常规 log 里能看到,比如 Android 的 adb logcat 里就会自动打印出'this is log data'一行。

3. 大杀器:Chrome 逐行调试

这个杀器的最牛逼之处就是可以像 Client 一样,逐行调试代码!

我们来看下面一张图。从左往右。先是文件目录,我们选中了 index.js 文件夹,然后第二个 Tab,是 index.js 的内容。这里关键的是我可以直接选中某一行代码设断点。当 Client 运行到这一行时,就会在第三个 Tab 里打印出运行时环境及变量。我们可以看到 props 里就有我们传进去的变量值。

Chrome Debug

有了以上几种调试方式,我们几乎可以和常规的 Native 开发一样来调试 RN 代码了,不得不说 RN Team 确实牛 x 啊!

九、从 JS 调用 Native 方法或显示自定义 Native View

这又是另一个牛 x 之处啊。

很多人觉得 RN 限制太多,只能支持有限的 View 组件和有限的方法,难以发挥 Client 的最大性能。简单点说,在 Client 可以绘制复杂的 View,可以调用高性能 C++ 等底层代码,但 RN 却做不到。

于是,RN 里提出了 Native ModulesNative UI Component 两种技术。

Native Modules:JS 里直接调用 Native(Java/Swift) 方法

所谓 Native Modules,就是自己在 Client 写好了某些方法,由于某些原因这些方法不太方便或者无法搬到 RN 里面,那么,我们可以在 Client 把这些方法暴露出来给 RN,然后在 JS 里可以像 import 普通的 module 一样把这些 Native Modules 引入进去,直接调用。

具体的实现方法可以参考文档 iOS Native ModulesAndroid Native Modules

Native UI Component:JS 里直接调用自定义的 Native View

很多时候我们在写 Client 时,为了实现 Designer 天马行空的设计,常常需要自定义 View,即自己绘制某些系统并不提供的特定 UI。可想而知,这些 View 肯定不会出现在 RN 的 UI Component 里。

那么,我们就需要首先在 Native 层自己写好一个自定义 View,然后利用Native UI Component 技术把这个 View 及其中某些 public 方法暴露给 RN,那么 RN 就能直接 import 进来并显示了。

具体的实现方法可以参考文档 iOS Native UI ComponentAndroid Native UI Component

如果读过文档不是很理解的小伙伴可以留言,我再 post 一些 demo 代码上来

十、React Native 适合你吗?

这里借鉴下前段时间旧金山的 React Native 会议上的一些优劣总结给读者以参考。当然不一定对,仅供参考。

RN 的优点:

RN 的缺点:

适合下面这些人/公司:

下面这些人要稍微考虑下:

十一、为什么要写这篇文章

几个月前我对 React Native 也非常不看好,当然现在也没有说非常看好。或者说,写这篇文章毫无为 React Native 布道之意。

接触 React Native 主要是因为业务需要,PM 希望能够随时改动某块变化较大的模块,常规的开发提交流程往往需要较长的时间,而热修复技术本身并未得到 Google 和 Apple 的官方认可,也就是随时可能因破坏生态安全之名被取缔。

因此才考虑去了解 Hybrid 开发和 JS Native 开发模式,在了解过程中,又由于性能差、用户体验不好而放弃 Hybrid,由于社区不完善、Bug 较多等原因放弃 Weex,最终才选择了 React Native,开始学习 React、JSX等语法。

目前使用下来对 React Native 的一些个人感受:

  1. 学习门槛并没有开始想象那么高。大概只花了两三天时间就熟悉了 Javascript、React 框架、JSX语法,然后就开始着手业务开发。
  2. 对 Android App 的影响。React Native 会给 Android 端带来 6MB 左右的 size 增幅,不过在采用了 split apk 后就只有 1MB 左右增幅。
  3. Debug 功能比较完善,至少不用担心发生问题后不知从哪下手。
  4. 性能还行。最初担心的是 React Native 性能不好,但自己上手后,并没有明显感觉到很明显的 React Native 对 App 性能的负面影响,无论是 iOS 还是 Android,当然,这一点还在继续考察中。
  5. 动态部署真的很不错。以前每次写好代码都要花不少时间来编译运行,而现在只要写一份代码,就可以同时在 Android 和 iOS 实时更新了,这无疑节省了生命。
  6. 有待完善。当然,React Native 中确实还存在着不少问题,生态系统也还不够完善。不过我相信,这只是时间问题。

关于React Native一直以来都有很多争议。

不过我想说的是,React Native 所代表的跨平台、动态更新技术已经引起了全世界开发者关注,而且这种技术势必会是未来的需求和潮流。React Native 不一定会成功,但至少目前 React Native 已经是这一领域的领跑者。

而写这篇文章的目的,就是希望告诉更多开发者,React Native 并不完美,但值得一试。

谢谢。

wingjay

上一篇下一篇

猜你喜欢

热点阅读