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

アニマネ開発日誌

アニメアプリのアニマネの開発日誌です。

React Nativeはアプリ開発者の夢を見るか?

ES6とReactの勉強を兼ねて、React NativeでiOSアプリとAndroidアプリを作ってみました。

アニメグッズの最安値を検索するアプリです。

React NativeはJavaScriptが書ければiOSアプリとAndroidアプリが作れます。 それに加えてHTML5のハイブリッドアプリとは違い、高速に動作すると謳われるプラットフォームです。

コードの共通化ができて、しかも高速というのは開発者にはとても魅力的です。

タイトルはパロディなので少々大げさな感じがしますが、実際に作って色々と分かりましたので、 React Nativeについて軽く紹介しつつ、これから導入を検討している人向けに書いてみます。

ざっくりとしたまとめ

長い記事なので、忙しい人向けのざっくりとしたまとめを置いておきます。

良いところ

  • iOSアプリとAndroidアプリをほぼ共通のコードで作れる
  • 言語(ES6)の習得コストが低い(新しくSwift,Objective-C,Java,Kotlinなどを覚えることに比べれば)
  • ライフサイクルを意識しなくても開発ができる
  • flexboxが使えるので、思い通りのレイアウトにしやすい
  • ビルド待ちのストレスから解放される
  • ネイティブアプリの開発経験がなくても頑張れば何とかなる
  • 技術的障壁が低いことでエンジニアを捕まえやすい

辛いところ

  • 開発速度と技術的容易さを維持するにはUIをある程度犠牲にする必要がある
  • UIはネイティブコードで実行されるが、ロジックはES6(JavaScript)なので、重い処理は苦手
  • UIの組み方によっては、動作が遅いケースがある
  • UIに凝りだすとネイティブコードが必須になる
  • まだ発展途上のため、バージョンによって挙動が変わることが多い
  • サードパーティ製ツールは多いがマメにメンテされてるソースが少ない
  • メモリの使用量が多いかも(アプリの構造にもよると思います)

こんなケースにおすすめ

Androidエンジニアと、iOSエンジニアが揃っていて、 UX/UIにはこだわりたいなら、基本的には手を出さくてもよいかも知れません

コードの共通化をはかるならC++とかで静的ライブラリを書いて、 iOSはそのまま使い、AndroidではNDKを使うのがベターと思います。

それ以外では下記のようなケースにあてはまる場合はReact Nativeがオススメです。

  • Web開発者しかいないけど、アプリを作ってみたい
  • とにかく開発スピードが求められる
  • ラピッド・プロトタイピングとして世にだしてから改善していきたい

斬新なアイデアの事業が多い、スタートアップなんかはよいかも知れません。 アプリ化はもやは必須になってきていますが、ちゃんとしたアプリを作れる人材を確保するのは大変だと思います。

React NativeはWeb開発の技術があれば何とかなるので、 UI的には未熟だけど、とにかく新しい事業を広めたいケースには最適と思います。

売上が上がって、ネイティブのエンジニアが揃えられたタイミングでネイティブに移行するもよし、 そのままReactベースで凝ったUIが実現できるようにするもよしと、選択肢が広がります。

前提条件

  • ReactNative 0.29
  • Xcode 7.3.1
  • Android Studio 2.1
  • 筆者はiOSアプリ、Androidアプリ共に開発経験あり。
  • Reactは全くの初めて。概念ぐらいはWebの記事で読んで知っている程度。
  • JavaScript自体はjQueryがなくても一通りの機能が実装できるぐらい。
  • CSSは普通に書ける。

React Nativeとは?

特徴

Facebookが2015年に公開した、アプリ開発のプラットフォームです。 JavaScriptでコードを書きながらも、UIは高速に動作することが特徴です。

最近人気がでてきているNative Scriptや往年のTitaniumも同じようなコンセプトですが、 最大の特徴はReactの仕組みでアプリが作れるということです。

悪くないパフォーマンス

JavaScriptで作られたアプリと言えば、かつては反応が悪いアプリの代名詞的な存在でした。

その結果、アプリ開発の黎明期に大量に作られていたHTML5のハイブリッドアプリは影を潜め、 現在はネイティブアプリが主流となっています。

