Slide 1

Slide 1 text

Our choice in ReactNative @joe_re

Slide 2

Slide 2 text

Who am I? • twitter: @joe_re • github: @joe-re • working in freee K.K

Slide 3

Slide 3 text

Released Android app using React Native

Slide 4

Slide 4 text

Today’s Topics • How was ReactNative? • Using NativeLayer’s assets • Architecture of JS Layer • For Release

Slide 5

Slide 5 text

Notice • 今回作ったアプリはAndroid向けなので、
 基本的には Androidの話です • JS LayerにはなるべくAndroidでしか動かない コードは書かないようにしていますが、
 クロスプラットフォームの話はしません

Slide 6

Slide 6 text

まずどういうものかDEMO

Slide 7

Slide 7 text

How was ReactNative?

Slide 8

Slide 8 text

プロジェクト概要 • 開発期間: 3ヶ⽉月 • 開発メンバー:2名
 - Webフロントメインなエンジニア1名
 - インターン1名 • モバイルエンジニアは開発メンバーには
 いない

Slide 9

Slide 9 text

Q: ReactNativeでは
 Webフロントの知⾒見見だけで
 Nativeアプリケーションが
 作れるのか

Slide 10

Slide 10 text

Q: ReactNativeでは
 Webフロントの知⾒見見だけで
 Nativeアプリケーションが
 作れるのか

Slide 11

Slide 11 text

やっぱりNativeの知識は必要 • Nativeの資産を⽣生かしたい場⾯面では NativeLayerを書く必要がある • UIコンポーネントもSDKに提供されているも のを使うので、ある程度知識があるとハマり どころは回避しやすい • その他ビルドスクリプトの微調整など

Slide 12

Slide 12 text

Q: ReactNativeを
 採⽤用して効果的だったか

Slide 13

Slide 13 text

Q: ReactNativeを
 採⽤用して効果的だったか

Slide 14

Slide 14 text

今回の開発体制、
 状況的には正解だったと思う • 開発メンバーにモバイルエンジニアがいない中で、
 使い慣れたReactでフロントが構築できるのは
 ⾮非常に効率的だった • 社内にはモバイルエンジニアがいるので、
 モバイルについていつでも質問はできる環境があった • 補⾜足として、Javaはチョット書けたし、
 モバイルもまぁ書いたことがないわけではなかった

Slide 15

Slide 15 text

Using NativeLayer’s assets

Slide 16

Slide 16 text

提供している機能をざっくり • NFCタグを読み取り使⽤用履履歴に変換 • 使⽤用履履歴を元に経費申請する • その他Webとの連携 Native Layer JS Layer

Slide 17

Slide 17 text

Android SDKはNFCタグの
 操作を提供している https://developer.android.com/reference/android/nfc/package- summary.html

Slide 18

Slide 18 text

Android SDKの NfcAdapterを利利⽤用するには • Android SDKの提供するAPIを利利⽤用できるよう にするために、NfcAdapterの機能をラップし たNativeModuleを作成する • Reactのライフサイクルに合わせて、
 作成したNativeModuleのAPIを呼び出す

Slide 19

Slide 19 text

