【React Native】 Expoを使えば審査なしにアプリ更新出来てウハウハなのか？

# Expoとは
ExpoはReact Nativeアプリの開発を支援してくれるサービスです。

https://expo.io/

ビルドや実行環境が提供され、リリース後のアプリでも**Apple審査なしに変更がリアルタイムに反映**され、Webのような感覚で開発ができるのが大きな特徴です。

リリース後にアプリ挙動を外部で変更することを嫌っている Apple社がこれを許している理屈はよくわからないのですが、とにかく現状、問題視されていないのは事実のようです。

もし、今後、問題視されるようになったとしても、クリーンな React Native アプリとの互換性は１００％に近いので移行も容易ではないかと思います。恐れずに使って、メリットを享受するというのも一つの考えかと思います。

ちなみに本文にありますが、若干、Expo対応のコードが必要だったりするようです。ネイティブライブラリの制限もある（どういうことが制限となるのか、自分はよく分かってません）ようですので、その辺りを許容できるかが、採用のポイントかなと思います。

# 開発環境構築
## Expo-CLIのインストール
Expoのコマンド群をグローバルにインストールします。

```
$ npm install expo-cli --g
```

# アプリ作成
# プロジェクト作成
Expoのプロジェクトを作成します。

```
$ expo init [プロジェクト名]
```

# テンプレートの選択
blank と tabs が選べる。ここではblankを選択。
```
? Choose a template: expo-template-blank
```

# Yarn を使う？
npm ではなくYarnを使うかどうか聞かれてると思う。ここではNoを選択。
```
? Yarn v1.7.0 found. Use Yarn to install dependencies? No
```

```
$ expo start
```
次のようなコマンドライン表示と、 Metro Bundler (Webページ）が起動します。
![スクリーンショット 2019-01-17 19.07.53.png](https://qiita-image-store.s3.amazonaws.com/0/22218/b292b49a-b581-ed38-f8e3-9828ba48971c.png)


「 Press a for Android emulator, or i for iOS simulator.」とあり、「a」押下でAndroidエミュレータ、「i」押下でiPhoneエミュレータでの確認ができます。

# iOS
<img width="375" alt="ios.png" src="https://qiita-image-store.s3.amazonaws.com/0/22218/9211ce44-e337-30c6-01ea-9a7ad6ff3d59.png">

# Android
<img width="375" alt="android.png" src="https://qiita-image-store.s3.amazonaws.com/0/22218/0ccb7b30-fc50-5553-7ffa-5f7b9bf2dce7.png">

# NativeBase、React Navigation を使ってみる
それではアプリ作成をイメージしながら下記で行なったようにNativeBase、React Navigation を使用してみます。
[【React Native】NativeBase導入](https://qiita.com/keneo/items/d3a36d973c0b89829aa9)
[【React Native】React Navigation を使ってみる（画面遷移編）](https://qiita.com/keneo/items/b62ddcab0e35ce792b67)

上記を参考にインストールしたところ、まず、

```
$ react-native link
```
はエラーが出ますが、そもそも、この手順は、Expoの場合は必要ないようです。

更に「expo start」すると、
```
 Unable to resolve "@expo/vector-icons/FontAwesome5" from "node_modules/native-base/dist/src/basic/IconNB.js"
```
というエラーとなりました。

調べてみたところ、Expo-CLI は [Create React Native App](https://github.com/react-community/create-react-native-app) をベースにしていて、ちょっと違う手順となるようです。

参考：
https://github.com/GeekyAnts/NativeBase#4-getting-started

以下のインストールを別途行ったところ、iOSエミュレータで「[【React Native】React Navigation を使ってみる（画面遷移編）](https://qiita.com/keneo/items/b62ddcab0e35ce792b67) 」と同様の表示、動作が確認できました。

```
npm install @expo/vector-icons --save
```

## Androidでの問題
iOS では動作が確認できたのですが、Android ではまだ問題が残っていました。

Androidエミュレータ起動すると、
```
fontFamily 'Roboto_medium' is not a system font and has not been loaded through Exponent.Font.loadAsync.
```
というエラーとなりました。

[NativeBaseでのRoboto_mediumフォントの読み込みに関するErrorについて](https://qiita.com/yusuke1111/items/c9d11a2a6cc1cefae728)
を参考に（カスタムフォントがロードされるまでは表示をしないという対処でしょうか）、下記のソース

### App.js
```js
import React, {Component} from 'react';
import { createStackNavigator, createAppContainer } from 'react-navigation'

import Main from './screens/Main'
import Push from './screens/Push'
import Modal from './screens/Modal'

const MainNavigation = createStackNavigator(
  {
    Main: { screen: Main },
    Push: { screen: Push },
  },
  {initialRouteName: 'Main', headerMode: 'none'}
)
const NestNavigation = createStackNavigator(
  {
    MainNavigation: { screen: MainNavigation },
    Modal: { screen: Modal },
  },
  {initialRouteName: 'MainNavigation', mode: 'modal', headerMode: 'none'},
)
const AppContainer = createAppContainer(NestNavigation);

type Props = {};
export default class App extends Component<Props> {
  constructor() {
    super();
    this.state = {
      isReady: false
    };
  }

  componentWillMount() {
    this.loadFonts();
  }

  async loadFonts() {
    await Expo.Font.loadAsync({
      Roboto: require("./node_modules/native-base/Fonts/Roboto.ttf"),
      Roboto_medium: require("./node_modules/native-base/Fonts/Roboto_medium.ttf"),
    });
    this.setState({ isReady: true });
  }

  render() {
    if (!this.state.isReady) {
      return <Expo.AppLoading />;
    }

    return (
      <AppContainer
        ref = {nav => {this.navigator = nav;}}
      />
    );
  }
}
```

更にナビゲーションバーがステータスバーに重なってしまう問題もあり、app.json に以下の設定の追加が必要でした。

### app.json
```json
    "androidStatusBarColor": "#334393",
    "androidStatusBar": {
      "barStyle": "light-content",
      "backgroundColor": "#334393"  }
    }
```
参考：
https://github.com/expo/expo/issues/71

# リポジトリ
本記事で作成したものは以下で公開していますので、参考にしてください。
https://github.com/k-neo/ReactNativeCourseExpo

# 最後に
本記事は[ローラハウス](http://laurahouse.net) が執筆している React Native の記事を集約した[【全てのアプリ開発者に贈る】React Native いろいろ触ってみた【目次】](https://qiita.com/keneo/items/3c093c7afde03e5b4d08) の子記事です。React Native の開発で参考になる情報がきっとありますので、ぜひ他の記事も読んでみてください！