FacebookHTML5を推進していることもあり、 過去に自社のFacebookアプリをHTML5のハイブリッドアプリとして提供していた時期がありました。

しかし、パフォーマンスの悪さからユーザーの評価が著しく低く、 ネイティブアプリに切り替えざるを得ない状況に陥りました。

マーク・ザッカーバーグは後にHTML5に賭けたのは最大の失敗だったとまで発言しています。

その過程で生まれたものなのかは定かではないですが、HTMLを高速にレンダリングできるReact.JSを世に出したのが2013年、 その2年後の2015年にはネイティブアプリを開発できるReact Nativeが発表されました。

React NativeはJavaScriptで作られたアプリのパフォーマンス問題を解決するプロダクトであり、Facebookがアプリ開発に対して出した答えの一つです。

どのようにパフォーマンスを向上させたか?

  • JavaScriptで開発を行いながらも、UIはネイティブのコードで実行
  • ビューの描画時にはReact.JSで培った仮想DOMの技術を利用
  • JSXと呼ばれるXMLに似た構文でビューを定義、各プラットフォームでの実行時にネイティブのコードへと変換する

React.JSで培った技術を最大限に使うことで、パフォーマンスを向上させています。

既にFacebook製のアプリの多くがReact Nativeで作られており、 ネイティブアプリと同じように扱えることを実感できます。

必要とされる知識

  • ES6 (簡単に言うとJavaScriptの機能を強化した言語です)
  • React(React.JSの知識があればすぐにでも作り始められます)
  • CSS (CSS自体は分からなくてもiOSAndroidの開発で、ビューをXMLで書けるなら問題なし)
  • npm等の周辺ツールの知識(開発し始めれば自然と覚えられます)

基本的にはWeb開発の知識があれば、アプリを開発することが可能です。

ただ、ネイティブアプリの知識があるにこしたことはないので、 iOSAndroidアプリのチュートリアル程度はやっておいた方が良いと思います。

ES6

JavaScriptの元となっている、ECMAScriptの第6版としてリリースされたのがES6です。

プロトタイプベースの言語にクラス構文を導入するなど大きく変わったバージョンで、 従来のJavaScriptを想像していると全くの別言語に見えると思います。

クラスに加えて、importなどのモジュールの概念が入ってきていますので、 その辺りだけ学べばとりあえずは開発できると思います。

ただ、SwiftやJava8,Kotlinと比べると言語的な貧弱さは否めません。 ですが、言語そのものの堅牢性を犠牲にする代わりに、開発人口の多いJavaScriptで作れると思えば悪くはないと思います。

React

React Nativeの中心となる、Reactについては最初にある程度学んでおいた方がよいです。

僕は多少の知識だけはあったので、そのままコードを書き始めましたが、 Reactの概念や思想を理解した上で使わないと、まともなコードが書けないと思います。

1〜2日あれば大体のことは理解できると思いますので、開発の前にある程度は知識を入れておくことをオススメします。

逆にReact.JSの開発者であれば、すぐにでも開発を進められると思います。

今回は作りながら、Reactの良さや課題となっていることが実感できたので、 とても良い経験になりました。

最初はコードの中にJSXが入っていることへの違和感が半端ないのですが、 コンポーネント化されたものと思えば、この書き方が自然に思えてきます。

頭を切り替えてReactの思想に傾倒するのが、習得への近道です。

React.JSの場合はHTML/CSSコーダーとエンジニアの分業が時々話題にあがりますが、 アプリ開発者ならHTMLほど分業化は進んでいないと思いますので、Reactという仕組みはむしろアプリ向きと思います。

開発環境

ネイティブアプリ開発時に使うXcodeAndroid Studioのような、統合開発環境はありません。

手に馴染んだエディタと、ブラウザの開発者ツール(デバッグに利用)で開発することになります。

僕はAtomで開発しました。

ES6やReact向けのプラグインを入れて開発しましたが、ネイティブ開発で使えるIDEは優秀なので、IDEがないのは残念です。

今後の統合開発環境の登場に期待しましょう。

ビュー

基本的な書き方

React.JSと同様にJSX(DeNAが開発している言語とは別もの)で書いていきます。

簡単なものだと以下のような感じです。