Wrap NFCAdapter @ReactMethod QVCMJDWPJETUBSU3FBEJOH/GD \ /GD"EBQUFSOGD"EBQUFS /GD"EBQUFSHFU%FGBVMU"EBQUFS SFBDU$POUFYUHFU"QQMJDBUJPO$POUFYU "DUJWJUZBDUJWJUZSFBDU$POUFYUHFU$VSSFOU"DUJWJUZ JG OGD"EBQUFSOVMMccBDUJWJUZOVMM \ SFUVSO ^ OGD"EBQUFSFOBCMF3FBEFS.PEF BDUJWJUZ OFX$VTUPN3FBEFS$BMMCBDL SFBDU$POUFYU '-"(@3&"%&3@/'$@' OVMM ^ @ReactMethod public void endReadingNfc() { NfcAdapter nfcAdapter = NfcAdapter.getDefaultAdapter(reactContext.getApplicationContext());; Activity activity = reactContext.getCurrentActivity(); if (nfcAdapter == null || activity == null) { return; } nfcAdapter.disableReaderMode(activity); }

Slide 20

Slide 20 text

Send to JS Layer class CustomReaderCallback implements ReaderCallback { ReactContext reactContext; public CustomReaderCallback(ReactContext reactContext) { this.reactContext = reactContext; } @Override public void onTagDiscovered(Tag tag) { try { analizeTag(tag); } catch (IOException e) { Crashlytics.logException(e); } } private void analizeTag(Tag tag) throws IOException { FelicaReader reader = new FelicaReader(tag); //… 解析処理理 … sendEvent(reactContext, “READ_CARD", payload); } private void sendEvent(ReactContext reactContext, String eventName, @Nullable WritableMap params) { reactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class) .emit(eventName, params); } }

Slide 21

Slide 21 text

ReactNative Side import { NativeModules, DeviceEventEmitter } from ‘react-native'; class ReadingCardPage extends React.Component { // … componentDidMount() { NativeModules.NFCReactModule.startReadingNfc(); DeviceEventEmitter.addListener('READ_CARD', this._handleReadCard); } componentWillUnmount() { DeviceEventEmitter.removeListener('READ_CARD', this._handleReadCard); NativeModules.NFCReactModule.endReadingNfc(); } // … }

Slide 22

Slide 22 text

これだけで簡単に
 Android SDKの機能を
 JSから利利⽤用できる

Slide 23

Slide 23 text

Architecture of JS Layer

Slide 24

Slide 24 text

Using Redux • Middleware • redux-thunk • redux-promise-middleware • redux-logger

Slide 25

Slide 25 text

redux-promise-middlewareを 選択した理理由 • middlewareの層に副作⽤用を押し付けるアプローチはなるべく取ら ない⽅方針(多少個⼈人的な趣向が⼊入ってはいる) • ⾮非同期処理理が⼊入るところで、どうしても時間軸を気にしなくては ならないアクションの発⾏行行だけmiddlewareでどうにかしたかった • ⼤大抵の⾮非同期処理理を伴うアクションは、処理理の開始、成功、失敗 の3種類類さえあれば⼗十分 = これらはPromiseのstatusにそのまま対 応している • redux-promise-middlewareはPromiseの状態に従って、
 アクションの発⾏行行を⾃自動化してくれる

Slide 26

Slide 26 text

redux-promise-middleware // action creator const getPost = id => ({ type: 'GET_POST',\ payload: new Promise(resolve => { setTimeout(() => fetch(`/api/posts/${id}`).then(response => { resolve(response.json()); }), 1000); }) }); // reducer const reducer = (state = {}, action) => { switch (action.type) { case 'GET_POST_PENDING': return { isPending: true }; case 'GET_POST_FULFILLED': return { body: action.payload.body }; default: return state; }; } payloadにpromiseを渡す promiseのstatusの遷移に従い
 actionが⾃自動でdispatchされる

Slide 27

Slide 27 text

Nativeアプリケーションと ReduxStateとの相性は良い • ReduxStateに画⾯面上の表示の元となっている箇所を全てを押 し込めることで、画⾯面の再構成がいつでも⾏行行えるようになる • モバイルでは、Webよりもエラー復復旧のために
 アプリケーションレイヤーで保持しておかなくてはいけない 情報は多い(Navigationのスタックなど) • 画⾯面が狭いので、エラー表示⽅方法や復復旧⽅方法も異異なる
 (ネットワークエラー発⽣生時には、画⾯面全体をエラーページ にする→再読み込みボタンで成功すれば画⾯面を戻す、など)

Slide 28

Slide 28 text

Routerには react-native-router-fluxを選択 • Reduxサポートが厚いので選択 • いい感じに使えて特に不不満はなかった • けど内部で使っていたNavigationExperimentalが [email protected]からdeplicatedになってしまった • 今なら公式のreact-navigationがおすすめ
 (個⼈人的に使っている感じでは、違和感もないし、
 Reduxも普通に使える)

Slide 29

Slide 29 text

HOCの活⽤用 • 以下の処理理はHOCで共通化 • ログイン必須ページのログイン要求 • flex-boxだけでは対応の
 難しい画⾯面のリサイズ
 (リストビューの横幅の再計算とか) • Indicatorの表示 • SnackbarなどのNotification表示 • etc…

Slide 30

Slide 30 text

Example of HOC // for typed hoc pattern: https://github.com/facebook/flow/issues/2521 type FunctionComponent

= (props: P, context: S) => ?React$Element; type ClassComponent = Class>; type Props = { snackbarMessage: SnackbarMessage, actions: typeof Actions }; export default function ShowSnackbar( WrappedComponent: ClassComponent|FunctionComponent

): ClassComponent { return class _ShowSnackbar extends Component { props: P & Props; state: {}; componentWillReceiveProps(nextProps: Props) { if (this.props.snackbarMessage !== nextProps.snackbarMessage) { this.showSnackbar(nextProps.snackbarMessage); } } showSnackbar(snackbarMessage: SnackbarMessage) { // 表示処理理 } render() { return ( ); } };

Slide 31

Slide 31 text

For Release

Slide 32

Slide 32 text

Crash reporting • 社内で実績があったCrashlyticsを導⼊入 • ReactNativeでも導⼊入は簡単
 (ReactNative向けにreact-native-fabricという npmが提供されている) • モバイルはユーザ環境によって
 予想外のエラーが起きることが多いので、
 できればリリース前に⼊入れておくのが良い

Slide 33

Slide 33 text

不不要な権限は削ろう(Android) • 初期状態では以下の権限が要求される
 - USBストレージの読み取り
 - 端末情報とIDの読み取り
 - 他のアプリの上に重ねて表示 • USBストレージの読み取りはAsyncStorageを使うために必要だ けど、他の権限は今回のアプリでは不不要 • これらの権限は実はデバッグツールのために要求されているので、 不不要であればリリースバージョンで取り除くようにmanifestを
 書くのが良い

Slide 34

Slide 34 text

app/src/release/ AndroidManifest.xml • Androidのgradleスクリプトでは
 ディレクトリの規約によりリリース時の Manifestを選択できる

Slide 35

Slide 35 text

Yarnを利利⽤用してLicense表記の 雛形を作る • yarnにはlicensesコマンドがあり、package.jsonの依存定義 からLicense表記を⽣生成するコマンドがある • ReactNativeでは基本的にnpmでpackage管理理をするため、 このコマンドをLisense表記の雛形を作るために使うと便便利利 • ライセンス表記は⼊入れなきゃいけないもの、⼊入れなくても 良いものの判断は別途しないといけないので、あくまで雛 形として使いましょう
 (会社に法務がいる場合は相談しよう)

Slide 36

Slide 36 text

AsyncStorageREPL (おまけ)

Slide 37

Slide 37 text

Access AsyncStorage from Node REPL • 開発中気軽にAsyncStorageの中身を⾒見見たり、
 変更更したりできないのが不不満だった • NodeのREPLからアプリケーションの AyncStorageにアクセスしたかった
 (rails consoleみたいなイメージ)

Slide 38

Slide 38 text

作った • https://github.com/joe-re/async-storage-repl

Slide 39

Slide 39 text

DEMO

Slide 40

Slide 40 text

興味があれば ぜひ使ってみてください


Slide 41

Slide 41 text

GraphQLのmeetupやります! https://www.meetup.com/ja-JP/GraphQL-Tokyo/events/239924595/ 5/30(⽕火) 20:00〜22:00

Slide 42

Slide 42 text

React Native is fun

Slide 43

Slide 43 text

Thank you for your attention!