読者です 読者をやめる 読者になる 読者になる

YDブログ

(Y)やりたいことしか(D)できない病のブログです。

「React Native」入門

Javascript プログラミング React Native

スポンサーリンク

今年のプログラミングネタは「React Native」推しです。

本来であればコマンドを2つ3つ覚えるだけで、APIドキュメント片手にゴリゴリ開発できるはず……が、記事を書いた時点のバージョンはいまだ0.25。 けっしてマニュアル通りすんなりコトは運びません。 ハマった点を記録しておきます。

目次

予備知識。「React Native」とは?

React Native」はJavascriptでiOS・Androidのハイブリッドアプリが作れる開発環境です。 Web開発フレームワーク「React.js」をベースにしています。 facebookが開発しています。

HTML5・WebViewハイブリッドアプリではない

React Nativeは数あるJavascriptフレームワークのひとつですが、IonicCordovaのようにブラウザ・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」です。

使い方

チュートリアルはコチラ。

facebook.github.io

下のリンク集も参考になります。

github.com

インストール〜シミュレータ・実機でテスト

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.jsindex.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()で書き込みます。

これだけわかれば、あとはサンプルコードで自然におぼえられます。

www.reactnative.com

rnplay.org

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をメインにしようと思います。

関連記事

matagotch.hatenablog.com