React Native for Android 入门老虎

昨天期待已久的 React Native for Android 发布了,赶紧来尝试一下,我跟着这个 Getting Started 开开始入门。发现被一些 "老虎" 堵在门口, Hello World 都跑不起来,入不了 React Native 的门,让我很懊恼,最后终于解决。可能大家也会遇到类似的问题,这篇文章希望能帮到你。

安装环境

根据官方的入门文档,需要安装 Homebrew, nvm, Node.js 4.0, watchman, flow。

首先 Homebrew 大家应该都安装好了,这里就不说了。接下来实用 brew 安装 nvm:

$ brew install nvm

然后会提示你把 nvm 加入环境变量中,例如,我就在 .bashrc 或者 .zshrc 中加入如下两行:

export NVM_DIR=~/.nvm  
source $(brew --prefix nvm)/nvm.sh  

然后使用 nvm 安装最新的 Node.js 4.0(Node.js 怎么突然到了 4.0 了,之前版本都是 0.xx?还是很惊讶的)。

$ nvm install node && nvm alias default node

我在这里遇到了第一只 "老虎"。这个命令执行不下去,我来打开 NodeJS 官网,发现竟然打不开,原来是 Node.js 的访问有问题。如果也有同学和我一样,可以点击这里下载这个安装包直接安装也可以。

另外多说一句:nvm 确实是一个好东西,可以在你的机器上装几个版本的 Node.js,然后根据需要切换版本。例如装完 4.0 以后,发现 Hexo 挂掉了,可以方便的实用 nvm 切换到 0.12。

后面的安装没有啥问题,按照官方文档来就可以:

$ brew install watchman
$ brew install flow

最后,最好执行一下如下命令,更新相关软件:

$ brew update && brew upgrade

开始 Hello World

环境安装好了,迫不及待的来 Hello world。运行如下几条命令,直接可以生成一个样例项目:

$ npm install -g react-native-cli
$ react-native init AwesomeProject
$ cd AwesomeProject/

接下来就是激动人心的时候,插上手机,开始运行:

$ react-native run-android

这里会使用 Gradle 进行编辑。编译过程中有可能会出现 Android sdk 找不到,Build tools 版本找不到的错误。这是因为 RN for Android 需要环境变量 ANDROID_HOME

export ANDROID_HOME=/usr/local/opt/android-sdk  

并且需要 Build-tools version 23.0.1,API 23 等,安装好就可以正常编译了。

正常情况下会自动安装安装 APK 包并运行,与此同时会打开一个终端运行 dev server。但是,我期待的 Hello World 页面并没有出现,只是出现了一个空白的 Activity。发生了什么?我一步一步检查我的配置过程,是不是我漏掉了什么,并没有发现我做错什么。

我发现运行运行 dev server 的终端中打出了一些错误信息:

dyld: Library not loaded: /usr/local/lib/libpcre.1.dylib  
  Referenced from: /usr/local/bin/watchman
  Reason: image not found

dyld: Library not loaded: /usr/local/lib/libpcre.1.dylib  
  Referenced from: /usr/local/bin/watchman
  Reason: image not found

Watchman:  watchman--no-pretty get-sockname returned with exit code null dyld: Library not loaded: /usr/local/lib/libpcre.1.dylib  
  Referenced from: /usr/local/bin/watchman
  Reason: image not found

 ERROR  watchman--no-pretty get-sockname returned with exit code null dyld: Library not loaded: /usr/local/lib/libpcre.1.dylib
  Referenced from: /usr/local/bin/watchman
  Reason: image not found

Error: watchman--no-pretty get-sockname returned with exit code null dyld: Library not loaded: /usr/local/lib/libpcre.1.dylib  
  Referenced from: /usr/local/bin/watchman
  Reason: image not found

    at ChildProcess.<anonymous> (/Users/Jing/Projects/ReactNative/AwesomeProject/node_modules/react-native/node_modules/sane/node_modules/fb-watchman/index.js:194:18)
    at emitTwo (events.js:87:13)
    at ChildProcess.emit (events.js:172:7)
    at maybeClose (internal/child_process.js:817:16)
    at Socket.<anonymous> (internal/child_process.js:319:11)
    at emitOne (events.js:77:13)
    at Socket.emit (events.js:169:7)
    at Pipe._onclose (net.js:469:12)

