React Nativeを用いた初めてのiOSアプリ開発 : 選んだ理由と、開発で学んだこと

候補としてモバイルアプリの作成について話し合いを始めた時、何を用いてモバイルアプリを構築するかについて、私たちには何の考えもありませんでした。クールな仕様で、楽しく使え、さらには洗練されたものでありたいという一般的な方向性は分かっていたのですが、誰もモバイルアプリを構築した経験がなかったのです。

そこで私たちはReact Nativeを使ってみることにしました。選んでみて良かったと思っています。この記事では、React Nativeを使うと決めた時に考えたことや、構築途中で学んだことを書き綴っています。

React Nativeを選んだ理由

私たちはWeb開発者であって、iOS開発者ではありません。ニューヨークでの集まりで、Swiftがどれだけ性能がいいか、それでいてObjective-Cもまだ存在価値があるということを、少しかじった程度で、一番得意なのはRubyとJavascriptです。私たちのチームは2015年の初頭、FacebookのReactを利用するところから始めました。Reactに対する最初の印象はとてもポジティブなものでした。React Nativeが登場した時、(デバイスをまたがるプラットフォームは問題を起こしがちですから)私たちは当初懐疑的でした。しかし、知れば知るほど、React Nativeの虜になっていったのです。その最たる理由が以下になります。

1. 一度覚えると、どこでも書ける。クロスデバイスのプラットフォームは一般的に使えないことが多いものです。通常、最小限のニーズを満たし、結果は常に最善の策とは言えません。React Nativeは同じReact.jsのフレームワークを使いますが、Androidのためにコードを書くのとiOSのために書くのとでは、共有するコードが多少あったとしても、違うプロジェクトになります。つまりそれぞれのデバイスのコードはまったくのネイティブコンポーネント(驚きましたね!)を使って、そのデバイスのためだけに書かれるということです。


1.宣言型のビュー。私たちはReactの宣言型ビューにも惚れ込んでいました。WebでReact Nativeを利用したときに、iOSの開発で宣言型ビューができるというのは、コードが予測でき、バグが減らせるという意味で大きなプラス要素でした。
https://en.wikipedia.org/wiki/Reactive_programming

2.モバイルのためのFlexbox。制約ソルバがどのようにiOSで機能するのか、よく分かりませんでしたし、そのまま進めていきたいという確証もありませんでした。最近では、ほぼのブラウザでサポートされ、レイアウトを直観的なものにするFlexboxがReact Nativeで使えたのはラッキーでした(あくまで私見です)。
https://css-tricks.com/snippets/css/a-guide-to-flexbox/

ios constraint
iOSの制約

flexbox
Flexbox

1.Javascript。これは私たちが知らない(Objective-CとSwiftの)カテゴリに分類されます。分かり切ったことですが、もう1つの言語を学ぶ必要がないというのは、開発時間を大幅に削減してくれます。またReact Nativeが最初からサポートしているES6を使ってみたら、とても興奮しました。私たちはCoffeeScriptのヘビーユーザだったので、ES6に移行することは簡単だったのです。https://robots.thoughtbot.com/replace-coffeescript-with-es6

React Nativeを使う上での懸念

React Nativeを使えば、開発時間が短いというメリットはあっても、React Nativeコンポーネントのカスタマイズ性の低さと、依存性から、後にそれが相殺されることになると分かっていました。下記に述べるのが、React Nativeを使うことをためらっていた理由です。

1.React Nativeエコシステムに制限される。私たちが初めてReact Nativeを目にしたのは、2015年9月のことでした。すでに多くのiOSのネイティブ要素が実装され、開発途中であるのを見ました。しかしながら、まだ私たちが必要とする特定のコンポーネントがReact Nativeで使えないということに不安があったのです。その後、特定のSDK(AWSとMixpanel)のための独自のReact Nativeを構築すればいいということが分かりました。

2.試作段階React Nativeの更新は早く、その前に構築したコードが(まれですが)使えなくなる場合があります。開発中に何度か、この事態を経験しました。そこで影響をできる限り軽減するため、新機能が必要な時だけ意図的にアップグレードし、そのあとしっかりテストをしました。

3. Google検索で見つけられない。新しいシステムのコードを書いていると、かつて誰も経験したことの無いエラーに遭遇することがあります。RubyやRailsの場合に比べて、「Google検索で見つけられない」問題の数は相当に多く、解決方法を見つけるのにはかなりの忍耐を要しました。ドキュメントを参照し、ソースコードを(古き良き時代のように)探らなくてはなりませんでした。しかしReact Nativeチームとそのエコシステムの功績は大きく、予期せぬ挙動に対処するための定期的なアップデートをリリースしてくれました。

