ReactNativeでのアプリ開発、ExpoSDKがいい感じになってきたようなので試してみた：その３

[前回](https://qiita.com/sakai-y/items/c4fd712fe31063d4ea5d)からの続きです。

# Expo Modules
では、カスタムネイティブ機能の開発のため、Expo Modulesを素振りしてみます。

https://docs.expo.dev/modules/overview/

## ざっくり説明
素のReactNativeでカスタムネイティブ機能を追加する場合、`ios`および`android`ディレクトリ以下のネイティブコードを触ることになります。
そこはWeb技術が基本となるReactNativeとは異なり、それぞれのプラットフォームの世界です。
`react-native`コマンドでセットアップした場合、iOSはObjective-C、AndroidはJavaでネイティブ側のコードが生成されています。新たにカスタムモジュールを追加する場合、それぞれにモジュールの設定コードを追加することになります。

Expo Modulesを利用すると、モジュール追加のためのボイラープレートなどをExpoに任せることができます。
また、Expo ModulesではiOSではSwift、AndroidではKotlinを使用することになります。これはReactNative側のJavaScript/TypeScriptと、パラダイムの異なるObjective-C/Javaを行ったり来たりすることによる効率低下を避けるため、という説明がされています。
（そもそも、もうObjective-Cなんか書きたくない！）

## 触ってみる
`Get started`に沿って触ってみます。

https://docs.expo.dev/modules/get-started/

```shell
yarn create expo-module my-module
```

質問は全てデフォルトでOK。

```shell
✔ Downloaded module template from npm
✔ Created the module from template files
✔ Installed module dependencies
✔ Compiled TypeScript files
✔ Initialized the example app
✔ Configured the example app
✔ Prebuilt the example app
⠹ Installing dependencies in the example app
```

exampleアプリの依存インストールが結構時間掛かりました。

```shell
✔ Created an empty Git repository

✅ Successfully created Expo module

To start developing your module, navigate to the directory and open iOS and Android projects of the example app
> cd my-module
> yarn open:ios
> yarn open:android

Visit https://docs.expo.dev/modules for the documentation on Expo Modules APIs
✨  Done in 214.73s.
```

まずはモジュールをビルドします。
```shell
yarn build
```

watchモードで待機されてターミナルが解放されないので、別のターミナルでexampleアプリを起動します。

```shell
cd example
yarn android
```

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/243061/df95604e-d452-357d-dc08-669b12c995b2.png" width="50%">

iOSも同様に

```shell
yarn ios
```

少しコードを見てみます。

```tsx:example/App.tsx
import * as MyModule from 'my-module';

export default function App() {
  return (
    <View style={styles.container}>
      <Text>{MyModule.hello()}</Text>
    </View>
  );
}
```

画面中央のテキストは`MyModule.hello()`の返す値が表示されたものです。
その`MyModule.hello`は、これです。
```ts:src/index.ts
// Import the native module. On web, it will be resolved to MyModule.web.ts
// and on native platforms to MyModule.ts
import MyModule from './MyModule';

export function hello(): string {
  return MyModule.hello();
}
```

`import MyModule from './MyModule'`でネイティブモジュールをインポートして、`hello()`を呼び出した結果を返しているだけです。

ネイティブ側のコードが、以下それぞれAndroidとiOSです。

```kotlin:android/src/main/java/expo/modules/mymodule/MyModule.kt
    Function("hello") {
      "Hello world! 👋"
    }
```

```swift:ios/MyModule.swift
    Function("hello") {
      return "Hello world! 👋"
    }
```

該当箇所の周辺を見ても、KotlinとSwiftがよく似ているのが分かりますね。
`android`、`ios`ディレクトリ以下のモジュール用のコード、それぞれ２ファイルずつしかありません。中身も`@ReactMethod`（Android）や`@objc`（iOS）などのアノテーションもなく、スッキリしています。
スゴイ。

## 変更してみる
説明に沿ってネイティブコードを変更してみます。

`android/src/main/java/expo/modules/mymodule/MyModule.kt`
```kotlin:変更前
    Function("hello") {
      "Hello world! 👋"
    }
```
```kotlin:変更後
    Function("hello") {
      "Hello world! 🌎🤖"
    }
```

`ios/MyModule.swift`
```swift:変更前
    Function("hello") {
      return "Hello world! 👋"
    }
```
```swift:変更後
    Function("hello") {
      return "Hello world! 🌎🍎"
    }
```

コード変更後、`yarn android`および`yarn ios`すると、変更が反映されます。
（ネイティブ側の変更は自動リロード対象ではないため、ビルドが必要）

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/243061/0742f67b-9079-5d4b-da78-35fea0e639ca.png" width="70%">

ネイティブモジュールの素振りができたので、次はこれをアプリに組み込んでいきます。

つづく