class MySample extends Component {
    render() {
        return (
            <View style={{backgroundColor: "blue"}}>
                <Text>
                  Hello World!
                </Text>
            </View>
        );
    }
}

スタイルはインライン指定していましたが、分けるのが一般的です。 上記のコードだと下記のような感じになります。

class MySample extends Component {
    render() {
        return (
            <View style={styles.mystyle}>
                <Text>
                  Hello World!
                </Text>
            </View>
        );
    }
}

const styles = StyleSheet.create({
    mystyle: {
        backgroundColor: "blue",
    }
});

こんな感じで書いておくと、React Nativeが用意している標準コンポーネントについては、 Android向けとiOS向けに自動でネイティブコードに展開してくれます。

標準コンポーネントで対応できない場合はどうするの?

ネイティブコードと連結できる仕組みがありますので、 標準で提供していないUIはネイティブコードを書いていくことになります。

iOSでいうUITableViewは標準で提供されていないため、 サードパーティコンポーネントが存在しています。

コードの共通化という点からは外れてしまいますが、最悪はネイティブのコードを書けば何とかなります。

レイアウト

レイアウトはCSS3のflexboxという概念を使って行います。

特に難しいところはないので、下記を読めばすぐに理解できると思います。

初めての人には難解なiOSのAutoLayoutと比べると、とても分かりやすくレイアウトが組めます。

複雑なレイアウトを組もうとすると、ビューの階層が深くなりますが、今のところは目に見えてパフォーマンスの劣化を感じたことはありませんでした。

アニメーション

アニメーションについてのAPIも用意されていて、簡単に使える感じのようですが、 今回は特に使いませんでした。

ドキュメントをさらっと読んだ程度ですが、よほど複雑なアニメーションでない限りは問題なさそうです。

Animations – React Native | A framework for building native apps using React

ライフサイクル

ネイティブアプリを開発していると、嫌でもライフサイクルを意識しながらの開発になりますが、 React Nativeは状態で全てを管理するため、ライフサイクルをほぼ意識せずに開発することが可能です。

これはとても大きな効果があり、開発効率が上がると思います。

React Nativeにもコンポーネントがマウントされたり、レンダリングされたタイミング等の ライフサイクルが一応存在しますが、今回はほとんど使いませんでした。

ライフサイクルを意識しないで開発できる。

これはReact Nativeの大きなメリットの一つです。

コードの共通化

React Nativeの標準コンポーネントを使っていれば、基本的にViewも使いまわせます。 OSらしい感じのUIではなくなりますが、コードの共通化ができるのは大きいと思います。

今回はUIにそこまでこだわらなかったので、8割〜9割ぐらいは共通のコードで書けました。

サードパーティ製のコンポーネントが充実してくれば、個別でコードを書く必要はどんどん少なくなりそうです。

コードを分ける場合は?

一番スマートなのが、iOS用とAndroid用のコンポーネントを作るのがよいかと思いますが、 今回は大元のナビゲーション以外は一つのコンポーネント内で分岐させました。

たとえば、iOSではSFSafariViewを使いたいけど、Androidは内部ブラウザではなく、 標準ブラウザで見せたい時とかです。

良いやり方が見つからなくて、propsに「isAndroid」みたいなのを渡して条件分岐させましたが、 propsのバケツリレーにはしたくないのでもう少しスマートに書きたいところです。

クラスを継承したりすれば、上手くまとまりそうなので、この辺は今後の課題としています。

パフォーマンス

UI面はネイティブのコンポーネントが使われているのでおおよそ問題ないのですが、 レイアウトによっては描画に時間が掛かったりするケースがありました。

あとAndroidについては古い端末だと全体的にもっさりな感は否めないです。 公式のドキュメントにUIパフォーマンスのプロファイリング方法があるので、場合によってはチューニングが必要となるかも知れません。

Profiling Android UI Performance – React Native | A framework for building native apps using React

ReactNativeのバージョンアップで最適化が進めば解消されるかも知れませんが、 現状ではAndroid版のチューニングに多少時間が掛かることは覚悟した方がよいかも知れません。 (今回は試しに作っただけなので、そこまでは手がまわりませんでした。)

ロジック部分はJavaScriptなので、基本的に重い処理には向きませんが、 APISQLite等とやりとりする程度であれば問題ないと思います。