React Nativeパッケージ

ReactNativeのコンポーネントサポートは非常に優れていて、ActivityIndicator(スピナー)から、アラートスライダまで全てがJavascriptからシームレスに機能しました。Objective-CやSwiftの知識が無くても、ネイティブのiOSアプリを苦労なく開発できたという点について、強調してもし過ぎることはありません。その上、毎日新しいパッケージがnpm経由で入手できるようになっていました。以下にお気に入りをランダムにリストします。

  • react-native-simple-store
    https://www.npmjs.com/package/react-native-simple-store 当初私たちはAsyncStorageを使っていましたが、同じ関数の保存と取得を何度も構築するのが面倒でした。Simple StoreはAsyncStorage上に構築できる素晴らしいソリューションで、シンプルにストレージにアクセスすることができます。
Store.get('user').then((user)=> {
  // some code
}).catch((error) => {
  console.warn(error)
}).done()
  • React-native-vector-icons
    https://www.npmjs.com/package/react-native-vector-icons 私たちが見つけた中で最高のベクターアイコンパッケージです。FontAwesomeとEvilIconsを組み合わせましたが全く問題なく使えました。このパッケージからMaterialIcons、IonIconなどが入手可能です。
<Icon name='trophy' />
<EvilIcon name='check' />
  • tcomb-form-native
    https://github.com/gcanti/tcomb-form-native このパッケージを使うとフォーム作成が非常に簡単になります。通常の入力コンポーネントと同様に、カスタムの入力タイプやキーボード、オートコレクトなどが定義できます。
var Person = t.struct({
  name: t.String,              // a required string
  surname: t.maybe(t.String),  // an optional string
  age: t.Number,               // a required number
  rememberMe: t.Boolean        // a boolean
});
Actions.dashboard()

奇妙な挙動

Web開発の世界から来た私たちにとっては頭を抱えてしまうような難題にもいくつか突き当りました。下記がその例です。

  • スタイリング RNでスタイルシートは作成できたのですが、カスケード処理ができないせいでスタイル定義がおかしなことになりました。この問題はインラインをオーバーライドしていくつかのレベルに分けてスタイル定義をすることで解決しました。

Styles.js

module.exports = StyleSheet.create({
  title: {
    fontSize: 23,
    textAlign: 'center',
    color: blueText,
    fontFamily: 'Avenir',
    fontWeight: '700',
  },
  header: {
    padding: 20,
    paddingTop: 30,
    backgroundColor: '#fff',
    borderBottomWidth: 1,
    borderBottomColor: '#ccc',
  },
})

Component.js

...
<Text style={[Styles.header, {color: 'white'}]}>
  Some text
</Text>
...

標準スタイルは次のようになります。

style={Styles.header}

カスタムインラインスタイルは次のようになります。

style={{color: 'white'}}

2つをマージすると次のようになります。

style={[Styles.header, {color: 'white'}]}

ハックっぽくってあまりよろしくないですね。恐らく他にいい方法があるのでしょうが、この時点では思いつきませんでした。

  • 循環のrequireとナビゲーション

これは絶対やめてください(リカーシブである再帰を除いて、循環は良くありません)。NavigatorIOSを使っていると偶然起きてしまう可能性があります。Webのルーティングはシングルステージで、自分の現在やその前の位置が分かっています。そんなところですよね。iOSでは、ビューはプッシュされ、スタックにポップされます。以前プッシュされたコンポーネントをプッシュしようとすると、エラーになります。単純にコンポーネントをrequireしようとしてカレントコンポーネントをプッシュすると、循環参照され破損してしまうかもしれません。react-native-router-fluxを使ってこの問題は解決し、更にスケーラブルな方法でルートを推論することができました。

全体について

React Nativeはモバイルアプリを構築する素晴らしい方法です。SwiftやObjective- Cの知識が無いので、直接比較することはできませんが、とても有意義な経験でした。RNにはきめ細やかさは無いかもしれませんが、真のネイティブアプリを構築できるというメリットがあります。初めてのモバイルアプリを作成するのに、RNを使って良かったと思っています。React Nativeは進化を続けています。私たちのような小さい開発チームにとって、さっとWebからモバイルへと切り替えられるのはすごいことです。

今後、いくつか記事を投稿して、下記の問題をどのように解決したか詳細を書いてみようと思っています。

  • ログインと認証
  • APIとコールバック
  • RNBridgeを使ったiOS SDK

アップデート

私たちのアプリがApp Storeからダウンロード可能です。

https://itunes.apple.com/us/app/id1056320926

unnamed
https://www.linkedin.com/in/tom-tang-65579616