经过一番搜索,发现是 pcre 找不到,通过如下命令即可修复:

$ brew uninstall pcre && brew install pcre

有时候你运行 react-native run-android,发现并不能自动运行 dev server,你可以在当前项目目录中运行如下命令来手动启动 server:

$ react-native start

再次启动,发现还是空白的页面,终端中也没有任何的错误提示,按 menu 键、摇手机也没有出现官网中所说的开发者菜单。

是不是我手机的问题?我决定使用模拟器试一下,果然,终于出现能够正常显示了内容了。也知道正常的 React Native App 开发运行时怎么样的了:首先会出现一个 Loading JS 的窗口,并且在 dev server 端也会打出客户端下载 JS Bundle 的 log。

我再用手机试一下,发现 APP 直接显示一个空白的页面,dev server 终端也没有打印任何 log。难道是 dev server 没有连接上 server 端?看一下 Logcat 的 log,有如下错误:

E/unknown:React: Unable to download JS bundle  
E/unknown:React: java.net.ConnectException: failed to connect to localhost/127.0.0.1 (port 8081) after 5000ms: isConnected failed: ECONNREFUSED (Connection refused)  
E/unknown:React:     at libcore.io.IoBridge.isConnected(IoBridge.java:223)  
E/unknown:React:     at libcore.io.IoBridge.connectErrno(IoBridge.java:161)  
E/unknown:React:     at libcore.io.IoBridge.connect(IoBridge.java:112)  
...
E/unknown:React:  Caused by: libcore.io.ErrnoException: isConnected failed: ECONNREFUSED (Connection refused)  
E/unknown:React:     at libcore.io.IoBridge.isConnected(IoBridge.java:208)  
E/unknown:React:     at libcore.io.IoBridge.connectErrno(IoBridge.java:161)  
E/unknown:React:     at libcore.io.IoBridge.connect(IoBridge.java:112)  
E/unknown:React:     at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:192)  
E/unknown:React:     at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:460)  
E/unknown:React:     at java.net.Socket.connect(Socket.java:833)  
...

发现,果然是 Server 访问错误。参考官方文档。对于 Android 5.0 及以上的设备,直接运行:

$ adb reverse tcp:8081 tcp:8081

我找来一个 Android 5.0 的机器,果然可以了。对于 5.0 以下的机器,上面的命令会出错:

$ adb reverse tcp:8081 tcp:8081
error: closed  
error: closed  

我的主力开发机器是 Android 4.4 的。按照官方文档,需要按 menu 键或者摇晃手机,在开发菜单中设置一下 dev server 的 IP 地址。前面我就试过了,我怎么操作都不能打开这个菜单。突然想到,是不是系统屏蔽了?我去找系统权限设置,发现如下:

果然,系统默认禁用掉了 APP 的显示悬浮窗的权限。因为那个菜单是实用悬浮窗来显示的,所以一直看不到。开启这个权限,然后就可以正常唤起菜单了。然后菜单中选择 Dev Settings -> Debug server host for device,填入你开发电脑的 IP 地址。如果手机和电脑不在同一个网段,或者手机不能访问到,就会出现如下页面:

之前显示空白页面,其实应该是弹出这个错误页面的,因为这个页面也是一个悬浮窗,默认也被禁止了。

到现在,终于真相大白了,可以对 React Native "Say Hello" 了。为了运行一个 Hello World 花费了我不少时间,接下来就可以开始 React Native 之旅了。