デバッグ

デバッグは基本的にブラウザの開発者ツールを使います。

React Nativeの開発時はローカル環境にJavaScriptを実行するサーバを立ちあげ、 アプリはそのサーバと通信する形で処理を実行します。

そのため、ステップ実行等はブラウザの開発者ツールで行います。

正直なところIDEと比べると使いにくいので、ないよりマシな感じはします。

ただ、Reactの仕組みのおかげか今回作ったアプリのレベルでは、 デバッガーで追いかけないと分からないような不具合にはあたりませんでした。

ロギングはJSでお馴染みのconsole.log()を使うと開発者ツールのコンソールに出力されます。

サードパーティSDKの組み込み

Google Analytics等の有名なSDKは既にモジュールを作ってくれている人がいるので、npmで簡単にインストールできます。

問題は世界的には有名でない日本の広告事業者などのSDKです。

これらを利用するには、ネイティブの処理とブリッジする処理を作ってあげる必要があります。

SDKの数が多いと手間取りそうなので、開発前に考慮しておいた方がよさそうです。

使用リソース

アプリ化時のディスク容量はそれほどでもないのですが、メモリ使用量は多いかも知れません。

まだアプリを1本しか作っていないので、何とも言えないですが、 簡単な構造のアプリの割には最大で200MBぐらいメモリを使用していました。

ある程度はReact Native側で管理してもらえると思いますが、 Objectの参照が残っているとリークの原因になります。

ビルド

基本的にビルドは一度行えば、再ビルドせずにコードの変更をアプリに反映することが可能です。 これはスクリプト言語であるES6の最大のアドバンテージと思います。

iOSAndroidでも差分ビルドは存在しますが、React Nativeで開発する限りはビルド待ちがほぼ発生しないため、 高速に開発を進めることができます。

npmでモジュールを追加した時などは、再ビルドが必要となりますが、 ビルドのストレスからは解放されます。

テスト

今回はテストコードを書かなかったのですが、React.JS同様にJestが使えるようです。 UIテストについては、ネイティブと同様のテストになりそうです。

このあたりは、まだ勉強が必要になりそうでした。

リリース

iOSはAppDelegateで内部のJSバンドルを利用する形に変更し、 あとはXcodeを使って通常の手順でリリースができます。

Running On Device – React Native | A framework for building native apps using React

Androidはリリースビルド用の記述をGradleの設定に追加し、コマンドでリリース用のapkを作成します。

Generating Signed APK – React Native | A framework for building native apps using React

ネイティブアプリの開発経験がないと一番ハマるのがリリースのフェーズかも知れません。

スクリーンショットなど、意外と用意するものも多いので、早めに取り組んでおくと後からバタつかなくてすみます。

React Nativeはアプリ開発者の夢となるか?

今後のコミュニティの盛り上がり次第では、かなり強力なプラットフォームとなりそうです。

現状では凝ったUIにするならネイティブ化が必須になりますが、 そのあたりを吸収してくれるコンポーネントが増えれば、十分に有用なツールになると思えます。

React.JSと同様にnpmで豊富なモジュールを扱えるのも大きいです。

あと、React.JSでWebサイトを作っている場合は、アプリとWebで共通のコードを動かすこともできそうなので積極的に検討してもいいかも知れません。

ただ、銀の弾丸ではないので、今後の戦略や現状のエンジニアリソースと相談しながら導入を検討する必要があります。

今は亡きParse.comのようにFacebookがサジを投げる可能性もゼロではないですが、 Facebookのアプリ自体がReact Nativeなので、そのあたりは心配しなくても大丈夫な気がします。

Reactに依存するのはリスクもありますが、2016年7月現在では使えるレベルになっていますので、個人的には今後が楽しみです。

今回は簡単なアプリを作っただけですが、とても良い印象を受けました。

React自体も触ってみたらとても良い仕組みでしたし、それを使ってクロスプラットフォームのアプリを作れるのは素晴らしいです。

勝手なイメージで車に例えると、React Nativeが市販車、Xmarinがチューンドカー(Xmarinは触ったことないけど)、ネイティブ開発がF1というような印象です。

凝ったUIでなければ簡単にアプリを作れるので、ネイティブ開発者も触っておいて損はないと思います。