既存のreact-nativeプロジェクトでexpo-notificationsを使う

# はじめに
Expoは、React Nativeでのアプリ開発を超絶楽に行えるフレームワークです。
Expoのフルマネージド環境下では、優れた開発体験と引き換えに、ネイティブの機能はExpoで提供されているもの以外を使用できません。
ExpoのAPI郡を使用しながらネイティブの機能を使用するライブラリを使用したい場合、
Expoプロジェクトの初期化時にBare Workflowを選択したり、
Expoフルマネージドプロジェクトをejectする等の方法があります。
今回は既存のReact Nativeプロジェクトでexpo-notificationsを使用する手順を紹介します。

https://expo.dev/

# リポジトリ

コードはこちら

https://github.com/alternacrow/ExistingReactNativeWithExpoNotifications

## ライブラリのバージョン
```json
"react": "17.0.2"
"react-native": "0.65.1"
"react-native-unimodules": "0.14.6"
"expo-notifications": "0.12.3"
```

# 手順

## 既存プロジェクトにreact-native-unimodulesを追加する

`react-native-unimodules`はExpoのユニモジュールを使用するためのライブラリです。
既存のReact Nativeに導入することで、Expoから提供されているAPIを使用できます。

```bash
yarn add react-native-unimodules
cd ./ios && pod install
```

iOSとAndroidの各設定は公式のドキュメントにあります。
https://docs.expo.dev/bare/installing-unimodules/

動作確認は、下記で行なえます。
systemFontsが`undefined`でなく、配列が表示されれば正常に設定完了です。

```typescript
import {Constants} from 'react-native-unimodules';
console.log(Constants.systemFonts);
```

## expo-notificationsを追加する

Expoの通知のライブラリです。
ローカル通知やExpoの提供するプッシュ通知機能を使用することができます。
プッシュ通知のテストには、ウェブツールも提供されています。
https://expo.dev/notifications

```bash
yarn add expo-notifications
```

あとは、他の通知ライブラリと同様、各種APIを使用して通知設定を行うだけです。

## 2021/09/05 補足: patchの追加

`react-native-unimodules@0.14.6`が、まだ`react-native@0.65.1`に対応していないため、patchをあてる必要があります。

`@unimodules+core+7.1.1.patch`

```diff
diff --git a/node_modules/@unimodules/core/ios/UMCore/UMUtilities.m b/node_modules/@unimodules/core/ios/UMCore/UMUtilities.m
index e1c02e3..c8b7604 100644
--- a/node_modules/@unimodules/core/ios/UMCore/UMUtilities.m
+++ b/node_modules/@unimodules/core/ios/UMCore/UMUtilities.m
@@ -28,7 +28,9 @@ UM_REGISTER_MODULE();

 - (void)setModuleRegistry:(UMModuleRegistry *)moduleRegistry
 {
-  _moduleRegistry = moduleRegistry;
+  if ([moduleRegistry isKindOfClass: [UMModuleRegistry class]]) {
+    _moduleRegistry = moduleRegistry;
+  }
 }

 - (nullable NSDictionary *)launchOptions

```

`@unimodules+react-native-adapter+6.3.5.patch`

```diff
diff --git a/node_modules/@unimodules/react-native-adapter/ios/UMReactNativeAdapter/Services/UMReactNativeEventEmitter.m b/node_modules/@unimodules/react-native-adapter/ios/UMReactNativeAdapter/Services/UMReactNativeEventEmitter.m
index 7fe313b..6fe899a 100644
--- a/node_modules/@unimodules/react-native-adapter/ios/UMReactNativeAdapter/Services/UMReactNativeEventEmitter.m
+++ b/node_modules/@unimodules/react-native-adapter/ios/UMReactNativeAdapter/Services/UMReactNativeEventEmitter.m
@@ -139,7 +139,9 @@ RCT_EXPORT_METHOD(removeProxiedListeners:(NSString *)moduleName count:(double)co

 - (void)setModuleRegistry:(UMModuleRegistry *)moduleRegistry
 {
-  _umModuleRegistry = moduleRegistry;
+  if ([moduleRegistry isKindOfClass:[UMModuleRegistry class]]) {
+    _umModuleRegistry = moduleRegistry;
+  }
 }

 @end
diff --git a/node_modules/@unimodules/react-native-adapter/build/NativeModulesProxy.native.js b/node_modules/@unimodules/react-native-adapter/build/NativeModulesProxy.native.js
index fdcfaba..d2a55e1 100644
--- a/node_modules/@unimodules/react-native-adapter/build/NativeModulesProxy.native.js
+++ b/node_modules/@unimodules/react-native-adapter/build/NativeModulesProxy.native.js
@@ -20,8 +20,10 @@ if (NativeProxy) {
         //
         // On Android only {start,stop}Observing are called on the native module
         // and these should be exported as Expo methods.
-        NativeModulesProxy[moduleName].addListener = (...args) => NativeModules.UMReactNativeEventEmitter.addProxiedListener(moduleName, ...args);
-        NativeModulesProxy[moduleName].removeListeners = (...args) => NativeModules.UMReactNativeEventEmitter.removeProxiedListeners(moduleName, ...args);
+        if (NativeModules.UMReactNativeEventEmitter) {
+            NativeModulesProxy[moduleName].addListener = (...args) => NativeModules.UMReactNativeEventEmitter.addProxiedListener(moduleName, ...args);
+            NativeModulesProxy[moduleName].removeListeners = (...args) => NativeModules.UMReactNativeEventEmitter.removeProxiedListeners(moduleName, ...args);
+        }
     });
 }
 else {
```

# おわりに

ライブラリのメンテは、リソースやコストの問題で行われなくなったものをよく見かけます。
ExpoのライブラリはExpoチームによるメンテナンスが行われている安定性をふまえると、
実際に使用してみなければハマりどころは分からないものですが、
事業プロダクトでもユニモジュールとして採用候補に入るかと思いました。