アプリエンジニアがのぞいた React Native 〜メドレー TechLunch〜
こんにちは、開発本部の高井です。メドレー開発本部で行われている勉強会「TechLunch」でReact Nativeについて発表しました。
私は普段は Swift、Kotlin/Java を使ってネイティブアプリを開発しており、React Native に触るのは初めてでした。そこで今回は、アプリエンジニアの視点から、実装するための基本的な知識と弊社の実際の開発で使えそうかを検討した結果についてご紹介します。
なぜ React Native を触ってみようと思ったか
オンライン診療アプリ「CLINICS」の開発では、iOS/Android アプリをそれぞれのネイティブ言語で別々に開発しているため、実装やレビューの際にはプラットフォーム間の仕様の違いを理解する必要があり、なかなか大変だと感じていました。
これらの課題に対してこちらのブログでも紹介したような施策を行って改善を行ってきましたが、ソースを共通化することでより開発効率を向上できないかと思い、クロスプラットフォーム開発についても調べてみることにしました。
その中でも以下の理由から、今回は React Native について調べてみることにしました。
- JavaScript(以下 JS)・ React のため、Web エンジニアがネイティブアプリ開発を行う際のハードルを低くすることができそう
- UI の実装にネイティブ UI を使用しているので自然なデザインやインタラクションを作りやすそう
- ある程度リリースから時間が経って情報が豊富にある
特に弊社では、ネイティブアプリより Web 開発をメインに行ってきたエンジニアの方が多く、また Web フロントに React が使われているプロダクトもいくつかあるので、React Native を採用することでチームの開発効率の向上だけでなく、開発本部全体でもネイティブアプリ開発の学習コストが低くなるのではないかと考えました。
そこで、以降ではネイティブアプリエンジニアと Web エンジニアそれぞれにとって、開発しやすいかどうかという観点で React Native の開発方法を見ていきたいと思います。
初期設定について
インストール〜アプリ実行
インストールは公式のGetting Startedにもありますが、以下のコマンドで完了です。
$ brew install node
$ brew install watchman
$ npm install -g react-native-cli
今回、私が触るにあたっては Xcode と Android Studio のシミュレータ(エミュレータ)で実行しながら開発しましたが、React Native は Xcode や Android Studio がインストールされていなくても、Expoというクライアントアプリを実機にインストールすることで画面をプレビューしながら開発することができます。
これなら、Xcode のダウンロードを待つ必要もありません!(iOS エンジニアでもアップグレードのたびに Xcode のダウンロードを待つのはイライラします)
次に、プロジェクト作成、シミュレータでのアプリ実行は以下のコマンドで実行できます。
ただし、シミュレータ実行前に Xcode Command Line Tools のインストールと Android Studio でいくつかの設定(SDK のインストール、AVD の作成、環境変数の設定)が必要です。
# プロジェクト作成
$ react-native init AwesomeProject
# アプリ実行(シミュレータ)
$ cd AwesomeProject
$ react-native run-ios or react-native run-android # Android の場合、emulator を別途起動してからでないと実行できない
実装してみた感想
UI の実装方法
React Native では React 同様 UI の各パーツをコンポーネントと呼び、それらを配置することで UI を実装していきます。違いは Web の HTML の代わりに Native の UI を描画するためのコンポーネントとして使う点です。
見た目やレイアウトは CSS と似たような形式で記述します。React Native で使えるスタイルのプロパティは各コンポーネントで異なりますが、例えば、View コンポーネントに設定できるプロパティには以下のようなものがあります。
Web で使われているものと全く同じというわけではないですが、flex、margin、border などの使い慣れている CSS のプロパティ名で設定できるので、Web エンジニアにとっては実装のハードルが下がるのではないかと思いました。ただ、普段 CSS を触っていないネイティブアプリエンジニアにとっては学習コストがかかると思います。
また一度ビルドすれば、JS による修正内容をビルドなしでシミュレータに反映することができるので、View 周りの調整は効率的にできそうでした。
// js/components/home.js
const renderItem = ({ item, index }) => (
<View style={styles.row}>
<Text style={styles.title}>
{parseInt(index, 10) + 1}
{". "}
{item.title}
</Text>
<Text style={styles.description}>{item.description}</Text>
</View>
);
const styles = StyleSheet.create({
row: {
borderBottomWidth: 1,
borderColor: "#ccc",
padding: 10,
},
title: {
fontSize: 15,
fontWeight: "600",
},
description: {
marginTop: 5,
fontSize: 14,
},
});
ただ、OS ごとにデザインを合わせる方針にしない限りは、コードも別々になるところがわりと多くなりそうだと感じました。
例えば、TabBar(iOS)と DrawerLayout(Android)、DatePicker(iOS)と TimePicker(Android)、ProgressView(iOS)と ProgressBar(Android)などは React Native では別コンポーネントとして提供されていて、API も違っていました。
画面遷移
画面遷移(プッシュ、モーダル、タブ遷移など)のために API として公式で提供されているのは iOS のみで Android は別途、実装するか、サードパーティのライブラリを使用する必要があります。
わたしが使ってみたreact-native-navigationはモーダル、プッシュなどの遷移がネイティブ API ベースで実装されているので、ネイティブ言語で実装した場合と比べて違和感なく実装することができました。
下記のような形でプッシュやモーダル表示での遷移ができます。特定の画面に戻る機能については開発中であったり、機能的な制約は少しありそうです。そういう細かいところはネイティブ言語でやった方が自由が効くので、良いなと思います。
それでも、iOS と Android では複数画面の管理や遷移についての考え方が違い、Android を初めて開発した時に同じことを実現するのが難しかった覚えがあるので、共通の方法で実現できるのは便利でした。特に Web だとあまり画面間の遷移について考えることはないと思うので、共通化されているとネイティブアプリ開発の学習コストが下がると思います。
this.props.navigator.push({
// プッシュ
screen: "example.PushedScreen",
title: "Pushed Screen",
});
this.props.navigator.pop({
// 前の画面に戻る
animated: true,
animationType: "fade",
});
this.props.navigator.showModal({
// モーダル
screen: "example.ModalScreen",
title: "Modal",
animationType: "slide-up",
});
ネットワーク周り
ネットワーク経由でデータを取得して、モデルに変換し、アプリ内で使うというよくある操作を行うには Fetch API を利用します。Fetch APIは JS で提供されている Promise ベースの API です。例えば、以下のような形で JSON を返す API からデータを取得し、receiveHelthNews
関数にオブジェクトに変換した配列を渡すことができます。JS の API なので Web エンジニアにとっては使いやすいのではないかと思います。
ネイティブ言語でそれぞれ実装する場合は、URLSession(iOS)と HttpURLConnection(Android)、あるいは各プラットフォーム向けに提供されているサードパーティのライブラリなどを使うと思いますが、当然、API は異なるのでそれぞれの実装方法を把握しないといけなくなります。それに比べると学習コストは低くなりそうです。
// js/actions/index.js
export function fetchHelthNews() {
return (dispatch) =>
fetch(constructHealthNewsUrl())
.then((response) => response.json())
.then((json) => dispatch(receiveHelthNews(json.articles)))
.catch((error) => {
console.log(error);
});
}
ネイティブアプリ特有の機能について
その他のアプリ開発でよく使うネイティブアプリ特有の機能を実装する方法は以下のようになります。多くの機能がサードパーティのライブラリに依存しているので、各言語のバージョンアップ時の対応が少し心配ではありますが、よく使う機能については実現することができます。
- Push 通知:Android はハンドリングする API が公式で提供されていないのでサードパーティのライブラリを使う
- カメラ、キーチェーンアクセス/ユーザデフォルト:公式の API は提供されていないのでサードパーティのライブラリを使う
- 位置情報の取得:公式 API が提供されている
- ディープリンク:アプリ起動時にハンドリングを行う API は提供されている。ユニバーサルリンクや IntentFilter の設定は各プラットフォームで個別に必要になる
リリースはどうやるか
アーカイブやストア配布についてはネイティブアプリの配布と同じプロセスになります。
各プラットフォームで証明書等の設定を行い、Xcode や Android Studio、あるいは CLI でコマンドを実行して、ipa / apk ファイルを作成し、各 Store にアップロードする必要があります。
CI はBitriseなどが使えます。Bitrise でビルドを試してみましたが、React Native のリポジトリと接続したときにできるデフォルトのワークフローを使えば、同時に 2 プラットフォームのアーカイブが作成できて便利でした。
あと、まだ試せてはいないのですがCodePushを使えば、審査に提出することなしに既存のアプリを変更することもできるらしいので、非常に便利だと思いました。
どんな場合に React Native を採用できそうか?
React Native で開発することで、Web 開発者の視点で見るとプラットフォームのネイティブ言語で開発するよりも、だいぶ学習コストが下がるのではないかと思いました。またサードパーティのライブラリを使えば、機能的に大きな問題となるようなことはなさそうでした。ただ、画面遷移のライブラリがそうだったように、もしやりたいことができないという場合は、妥協しないといけない部分が出てきそうだと思いました。
一方、アプリエンジニアにとっては、慣れるまではかなり開発速度が下がりそうなのでデメリットも大きいかなと思いました。React と JS、また Redux なども新たに理解しつつ開発していたので結構ハードルが高いと感じました。開発環境もビルドが通ってるうちは、View 周りの調整がすぐに確認できて良かったのですが、ランタイムエラーになるなどで、シミュレータがリロードできなくなった場合に再度ビルドし直すということがよく起こり、常に快適に開発できるというわけではありませんでした。
運用面でみると一通りアプリ開発に必要そうなツールは揃っているし(クラッシュ監視、CI、テスト配信、リリース)、Code Push など便利なツールもあるので利点が多いと思いました。
結論としては、Web エンジニアが社内に多かったり、開発チームに React、JS が得意なメンバーがいるなら、実際の開発でも使えるかなと思いました。ただ、アプリエンジニアにとってはかなりストレスがたまるプロジェクトになりそうだと感じました。
まとめ
自分の現状で考えると、アプリは得意だけど JS や React にそこまで詳しくないので、もし直近のプロジェクトで難易度もそこそこ高いようであれば、正直あんまり使いたくないなあという気持ちがあります。ただ、技術の幅を広げるとか、組織全体のポータビリティなどの観点で考えると利点が結構あるのかなと思います。チャンスがあればぜひ、チャレンジしてみたいです。
わたしはどちらかというと技術や開発ツールの新しさよりも、ユーザとの接点のところで新しいことや面白いことを追求したいと思っていますが、開発効率や品質の向上のために最適なものを選択できるように、今後も新しいツールのキャッチアップは積極的に行っていきたいと思っています。
お知らせ
メドレーは、5/31-6/2 に開催される RubyKaigi 2018 に LT スポンサーとして協賛します。ブースも構えておりますので、イベントにお越しになる方は、ぜひブースにも遊びにいらしてください!