Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Our choice in ReactNative

joe_re
May 19, 2017

Our choice in ReactNative

joe_re

May 19, 2017
Tweet

More Decks by joe_re

Other Decks in Technology

Transcript

  1. Our choice in
    ReactNative
    @joe_re

    View full-size slide

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

    View full-size slide

  3. Released Android app using
    React Native

    View full-size slide

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

    View full-size slide

  5. Notice
    • 今回作ったアプリはAndroid向けなので、

    基本的には Androidの話です
    • JS LayerにはなるべくAndroidでしか動かない
    コードは書かないようにしていますが、

    クロスプラットフォームの話はしません

    View full-size slide

  6. まずどういうものかDEMO

    View full-size slide

  7. How was ReactNative?

    View full-size slide

  8. プロジェクト概要
    • 開発期間: 3ヶ⽉月
    • 開発メンバー:2名

    - Webフロントメインなエンジニア1名

    - インターン1名
    • モバイルエンジニアは開発メンバーには

    いない

    View full-size slide

  9. Q: ReactNativeでは

    Webフロントの知⾒見見だけで

    Nativeアプリケーションが

    作れるのか

    View full-size slide

  10. Q: ReactNativeでは

    Webフロントの知⾒見見だけで

    Nativeアプリケーションが

    作れるのか

    View full-size slide

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

    View full-size slide

  12. Q: ReactNativeを

    採⽤用して効果的だったか

    View full-size slide

  13. Q: ReactNativeを

    採⽤用して効果的だったか

    View full-size slide

  14. 今回の開発体制、

    状況的には正解だったと思う
    • 開発メンバーにモバイルエンジニアがいない中で、

    使い慣れたReactでフロントが構築できるのは

    ⾮非常に効率的だった
    • 社内にはモバイルエンジニアがいるので、

    モバイルについていつでも質問はできる環境があった
    • 補⾜足として、Javaはチョット書けたし、

    モバイルもまぁ書いたことがないわけではなかった

    View full-size slide

  15. Using NativeLayer’s assets

    View full-size slide

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

    View full-size slide

  17. Android SDKはNFCタグの

    操作を提供している
    https://developer.android.com/reference/android/nfc/package-
    summary.html

    View full-size slide

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

    作成したNativeModuleのAPIを呼び出す

    View full-size slide

  19. 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);
    }

    View full-size slide

  20. 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);
    }
    }

    View full-size slide

  21. 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();
    }
    // …
    }

    View full-size slide

  22. これだけで簡単に

    Android SDKの機能を

    JSから利利⽤用できる

    View full-size slide

  23. Architecture of JS Layer

    View full-size slide

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

    View full-size slide

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

    アクションの発⾏行行を⾃自動化してくれる

    View full-size slide

  26. 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される

    View full-size slide

  27. Nativeアプリケーションと
    ReduxStateとの相性は良い
    • ReduxStateに画⾯面上の表示の元となっている箇所を全てを押
    し込めることで、画⾯面の再構成がいつでも⾏行行えるようになる
    • モバイルでは、Webよりもエラー復復旧のために

    アプリケーションレイヤーで保持しておかなくてはいけない
    情報は多い(Navigationのスタックなど)
    • 画⾯面が狭いので、エラー表示⽅方法や復復旧⽅方法も異異なる

    (ネットワークエラー発⽣生時には、画⾯面全体をエラーページ
    にする→再読み込みボタンで成功すれば画⾯面を戻す、など)

    View full-size slide

  28. Routerには
    react-native-router-fluxを選択
    • Reduxサポートが厚いので選択
    • いい感じに使えて特に不不満はなかった
    • けど内部で使っていたNavigationExperimentalが
    [email protected]からdeplicatedになってしまった
    • 今なら公式のreact-navigationがおすすめ

    (個⼈人的に使っている感じでは、違和感もないし、

    Reduxも普通に使える)

    View full-size slide

  29. HOCの活⽤用
    • 以下の処理理はHOCで共通化
    • ログイン必須ページのログイン要求
    • flex-boxだけでは対応の

    難しい画⾯面のリサイズ

    (リストビューの横幅の再計算とか)
    • Indicatorの表示
    • SnackbarなどのNotification表示
    • etc…

    View full-size slide

  30. 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 (

    );
    }
    };

    View full-size slide

  31. Crash reporting
    • 社内で実績があったCrashlyticsを導⼊入
    • ReactNativeでも導⼊入は簡単

    (ReactNative向けにreact-native-fabricという
    npmが提供されている)
    • モバイルはユーザ環境によって

    予想外のエラーが起きることが多いので、

    できればリリース前に⼊入れておくのが良い

    View full-size slide

  32. 不不要な権限は削ろう(Android)
    • 初期状態では以下の権限が要求される

    - USBストレージの読み取り

    - 端末情報とIDの読み取り

    - 他のアプリの上に重ねて表示
    • USBストレージの読み取りはAsyncStorageを使うために必要だ
    けど、他の権限は今回のアプリでは不不要
    • これらの権限は実はデバッグツールのために要求されているので、
    不不要であればリリースバージョンで取り除くようにmanifestを

    書くのが良い

    View full-size slide

  33. app/src/release/
    AndroidManifest.xml
    • Androidのgradleスクリプトでは

    ディレクトリの規約によりリリース時の
    Manifestを選択できる
    xmlns:tools="http://schemas.android.com/tools"
    package="jp.co.freee.nfc">
    tools:node="remove" />
    tools:node="remove" />

    View full-size slide

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

    (会社に法務がいる場合は相談しよう)

    View full-size slide

  35. AsyncStorageREPL
    (おまけ)

    View full-size slide

  36. Access AsyncStorage from
    Node REPL
    • 開発中気軽にAsyncStorageの中身を⾒見見たり、

    変更更したりできないのが不不満だった
    • NodeのREPLからアプリケーションの
    AyncStorageにアクセスしたかった

    (rails consoleみたいなイメージ)

    View full-size slide

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

    View full-size slide

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


    View full-size slide

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

    View full-size slide

  40. React Native is fun

    View full-size slide

  41. Thank you for your
    attention!

    View full-size slide