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/

18c5d6e2413dc02665fd4210bf5d094b?s=128

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. ⼀つのnpmパッケージとしてNative Modulesを開発するのはそんなに悪くなさそ う

  6. © - BASE, Inc. Native Modules開発の⽅針 • できる限り標準で推奨している⽅法で開発 • 現在のアーキテクチャーのI/Fを知る

    • Nativeのモダンな⾔語を採⽤して、最新の情報を得る
  7. © - 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
  8. © - BASE, Inc. Bob • ライブラリを実装してすぐに動かせるexampleのReact Nativeアプリ環境が⼿に⼊る • JavaScript/TypeScriptどちらでも使えるようにあらかじ

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

    Bridge Native Modules Helpers Objective-c Java
  10. © - BASE, Inc. Native Modules開発の⽅針 • 現在のアーキテクチャーのI/Fを知る React Native

    Bridge Native Modules Helpers Objective-c Java 最低限必要な実装 React NativeのNativeModules経由で 使えるようになる
  11. © - 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から呼び出すための型定義やヘルパー関数を⽤意する。
  12. © - BASE, Inc. Native Modules開発の⽅針 • Nativeのモダンな⾔語を採⽤して、最新の情報を得る Objective-CやJavaはプラットフォームAPIのコア機能で使われる⾔語である ものの、最近アプリケーションやライブラリの実装サンプルは、Swiftや

    Kotlinで書かれていることが多い。
  13. © - BASE, Inc. Native Modules開発の⽅針 • Nativeのモダンな⾔語を採⽤して、最新の情報を得る SwiftもKotlinもオープンソースな⾔語で、多くの提案が⾏われており、改善の スピードが早く、先進的な機能がいち早く体験できる。そのため、

    ECMAScript/TypeScriptでも⾒たような機能が存在する。 let x = foo?.bar.baz(); let roomCount = john.residence?.numberOfRooms TypeScriptのOptional Chaining SwiftのOptional Chaining
  14. © - BASE, Inc. SwiftでNative Moduleを実装した

  15. © - BASE, Inc. SwiftでNative Moduleを実装した • react-native-keychain-q https://github.com/baseinc/react-native-keychain-q •

    複数アカウントのインターネットパスワードを管理する
  16. © - 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
  17. © - 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を実装する
  18. © - 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を実装する
  19. © - 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を実装する
  20. © - BASE, Inc. TS側の実装

  21. © - 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が登録されているかチェックする
  22. © - 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()) } }
  23. © - 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'; } • ヘルパー関数でラップして、未対応プラットフォームでも使えるようにする
  24. © - BASE, Inc. Summary • Bobを使うと開発環境をすぐにセットアップできて、ビルドのことを基本的 には考える必要がない • Native

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