今年のプログラミングネタは「React Native」推しです。
本来であればコマンドを2つ3つ覚えるだけで、APIドキュメント片手にゴリゴリ開発できるはず……が、記事を書いた時点のバージョンはいまだ0.25。 けっしてマニュアル通りすんなりコトは運びません。 ハマった点を記録しておきます。
目次
予備知識。「React Native」とは?
「React Native」はJavascriptでiOS・Androidのハイブリッドアプリが作れる開発環境です。 Web開発フレームワーク「React.js」をベースにしています。 facebookが開発しています。
HTML5・WebViewハイブリッドアプリではない
React Nativeは数あるJavascriptフレームワークのひとつですが、IonicやCordovaのようにブラウザ・Webビュー(ブラウザ)経由のモノではありません。
書き方こそWeb向けJSフレームワーク「React.js」風ですが、かぎりなくNativeに近いアプリが作れます。
- 「React Native」 iOS・Androidにしか対応しませんが、パフォーマンスに優れている
- 「React.js」「Cordova」の組み合わせ iOS・Android・Webの3プラットフォームに対応。パフォーマンスは劣る
IonicというよりRubyMotionみたいな感じです。
Reactはコンポーネント指向
React.jsはコンポーネント思考です。
HTMLでいうdivとかimgとかいうタグを独自に定義できます。
AngularJSだと「ディレクティブ」にあたります。
class コンポーネント名 extends Component
で定義します。
ビルトインのコンポーネント(クラス)は公式ドキュメントにあります。 https://facebook.github.io/react-native/docs/getting-started.html
完全なハイブリッドアプリではない
React Nativeはネイティブのパフォーマンスを引き出すため、UIまわりであればビルトインのAPIでもiOS用とAndroid用が分かれています。
完全な同一コードで両プラットフォームに対応できるわけではありませんが、コードの大半を共通化できます。
ECMAScript6
新しいES6の構文が使えます。 コンポーネントの定義方法は従来のJSなら
var MyComponent = React.createClass({ getInitialState() { return { /* initial state */ }; }, });
ですが、ES6だと
class MyComponent extends React.Component { constructor(props) { super(props); this.state = { /* initial state */ }; } }
のような書き方になります。
MVCとflux
Ruby on Railsなど、これまでのウェブ開発フレームワークはMVC(Model、View、Controller)パターンを採用していました。
React自体はこのうちのビューしか扱わないので、大規模アプリケーションでモデルが複雑な場合はフレームワークを別に導入します。
その際、MVCに代わり「flux」アーキテクチャが勧められています。 fluxの実装は「redux」です。
使い方
チュートリアルはコチラ。
下のリンク集も参考になります。
インストール〜シミュレータ・実機でテスト
node.js、npmがインストール済みとします。
開発に必要なターミナルのコマンドは3つ。
npm install -g react-native-cli
でReact Native本体のインストールreact-native init プロジェクト名
でプロジェクト作成react-native run-ios
またはreact-native run-android
でビルド
です。ビルドコマンドでサーバーが立ち上がり、USBにスマホが繋がっていれば実機、繋がってなければエミュレータへテストアプリが配信されます。
シミュレータ・テスト端末の操作方法
シミュレータのエラー行をクリックすると、エディタの該当箇所にジャンプできます(少なくとも自分の使っているAtomの場合)。
スマホ実機を振るか、iOSシミュレータなら「コマンド+D」、Androidシミュレータならターミナルからadb shell input keyevent 82
で開発メニューが出せます。
コードの書き方
ソースコードのエントリポイントはindex.ios.js
とindex.android.js
でプラットフォームによって分かれています。
ファイル名にを"ios"とか"android"をつけるとプラットフォームに応じたコードがimportされます。
下の見本はindex.ios.js
の初期コードです。
import React, { Component } from 'react'; import { AppRegistry, StyleSheet, Text, View } from 'react-native'; class newProject extends Component { render() { return ( <View style={styles.container}> <Text style={styles.welcome}> Welcome to React Native! </Text> <Text style={styles.instructions}> To get started, edit index.ios.js </Text> <Text style={styles.instructions}> Press Cmd+R to reload,{'\n'} Cmd+D or shake for dev menu </Text> </View> ); } } const styles = StyleSheet.create({ container: { flex: 1, justifyContent: 'center', alignItems: 'center', backgroundColor: '#F5FCFF', }, welcome: { fontSize: 20, textAlign: 'center', margin: 10, }, instructions: { textAlign: 'center', color: '#333333', marginBottom: 5, }, }); AppRegistry.registerComponent('newProject', () => newProject);
class クラス名 extends Component
で定義したコンポーネントは、レイアウトrender()
メソッド内で<クラス名>
として呼び出せます。
各コンポーネント(HTMLタグのようなもの)はstyle属性で修飾します。
変数はconstructor()
関数内で初期化(古いやり方ならgetInitialState()
関数)、状態変数はthis.state
から読み、this.setState()
で書き込みます。
これだけわかれば、あとはサンプルコードで自然におぼえられます。
console.log()でデバッグ
iOSだとXCodeのパネル上にconsole.log()の出力が得られます。
Terminalで見たいならiOS Simulatorのシステムログから確認できます。
0.29以降のReact Nativeにはreact-native log-ios
react-native log-android
というコマンドもあるそうです。
つまったところ
ドキュメントが整備されていないのでトライ・アンド・エラーでがんばりましょう。
「Could not connect to development server.」エラー対策
ドキュメント通りセットアップ、ビルドすると最初に必ず直面するエラーがコレです。
React Nativeでは、スマホから開発サーバにアクセスしながら開発するので、スマホ側にPCのIPアドレスを教えなければいけません。
iOSの場合はAppDelegate.m
ファイル内jsCodeLocation
のIPアドレスを直接書き換えるか、AndroidならスマホのメニューDev Settings > Debug server host & port for device
からPCのIPアドレスを入力します。
iOSの場合はさらに後述のATSを無効に設定する必要があります。
開発機のIPアドレスはOSXならターミナルのifconfig
コマンドで確認できます。
デフォルトのポート番号は8081です。
iOSのエラー対策
ATS(App Transfer Security)でローカルホスト接続許可
React Nativeでの開発中はスマホからサーバにつなげるため、iOS/AppDelegate.m
のlocalhostを開発機のIPアドレスに書き換える必要があります。
iOSの場合はさらにセキュア通信(HTTPS)がデフォルト推奨で、通常のHTTP接続は許可が必要です(ATS=App Transfer Security)。 XCodeで許可を明示しなければスマホから開発機に接続できません。
ATSを無効にするにはinfo.plistに下のキーを追加します(下のやり方は本番環境では非推奨。限られたホストだけ許可すること)。
<key>NSAppTransportSecurity</key> <dict> <key>NSAllowsArbitraryLoads</key> <true/> </dict>
シミュレータで"Network request failed"エラー
いろいろ試してダメなら
iOS Simulator -> Reset Content and Settings...
です。
Androidのエラー対策
「SDK location not found. Define location with sdk.dir in the local.properties file or with an ANDROID_HOME environment variable.」
Android Studio(SDK)がインストール済みでも.bash_profileで環境変数「ANDROID_HOME」を設定しないと怒られます。
「failed to find Build Tools revision 23.0.1」
android list sdk -a
でBuild Tools revision 23.0.1を探します。
Build Toolsがリストの7番目だった場合は
android update sdk -a -u -t 7
コマンドで治ります。
スマホに転送できないとき
Execution failed for task ':app:installDebug'. > com.android.builder.testing.api.DeviceException: com.android.ddmlib.InstallException: Unable to upload some APKs
みたいなエラーが出た場合は、gradleのバージョンをダウングレードします。
android/build.gradle
ファイルのclasspath 'com.android.tools.build:gradle:1.3.1'
の1.3.2を1.2.3に変更します。
プラグインのインストール方法
パッケージは基本的にnpmでインストール。
モノによってはrnpmコマンドのrnpm link
でネイティブのプロジェクトにリンクします。
まとめ
React Nativeはシンプル・学習コストが低く、パフォーマンスも優れていて将来性の高さを感じます。
いまは普及途中でライブラリも充実していないのでJavaScriptで書けるのはUIや通信周りだけ、コア機能はネイティブで書いてプラグインで渡す場面が多くなりそうです。
そのうち1年もすれば環境も充実してJavascriptだけで事足りそうですが、それまではReact.jsとObjectiveCとAndroidSDKの3つの知識が必要かもしれません。
納期が2週間とかの場合(笑)ならこれからもIonicをつかいますが、今後のアプリ開発はReact Nativeをメインにしようと思います。