总结一下

  1. 确保相关工具和 Android SDK 都是最新的;
  2. 因为 React Native for Android 提示错误和开发菜单都是通过悬浮窗显示的,要注意的 ROM 有没有自作聪明的帮你默认禁用掉了显示悬浮窗的权限;
  3. RN 需要启动一个 Dev server 来辅助开发,Android 5.0 可以直接通过 USB 的访问,5.0 以下只能通过 WiFi 来访问。为了便于开发,还是建议实用 5.0 的机器。

Read more

Android 上的低功耗蓝牙实践

这是我在 Droidcon Beijing 2016 和 GDG Devfest 2016 上做的分享,以下是正文: Slide 01 我今天分享的主题是 Android 上低功耗蓝牙的实践。这个主题比较小众。我在过去的一年多的时间里,主要是在做低功耗蓝牙相关的开发。接触过程中发现,BLE 的开发和通常的 Android APP 的开发有点不一样,这里需要访问硬件资源,而且涉及到一些协议相关的内容,而且这方面的资料也比较少。今天我从 Android 开发者的角度,来分享一下低功耗蓝牙开发实践。 Slide 02 今天分享的内容,主要包含如下几个部分:首先对蓝牙和低功耗蓝牙做一个简单的介绍;然后介绍 Android 上对低功耗蓝牙的支持;再介绍一下在 Android 平台上可以开发哪些低功耗蓝牙应用;然后是,开发过程中,可以帮助我们调试的工具;最后,总结一下所谓的 “最佳实践”,低功耗蓝牙开发的一些小经验。 Slide

By Race604

React Native 触摸事件处理详解

触控是移动设备的核心功能,也移动应用交互的基础,Android 和 iOS 各自都有完善的触摸事件处理机制。React Native(以下简称 RN)提供了一套统一的处理方式,能够方便的处理界面中组件的触摸事件、用户手势等。本文尝试介绍 RN 中触摸事件处理。 1. RN 基本触摸组件 RN 的组件除了 Text,其他组件默认是不支持点击事件,也不能响应基本触摸事件,所以 RN 中提供了几个直接处理响应事件的组件,基本上能够满大部分的点击处理需求TouchableHighlight, TouchableNativeFeedback, TouchableOpacity 和 TouchableWithoutFeedback。因为这几个组件的功能和使用方法基本类似,只是 Touch 的反馈效果不一样,所以一般我们用 Touchable** 代替。Touchable** 有如下几个回调方法: * onPressIn:点击开始; * onPressOut:点击结束或者离开; * onPress:单击事件回调; * onLongPress:长按事件回调。 它们的基本使用方法如下,

By Race604

React Native 中 ScrollView 性能探究

1 基本使用 ScrollView 是 React Native(后面简称:RN) 中最常见的组件之一。理解 ScrollView 的原理,有利于写出高性能的 RN 应用。 ScrollView 的基本使用也非常简单,如下: <ScrollView> <Child1 /> <Child2 /> ... </ScrollView> 它和 View 组件一样,可以包含一个或者多个子组件。对子组件的布局可以是垂直或者水平的,通过属性 horizontal=true/false 来控制。甚至还默认支持“下拉”刷新操作。另外还有一个特别赞的特性,超出屏幕的 View 会自动被移除,从而节省资源和提高绘制效率。我们来看如下一个例子: class

By Race604

30 天入门 Android 开发, Google 与你一起圆梦

经常会有朋友让我推荐 Android 开发入门的教程或者视频,我一直是推荐看官方的教程。大部分人或者觉得比较迷茫,或者觉得坚持不下去。这次推荐这个《30 天入门 Android 开发》是 Google 亲自发起的免费教学,以学习小组方式,大家可以一起学习和交流。一个好的开始,是成功的一半。让 Google 工程师带领你一起进入多彩的 Android 开发大门。点击这里 报名。 Android 设备已经随处可见,你想尝试一下在 Android 设备上的开发和创新吗?快来跟随 Google 的步伐,一起学习 Android 入门课吧! Google Study Jams 活动介绍 Study Jams 是一个学习 Google 在线课程的活动。该活动由学员自主发起课程学习小组,带领小组成员入门 Android 开发,最终将

By Race604