Slide 1

Slide 1 text

© - BASE, Inc. 最近のNative Modules開発に ついて / / TECH STAND # React Native ⼤⽊ 聡 (@roothybrid )

Slide 2

Slide 2 text

⾃⼰紹介 • ⼤⽊ 聡 • GitHub/Twitter: @roothybrid • BASE, Inc. • Product Dev Division Native Application > Tech Lead • iOSアプリ開発 etc. • React Native歴 1年くらい © - BASE, Inc.

Slide 3

Slide 3 text

© - 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

Slide 4

Slide 4 text

© - BASE, Inc. React Nativeのセットアップ改善(>=v . ) • Native ModulesのAutolinking • ⼿順書でコマンドを記述する⼿間が減る) • RNプロジェクトの設定ファイル(react-native.config.js) • 設定を宣⾔できる(⼿順書でコマンド記述する⼿間) • プラットフォーム毎に違うライブラリを使うため⽚⽅をopt-out

Slide 5

Slide 5 text

© - BASE, Inc. ⼀つのnpmパッケージとしてNative Modulesを開発するのはそんなに悪くなさそ う

Slide 6

Slide 6 text

© - BASE, Inc. Native Modules開発の⽅針 • できる限り標準で推奨している⽅法で開発 • 現在のアーキテクチャーのI/Fを知る • Nativeのモダンな⾔語を採⽤して、最新の情報を得る

Slide 7

Slide 7 text

© - 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

Slide 8

Slide 8 text

© - BASE, Inc. Bob • ライブラリを実装してすぐに動かせるexampleのReact Nativeアプリ環境が⼿に⼊る • JavaScript/TypeScriptどちらでも使えるようにあらかじ め設定されている • ビルドのための設定はあらかじめされている • あとはコードを実装するのみ

Slide 9

Slide 9 text

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

Slide 10

Slide 10 text

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

Slide 11

Slide 11 text

© - 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から呼び出すための型定義やヘルパー関数を⽤意する。

Slide 12

Slide 12 text

© - BASE, Inc. Native Modules開発の⽅針 • Nativeのモダンな⾔語を採⽤して、最新の情報を得る Objective-CやJavaはプラットフォームAPIのコア機能で使われる⾔語である ものの、最近アプリケーションやライブラリの実装サンプルは、Swiftや Kotlinで書かれていることが多い。

Slide 13

Slide 13 text

© - 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

Slide 14

Slide 14 text

© - BASE, Inc. SwiftでNative Moduleを実装した

Slide 15

Slide 15 text

© - BASE, Inc. SwiftでNative Moduleを実装した • react-native-keychain-q https://github.com/baseinc/react-native-keychain-q • 複数アカウントのインターネットパスワードを管理する

Slide 16

Slide 16 text

© - 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

Slide 17

Slide 17 text

© - BASE, Inc. // Keychain.m #import @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を実装する

Slide 18

Slide 18 text

© - BASE, Inc. // Keychain-Bridging-Header.h #import • 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を実装する

Slide 19

Slide 19 text

© - 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を実装する

Slide 20

Slide 20 text

© - BASE, Inc. TS側の実装

Slide 21

Slide 21 text

© - 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が登録されているかチェックする

Slide 22

Slide 22 text

© - BASE, Inc. TS側の実装 // NativeMethods.ts type NativeConstants = Readonly<{ authenticationUserCanceledCode: number; keychainErrorCodes: { [K in KeychainErrorCodes]: string }; }>; type NativeMethods = Readonly<{ fetchSupportedBiometryType: () => Promise; }>; 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()) } }

Slide 23

Slide 23 text

© - 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'; } • ヘルパー関数でラップして、未対応プラットフォームでも使えるようにする

Slide 24

Slide 24 text

© - BASE, Inc. Summary • Bobを使うと開発環境をすぐにセットアップできて、ビルドのことを基本的 には考える必要がない • Native Modulesを開発する際に知っておくべきアーキテクチャーについて • Swiftを使ったNative Moduleの実装 • react-native-community/Expo SDKは実装の参考になる