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

最近のNative Modules開発について

最近のNative Modules開発について

Tech Stand #1 React Nativeでの発表資料
https://standfm.connpass.com/event/184223/

Satoshi Ohki

August 21, 2020
Tweet

More Decks by Satoshi Ohki

Other Decks in Programming

Transcript

  1. © - BASE, Inc. 最近のNative Modules開発に ついて / / TECH

    STAND # React Native ⼤⽊ 聡 (@roothybrid )
  2. ⾃⼰紹介 • ⼤⽊ 聡 • GitHub/Twitter: @roothybrid • BASE, Inc. •

    Product Dev Division Native Application > Tech Lead • iOSアプリ開発 etc. • React Native歴 1年くらい © - BASE, Inc.
  3. © - BASE, Inc. Native Modulesとは? iOSやAndroidなどのプラットフォームAPIにアクセスできる、React Native モジュール (例:

    MapView、Calendar、Keychainなど) 引⽤: React Native's New Architecture - Parashuram N - React Conf https://reactjs.org/blog/ / / /react-conf-recap.html
  4. © - BASE, Inc. React Nativeのセットアップ改善(>=v . ) • Native

    ModulesのAutolinking • ⼿順書でコマンドを記述する⼿間が減る) • RNプロジェクトの設定ファイル(react-native.config.js) • 設定を宣⾔できる(⼿順書でコマンド記述する⼿間) • プラットフォーム毎に違うライブラリを使うため⽚⽅をopt-out
  5. © - BASE, Inc. Native Modules開発の⽅針 • できる限り標準で推奨している⽅法で開発 開発環境のセットアップは、Bob(@react-native-community/bob) を使う

    https://reactnative.dev/docs/native-modules-setup ライブラリ開発環境の雛形が出来上がる。 npx @react-native-community/bob create react-native-awesome-module yarn bootstrap
  6. © - BASE, Inc. Bob • ライブラリを実装してすぐに動かせるexampleのReact Nativeアプリ環境が⼿に⼊る • JavaScript/TypeScriptどちらでも使えるようにあらかじ

    め設定されている • ビルドのための設定はあらかじめされている • あとはコードを実装するのみ
  7. © - BASE, Inc. Native Modules開発の⽅針 • 現在のアーキテクチャーのI/Fを知る React Native

    Bridge Native Modules Helpers Objective-c Java 最低限必要な実装 React NativeのNativeModules経由で 使えるようになる
  8. © - BASE, Inc. Native Modules開発の⽅針 • 現在のアーキテクチャーのI/Fを知る React Native

    Bridge Native Modules Helpers Objective-c Java 使いやすくするための追加実装 JS/TSからそのままだと扱いづらいので、 Native Modulesの型定義を定義したり、 Native Modulesの機能をベースに さらに便利な機能を提供したりする ライブラリとして公開する時、実装したNativeModuleをそのまま使うことはほぼない。 特にTypeScriptで実装する場合、Product Codeから呼び出すための型定義やヘルパー関数を⽤意する。
  9. © - BASE, Inc. SwiftでNative Moduleを実装した // Keychain.swift @objc(KeychainQ) class

    KeychainQ: NSObject { @objc func constantsToExport() -> [AnyHashable: Any]! { return constants.reduce(into: [AnyHashable: Any]()) { result, item in result[item.key.rawValue] = item.value } } @objc func fetchSupportedBiometryType(_ resolver: RCTPromiseResolveBlock, rejecter: RCTPromiseRejectBlock) { resolver(supportedBiometryType()) } } • Native ModuleクラスをSwiftで定義 • @objcを使って、クラスとメソッドをObjective-C Runtimeにエクスポート Native Modules https://reactnative.dev/docs/native-modules-ios
  10. © - BASE, Inc. // Keychain.m #import <React/RCTBridgeModule.h> @interface RCT_EXTERN_MODULE(KeychainQ,

    NSObject) RCT_EXTERN_METHOD(fetchSupportedBiometryType:(nonnull RCTPromiseResolveBlock)resolver rejecter:(nonnull RCTPromiseRejectBlock)rejecter) @end • React Native BridgeにNative Moduleを登録 // Keychain.swift @objc(KeychainQ) class KeychainQ: NSObject { @objc func constantsToExport() -> [AnyHashable: Any]! { return constants.reduce(into: [AnyHashable: Any]()) { result, item in result[item.key.rawValue] = item.value } } @objc func fetchSupportedBiometryType(_ resolver: RCTPromiseResolveBlock, rejecter: RCTPromiseRejectBlock) { resolver(supportedBiometryType()) } } Objective-c Swiftで⼀つNative Moduleを実装する
  11. © - BASE, Inc. // Keychain-Bridging-Header.h #import <React/RCTBridgeModule.h> • React

    Native Bridgeの型や機能を使えるようにする // Keychain.swift @objc(KeychainQ) class KeychainQ: NSObject { @objc func constantsToExport() -> [AnyHashable: Any]! { return constants.reduce(into: [AnyHashable: Any]()) { result, item in result[item.key.rawValue] = item.value } } @objc func fetchSupportedBiometryType(_ resolver: RCTPromiseResolveBlock, rejecter: RCTPromiseRejectBlock) { resolver(supportedBiometryType()) } } Swiftで⼀つNative Moduleを実装する
  12. © - BASE, Inc. React Native Bridge Native Modules Helpers

    Objective-c Java 使いやすくするための追加実装 JS/TSからそのままだと扱いづらいので、 Native Modulesの型定義を定義したり、 Native Modulesの機能をベースに さらに便利な機能を提供したりする Native Modulesを実装している多くのライブラリでは、そのまま公開するのではなく、JS/TSから使いやすいように型定義とヘルパー関数 を提供している • async-storage • https://github.com/react-native-community/async-storage • react-native-netinfo • https://github.com/react-native-community/react-native-netinfo Swiftで⼀つNative Moduleを実装する
  13. © - BASE, Inc. TS側の実装 // NativeInterface.ts import { NativeModules,

    Platform } from 'react-native'; import { KeychainNativeModule } from './privateTypes'; const KeychainQ: KeychainNativeModule | undefined = NativeModules.KeychainQ; if (!KeychainQ) { if (Platform.OS === 'ios') { throw new Error( `react-native-keychain-q: NativeModule.KeychainQ is null. To fix this issue try these steps: • Run \`react-native link react-native-keychain-q\` in the project root. • Rebuild and re-run the app. • If you are using CocoaPods on iOS, run \`pod install\` in the \`ios\` directory and then rebuild and re-run the app. You may also need to re-open Xcode to get the new pods. • Check that the library was linked correctly when you used the link command by running through the manual installation instructions in the README. * If you are getting this error while unit testing you need to mock the native module. Follow the guide in the README. If none of these fix the issue, please open an issue on the Github repository: https://github.com/baseinc/react-native-keychain-q` ); } } export default KeychainQ; • Native Moduleが登録されているかチェックする
  14. © - BASE, Inc. TS側の実装 // NativeMethods.ts type NativeConstants =

    Readonly<{ authenticationUserCanceledCode: number; keychainErrorCodes: { [K in KeychainErrorCodes]: string }; }>; type NativeMethods = Readonly<{ fetchSupportedBiometryType: () => Promise<BiometryType>; }>; export type KeychainNativeModule = NativeConstants & NativeMethods & {}; • Native Moduleの型定義 // Keychain.swift @objc(KeychainQ) class KeychainQ: NSObject { @objc func constantsToExport() -> [AnyHashable: Any]! { return constants.reduce(into: [AnyHashable: Any]()) { result, item in result[item.key.rawValue] = item.value } } @objc func fetchSupportedBiometryType(_ resolver: RCTPromiseResolveBlock, rejecter: RCTPromiseRejectBlock) { resolver(supportedBiometryType()) } }
  15. © - BASE, Inc. TS側の実装 // index.ts import Keychain from

    './internal/nativeInterface'; export async function fetchSupportedBiometryType(): Promise< BiometryType | 'unknown' > { if (Keychain) { return await Keychain.fetchSupportedBiometryType(); } // iOS以外はNativeModuleを実装してないので固定値を返す return 'unknown'; } • ヘルパー関数でラップして、未対応プラットフォームでも使えるようにする
  16. © - BASE, Inc. Summary • Bobを使うと開発環境をすぐにセットアップできて、ビルドのことを基本的 には考える必要がない • Native

    Modulesを開発する際に知っておくべきアーキテクチャーについて • Swiftを使ったNative Moduleの実装 • react-native-community/Expo SDKは実装の参考になる