メインコンテンツまでスキップ

Expo SDK 49アップグレード

参考

以下の記事を参考にして、このアプリのExpo SDKを49にアップグレードしました。 主な変更点とこのアプリで実施したアップグレード手順を紹介します。

なお、使用される可能性の低いEASとReact Native Webに関する内容は記載しません。

Expo SDK 49の主な変更

React Native v0.72.4

詳細は、以下のリンク先を参照してください。

Reactのバージョンは変更されておらず、依然としてv18.2.0です。

非推奨となっていた以下のコンポーネントは、React Native v0.72.0で削除されたことに注意してください。 コミュニティパッケージへの移行が推奨されています。

デバッグ機能の改善

ネットワークデバッグ

アプリがexpo-dev-clientまたはExpo Goで実行されるときのネットワークリクエストをJSデバッガーで確認できるようになりました。

React devtoolsとExpo CLIの連携

Shift+mを押して「Start React devtools」を選択することで起動できるようになりました。

VS Codeでのデバッグ

Expo Tools Extensionを使用して、VS CodeからアプリのJavaScriptコードを直接デバッグするための実験的なサポートが追加されました。

TypeScript バージョン ^5.1.3

SDK 48までは^4.9.4が使用されていました。

TypeScript ^5の詳細は、以下のリンク先を参照してください。

他のライブラリでサポートされていないv5.2.2が使用されないようにするため、^5.1.3ではなく~5.1.3指定を推奨します。

@typescript-eslint/typescript-estree(v5)がv5.1.xまでしかサポートしていません。

typescript-eslint/packages/typescript-estree/src/parseSettings/warnAboutTSVersion.ts at v5.62.0 · typescript-eslint/typescript-eslint

const SUPPORTED_TYPESCRIPT_VERSIONS = '>=3.3.1 <5.2.0';

関係するライブラリの依存関係は以下のとおりです。

  • expo-module-scripts(v3.0.x)
    • eslint-config-universe(v11)
      • @typescript-eslint(v5)

Expoがサポートするライブラリや機能

ライブラリの更新

Expoが管理しているライブラリの内、メジャーバージョンアップなど大きなリリースがあったものを記載します。

詳細やその他の変更は、以下のリンク先を参照してください。

Expo Module APIの改善

ローカル モジュールが導入されました。 これにより、ライブラリを作成したり、アプリのネイティブ プロジェクトを管理したりせずに、アプリ内でネイティブ コードを作成できるようになります。 SDK 49のプロジェクトで以下のコマンドを実行することで試すことができます。

ローカルモジュールの作成コマンド
npx create-expo-module --local

さらに、コンポーネント参照にネイティブの非同期関数を追加できるようになりました。 同期関数はJavaScriptValue、JavaScriptObject、JavaScriptFunctionなどのJS型の引数を受け取ることができるようになりました。

詳細は、JavaScript valuesを参照してください。

(iOSシミュレータ)AppleシリコンによるExpo Goのネイティブ実行サポート

TestFlightビルドを使用して、シミュレータを使用せずにAppleシリコンMac上でExpo Goを直接実行もできます。 ただし、UIの問題がいくつかあるようで、修正が行われています。

Appleシリコン上でネイティブ実行の詳細は、以下のリンク先を参照してください。

開発ビルドフラグ(--dev-client)の削除

npx expo start --dev-client--dev-clientフラグは必要なくなりました。

expo-dev-clientパッケージがプロジェクトにインストールされている場合、デフォルトで開発ビルドがターゲットになります。

キーボードショートカットs(switch)を使用して、開発ビルドとExpo Goターゲットを切り替えることができます。 これにより、QRコードが指すURLと、キーボードショートカットa(Android)とi(iOS)で起動するURLが変更されます。

expo export:embed

Bundle React Native code and imagesビルドフェーズの@react-native-community/cliバンドルコマンドが置き換わりました。 これにより、カスタムエントリポイントのサポートを追加できるようになりました。 package.jsonmainを変更して、任意のソースファイルを指すようにできます。 Expo Routerを使用していない場合は、新しいエントリファイルでregisterRootComponentを使用する必要があります。

Expo CLIによるMetro環境変数のサポート

React Nativeエコシステムの既存のアプローチには、変数を更新するためにBabelキャッシュをクリアする必要があるなどの問題がありました。

新しいアプローチでは、プロセスをExpo Metro構成に統合し、JavaScriptエコシステムで一般的な規則に従って環境変数名の接頭辞にPUBLICを含めて、これらの問題が解決されます。

SDK 49では、EXPO_PUBLIC_プレフィックスを付けて.env.env.localなどのファイルで変数を定義でき、それらが使用される場合はアプリのJavaScriptに組み込まれます。

詳細は、以下のリンク先を参照してください。

パッケージバージョン検証の選択的オプトアウト

環境によっては、Expoが推奨するバージョンとは異なるパッケージのバージョンを使用したい場合があります。

package.jsonexpo.install.excludeのキーがサポートされるようになり、expo startなどで行われる検証から除外するパッケージを指定できるようになります。

詳細は、以下のリンク先を参照してください。

scheme (app config)

以前は、追加のschemeを設定するにはConfig Pluginsを使用する必要がありました。 文字列の配列または文字列を使用できるようになりました。

app.config.js
scheme: ['myapp', 'fb1234'],
// or
scheme: 'myapp',

New Architecture/Fabricのサポート

expo-dev-clientでFabricが実験的にサポートされました。 npx create-expo-app@latest -e with-new-arch で試すことができます。

これにより、新しいアーキテクチャをサポートしていないモジュールはexpo-updatesのみになりました。

Android Expo Modules

Gradle 8を使用するようになりました。

マイグレーションする方法については、以下のリンク先を参照してください。

Expo CLI

すべてのプロジェクトでデフォルトのポート19000ではなく8081を使用するようになりました。

JSCのリモートデバッグ無効化(Expo Goおよびexpo-dev-client)

JSCリモートデバッグは、Hermesによるデバッグに比べて特にうまく機能することはなく、時間の経過とともに信頼性が低くなってしまいました。

詳細については、以下のReact Nativeへのプル リクエストを参照してください。 これは次のReact Nativeリリースに含まれる予定です。

Expo Constants

Constants.manifestが非推奨になりました。代わりに、Constants.expoConfigを使用してください。

詳細は、以下のリンク先を参照してください。

expo-auth-session

expo-auth-sessionuseProxyAuthSession.startAsyncが削除されました。

認証プロバイダーがカスタムschemeにリダイレクトしない問題を回避するために認証プロキシを使用していた場合は、Expo Goから開発ビルドに切り替え、ネイティブSDKの使用が推奨されています。

android:usesCleartextTraffic

システムのデフォルト値を使用するようになりました。

デバッグ ビルドでは明示的にtrueが設定されますが、他のビルドタイプ(例:リリースビルド)では指定されていません。 つまり、API 27以下ではデフォルトでtrue、API 28以降ではデフォルトでfalseになります。

セキュリティで保護されていないエンドポイントへのネットワークリクエストが存在する場合は、expo-build-propertiesを使用してtrueにする必要があります。

iOS用アイコンの簡素化

Xcode 14以降では自動的にサイズ変更される単一の1024x1024画像を使用してアプリアイコンを簡素化できます。 そのため、Expoではprebuild時に1024x1024画像のみを生成するようになりました。

Expo SDK 46のサポート終了

Expo SDK 46がサポート対象外になりました。Expo SDK 46を使用している場合は、Expo SDK 47以降にアップグレードする必要があります。

なお、次のリリースではExpo SDK47と48のサポートが終了する見込みのようです。

このアプリで実施したアップグレードの手順

このアプリでは、Expo SDK 48 から 49 にアップグレードする方法を参考に、以下の作業を実施してExpo SDK 49にアップグレードしました。

  1. npm install expo@^49.0.0を実行して、Expo SDKをアップグレード
  2. npx expo install --fixを実行して、Expoが管理するライブラリのアップグレード
    • TypeScript v5.2.xではなくv5.1.xを使用するためnpm install typescript@~5.1.3を追加で実行(参考
  3. 既存パッチファイルの更新
  4. jest-expoのアップグレード
  5. プロジェクトの依存関係に問題がないか確認
  6. TSCエラーへの対応
  7. テストコードの修正
  8. 警告ログへの対応
  9. npm run prebuildを実行してネイティブプロジェクトの再生成
  10. ビルドエラーの修正
  11. renovate除外設定更新
    • 使用しなくなったandroidx.swiperefreshlayout:swiperefreshlayoutを削除
  12. Config PluginswithAndroidRemoveUsesClearTextTrafficForReleaseを削除
  13. Proguardルールの更新
  14. Expoの更新履歴確認と対応
  15. React Nativeの更新履歴確認と対応
  16. expo-template-blank-typescriptの更新履歴確認と対応
  17. expo-template-bare-minimumの更新履歴確認と対応
  18. React Native Upgrade Helperを参照して、React Nativeの更新を確認
  19. 手動管理しているライセンスの更新

アップグレードを実施したPull Requestはws-4020/mobile-app-crib-notes#1221です。

既存パッチファイルの更新

このアプリでは、patch-packageを使用して、以下のライブラリにパッチファイルを適用していました。 パッチ内容の詳細は、こちらを参照してください。

  • react-native
  • @expo/config-plugins
  • expo-splash-screen
  • react-native-elements

react-nativeに適用していたパッチは、以下のPRで修正されたためパッチフィルを削除しました。

@expo/config-pluginsexpo-splash-screenは、Expo SDKのアップグレードに伴いバージョンが上がりました。しかし、適用していたパッチファイルはまだ必要な対応だったため、パッチファイルは削除せずに各ライブラリのバージョンに合わせてファイル名をリネームしました。

react-native-elementsに関しては、バージョンが変わらなかったため変更はありません。

jest-expoのアップグレード

jest-expoだけはnpx expo install --fixでバージョンが上がらなかったので、手動で^49.0.0に変更しました。

参考: Expo SDK 48アップグレード #jest-expoのアップグレード

プロジェクトの依存関係に問題がないか確認

npx expo-doctor@latestを実行したところ、以下の実行結果のように@expo/config-pluginsバージョンの問題が検知されました。

npx expo-doctor@latestの実行結果
✔ Check Expo config for common issues
✖ Check package.json for common issues
✔ Check dependencies for packages that should not be installed directly
✔ Check npm/ yarn versions
✔ Check for common project setup issues
✔ Check Expo config (app.json/ app.config.js) schema
✔ Check for legacy global CLI installed locally
✔ Check that packages match versions required by installed Expo SDK
✔ Check that native modules do not use incompatible support packages
✖ Check that native modules use compatible support package versions for installed Expo SDK

Detailed check results:

Expected package @expo/config-plugins@~7.2.2
Found invalid:
@expo/config-plugins@5.0.4
@expo/config-plugins@5.0.4
(for more info, run: npm why @expo/config-plugins)
Advice: Upgrade dependencies that are using the invalid package versions.

The following scripts in package.json conflict with the contents of node_modules/.bin: orval.

One or more checks failed, indicating possible issues with the project

しかし、前回実施したExpo48への更新から変わらず@react-native-firebaseの更新が必要であるため保留としました。

@expo/config-pluginsのバージョン
$ npm ls @expo/config-plugins
santoku-app@1.0.0 /path/to/mobile-app-crib-notes/example-app/SantokuApp
├── @expo/config-plugins@7.2.5
├─┬ @react-native-firebase/app@16.4.6
│ └── @expo/config-plugins@5.0.4
├─┬ @react-native-firebase/crashlytics@16.4.6
│ └── @expo/config-plugins@5.0.4
├─┬ expo-splash-screen@0.20.5
│ └─┬ @expo/prebuild-config@6.2.6
│ └── @expo/config-plugins@7.2.5 deduped
└─┬ expo@49.0.8
├─┬ @expo/cli@0.10.11
│ └── @expo/config-plugins@7.2.5 deduped
├── @expo/config-plugins@7.2.5 deduped
└─┬ @expo/config@8.1.2
└── @expo/config-plugins@7.2.5 deduped

TSCエラーへの対応

npm run lint:tscでTypeScriptの型をチェックしました。

DimensionValueの厳密化

react-nativev0.72.0ではDimensionの型定義が厳密になりました。

interface FlexStyle
-width?: number | string | undefined;
+width?: DimensionValue | undefined;
export type DimensionValue =
| number
| 'auto'
| `${number}%`
| Animated.AnimatedNode
| null;

style定義の型推論で${number}%ではなくstringとして認識されてしまう問題が起きたので、as constを追加しました。

src/bases/ui/picker/Fader.tsx
       case FaderPosition.TOP:
return {
containerStyle: {...staticStyles.containerTop, height: size},
- imageStyle: {height: size, width: '100%'},
+ imageStyle: {height: size, width: '100%'} as const,
imageSource: gradientTopImage,
};

WebView.onScrollの型定義変更

react-native-webviewのFabric対応でonScrollの型定義が変更されました。

WebViewProps
-onScroll?: (event: WebViewScrollEvent) => void;
+onScroll?: ComponentProps<typeof NativeWebViewComponent>['onScroll'];

これは整理すると以下になります。

-onScroll?: (event: NativeSyntheticEvent<NativeScrollEvent>) => void;
+onScroll?: (event: NativeSyntheticEvent<ScrollEvent>) => void | Promise<void>;

onScrollの型不一致エラーになったので、以下のように対応しました。

src/bases/ui/webview/WebView.tsx
-  const handleScroll = useCallback(
- (event: WebViewScrollEvent) => {
+ const handleScroll = useCallback<Exclude<WebViewProps['onScroll'], undefined>>(
+ async event => {
if (isUriChanged && event.nativeEvent.contentOffset.y > 0) {

FunctionComponentの型定義の変更

React.FC(FunctionComponent)の返り値の型定義がReactElementからReactNodeに変更されました。

namespace React
    interface FunctionComponent<P = {}> {
- (props: P, context?: any): ReactElement<any, any> | null;
+ (props: P, context?: any): ReactNode;
namespace React
    type ReactNode =
| ReactElement
| string
| number
| Iterable<ReactNode>
// 略

FlatListrenderItemReactNodeではなくReactElementを要求しているため、型不一致エラーとなりました。 そこで、renderItemに渡す関数にはReact.FCを使用しないように変更しました。

src/features/demo-app-info/components/AppInfoTemplate.tsx
return <FlatList data={items} renderItem={AppInfoListItem} keyExtractor={keyExtractor} testID={testID} />;
interface FlatListProps<ItemT>
  renderItem: ListRenderItem<ItemT> | null | undefined;
export type ListRenderItem<ItemT> = (
info: ListRenderItemInfo<ItemT>,
) => React.ReactElement | null;
src/features/demo-app-info/components/AppInfoListItem.tsx
-export const AppInfoListItem: React.FC<AppInfoListItemProps> = ({item}) => {
+export const AppInfoListItem = ({item}: AppInfoListItemProps) => {

テストコードの修正

react-native-reanimated v3対応

react-native-reanimated v3でディレクトリ構造が変わりました。 それに合わせてimportや型定義ファイルを変更しました。

-react-native-reanimated/lib/reanimated2/
+react-native-reanimated/lib/module/reanimated2/

また、setUpTests()のimportが短縮できるようになっていたので変更しました。

jest/setup/react-native-reanimated.js
 // https://docs.swmansion.com/react-native-reanimated/docs/guides/testing
-require('react-native-reanimated/lib/reanimated2/jestUtils').setUpTests();
+require('react-native-reanimated').setUpTests();

react-native Dimensionsのmock失敗への対応

DimensionsがES moduleに変更されました。

-module.exports = Dimensions;
+export default Dimensions;
node_modules/react-native/index.js
   get Dimensions(): Dimensions {
- return require('./Libraries/Utilities/Dimensions');
+ return require('./Libraries/Utilities/Dimensions').default;
},

そのため、mockする際は__esModule: trueを指定するように変更しました。

src/bases/ui/picker/DateTimePicker.ios.test.tsx
 jest.doMock('react-native/Libraries/Utilities/Dimensions', () => ({
- get: jest.fn().mockReturnValue({width: 400, height: 1000}),
- set: jest.fn(),
- addEventListener: jest.fn().mockReturnValue({remove: jest.fn()}),
+ __esModule: true,
+ default: {
+ get: jest.fn().mockReturnValue({width: 400, height: 1000}),
+ set: jest.fn(),
+ addEventListener: jest.fn().mockReturnValue({remove: jest.fn()}),
+ },
}));

jest.advanceTimersByTimeactでラップ

以下の警告が出るようになっていたため、actでラップするように変更しました。

  • Warning: An update to ForwardRef inside a test was not wrapped in act(...).
  • When testing, code that causes React state updates should be wrapped into act(...):
src/bases/ui/snackbar/SnackbarComponent.test.tsx
   it('SnackbarComponent表示中にpropsでhideを指定した場合、SnackbarComponentが消えることを確認', async () => {
render(<SnackbarComponent message="テストメッセージ" />);

- jest.advanceTimersByTime(FADE_IN_DURATION);
+ await act(() => {
+ jest.advanceTimersByTime(FADE_IN_DURATION);
+ });
expect(screen.queryByText('テストメッセージ')).not.toBeNull();

Constants.manifestがdeprecatedになったことへの対応

Expo SDK 49の主な変更 - Expoがサポートするライブラリや機能 - Expo Constantsに記載した通り、Constants.manifestが非推奨になりました。 jest-mockでもmockする際にスプレッド構文を使用してアクセスすると警告ログが出力されるようになっています。 そのため、スプレッド構文ではなくProxyを使用して上書きするようにしています。

jest/__mocks__/expo-constants.ts
 import ExpoConstants from 'expo-constants';

-export const Constants: typeof ExpoConstants = {
- ...ExpoConstants,
+import {wrapProperty} from '../utils/wrapProperty';
+
+export const Constants = wrapProperty(ExpoConstants, {
expoConfig: {
name: 'SantokuApp',
slug: 'santokuApp',
@@ -16,6 +17,6 @@ export const Constants: typeof ExpoConstants = {
mswEnabled: false,
},
},
-};
+});
jest/utils/wrapProperty.ts
function hasOwnProperty<T, K extends PropertyKey>(obj: T, propertyKey: K): obj is T & Record<K, unknown> {
return Object.prototype.hasOwnProperty.call(obj, propertyKey);
}

/**
* `{...original, [key]: value}`だとgetterにdeprecated警告ログが存在する場合警告ログが出てしまう問題対策
*/
export function wrapProperty<T extends object>(original: T, propertyObj: object): T {
return new Proxy(original, {
get(target, name, ...rest) {
if (hasOwnProperty(propertyObj, name)) {
return propertyObj[name];
}
return Reflect.get(target, name, ...rest);
},
});
}

アニメーション中のAnimatedStyleの僅かな変化への対応

アニメーション中のtranslateYの値が以前と僅かに異なっていました。 値が以前と同じことが必須ではなく差分も小さいため、理由の調査はせず、テストコードを更新しました。

src/bases/ui/picker/PickerContainer.test.tsx
@@ -53,7 +53,7 @@ describe('PickerContainer only with required props', () => {
await act(() => {
jest.advanceTimersByTime(DEFAULT_SLIDE_IN_DURATION / 2);
});
- expect(animatedView).toHaveAnimatedStyle({transform: [{translateY: 75}]});
+ expect(animatedView).toHaveAnimatedStyle({transform: [{translateY: 74.00333333333333}]});
expect(sut).toMatchSnapshot('Animating (slide in)');

// アニメーションが完了すると`transform`が設定値に到達していること
@@ -82,7 +82,7 @@ describe('PickerContainer only with required props', () => {
await act(() => {
jest.advanceTimersByTime(DEFAULT_SLIDE_OUT_DURATION / 2);
});
- expect(animatedView).toHaveAnimatedStyle({transform: [{translateY: 75}]});
+ expect(animatedView).toHaveAnimatedStyle({transform: [{translateY: 76.00333333333333}]});
expect(sut).toMatchSnapshot('Animating (slide out)');

// アニメーションが完了するとコンポーネントが消えること

slideOutDurationテストの時間指定が厳密すぎるとテストが失敗する問題の修正

今まではアニメーション終了1ms前のタイミングでアニメーション終了のcallbackが呼ばれないことを期待したテストをしていましたが、callbackが呼ばれるようになっていました。 1msは小さすぎ、誤差の影響と考えられるため10msに変更しました。

src/bases/ui/picker/PickerContainer.test.tsx
@@ -146,14 +146,14 @@ describe('PickerContainer with all props', () => {
sut.update(<PickerContainer isVisible={false} afterSlideOut={afterSlideOut} slideOutDuration={100} />);

await startAnimation();
- // slideOutDurationで指定した時間の1msc前ではafterSlideOutは実行されない
+ // slideOutDurationで指定した時間の10msc前ではafterSlideOutは実行されない
await act(() => {
- jest.advanceTimersByTime(99);
+ jest.advanceTimersByTime(90);
});
expect(afterSlideOut).not.toHaveBeenCalled();
// slideOutDurationで指定した時間経過後は、afterSlideOutが実行される
await act(() => {
- jest.advanceTimersByTime(1);
+ jest.advanceTimersByTime(10);
});
expect(afterSlideOut).toHaveBeenCalled();
});

keyExtractorの呼び出しが増えたことによって失敗するようになったテストの修正

react-nativeFlatListkeyExtractorの呼び出しが増えていました。 2回目にindex=1が呼ばれるのは内部実装に依存していたため、toHaveBeenNthCalledWithの替わりにtoHaveBeenCalledWithを使用するようにしました。

src/bases/ui/picker/SelectPickerItems.android.test.tsx
     expect(flatListProps.contentContainerStyle).toEqual({paddingVertical: 120});
expect(flatListProps.snapToInterval).toBe(60);
- expect(keyExtractor).toHaveBeenNthCalledWith(
- 1,
+ // `value: '1'` だけ2回呼ばれるのでtoHaveBeenNthCalledWithを使用しない
+ expect(keyExtractor).toHaveBeenCalledWith(
{value: '1', label: 'test1', key: 'key1', color: 'red', fontFamily: 'Roboto'},
0,
);
- expect(keyExtractor).toHaveBeenNthCalledWith(
- 2,
+ expect(keyExtractor).toHaveBeenCalledWith(
{value: '2', label: 'test2', color: 'yellow', fontFamily: 'SFProText'},
1,
);

警告ログへの対応

typescript-eslintを現在のTypeScriptバージョンに対応したバージョンへ更新

以下のライブラリがTypeScript~5.1.3をサポートしていなかったため、バージョンアップしました。

  • @typescript-eslint/eslint-plugin
  • @typescript-eslint/parser
発生していた警告ログ
WARNING: You are currently running a version of TypeScript which is not officially supported by @typescript-eslint/typescript-estree.

You may find that it works just fine, or you may not.

SUPPORTED TYPESCRIPT VERSIONS: >=3.3.1 <5.1.0

YOUR TYPESCRIPT VERSION: 5.1.6

Please only submit bug reports when using the officially supported version.
実行コマンド
npm update @typescript-eslint/eslint-plugin @typescript-eslint/parser

JSX namespaceが非推奨になったことへの対応

以下のcommitでJSXnamespaceがReactnamespaceの下に移動され、JSXは非推奨となりました。

これに対応するためJSX.ElementReact.JSX.Elementに変更しました。

src/bases/ui/picker/useSelectPickerItems.ts
 type SelectPickerItemsTypes<ItemT> = {
selectedValue?: React.Key | ItemT;
- children?: JSX.Element | JSX.Element[];
+ children?: React.JSX.Element | React.JSX.Element[];
items: Item<ItemT>[];
itemHeight: number;

initialScrollIndexの範囲外警告への対応

react-native v0.72.0からFlatListVirtualizedList)のinitialScrollIndex-1(負の値)を指定すると警告ログがでるようになりました。

initialScrollIndex "-1" is not valid (list has 0 items)

これは、itemsが空かselectedValueが不正でitemsに含まれてないというレアケースでしか問題になりません。 しかし、テストケースにitems=[]が存在するため、以下のように-1のときはnullにする対応をしました。

src/bases/ui/picker/SelectPickerItems.android.tsx
@@ -120,7 +120,7 @@ <AnimatedFlatList
renderItem={renderItem}
decelerationRate={DECELERATION_RATE}
getItemLayout={getItemLayout}
- initialScrollIndex={selectedIndex}
+ initialScrollIndex={selectedIndex !== -1 ? selectedIndex : null}
centerContent
testID={flatListTestID}
/>

ビルドエラーの修正

app.notifee:coreを見つけられない問題の対応

npm run androidを実行すると以下のエラーが出ました。

Could not find any matches for app.notifee:core:+ as no versions of app.notifee:core are available.

ワークアラウンドとして、expo-build-propertiesプラグインのandroid.extraMavenRepos[]を追加する必要がありました。

app.config.js
@@ -94,6 +94,10 @@
-keep public class com.horcrux.svg.** {*;}
`,
enableProguardInReleaseBuilds: true,
+ extraMavenRepos: [
+ // notifee Expo49対応: https://github.com/invertase/notifee/issues/808
+ '$rootDir/../../../node_modules/@notifee/react-native/android/libs',
+ ],
},
ios: {

参考Issueは以下です(2023/09時点で未解決)。

Config PluginswithAndroidRemoveUsesClearTextTrafficForReleaseを削除

今までは暗号化してないhttp通信を禁止するために、android:usesCleartextTrafficを削除するConfig Pluginsを作成し使用していました。

しかし、Expo SDK 49の主な変更 - Expoがサポートするライブラリや機能 - android:usesCleartextTrafficに記載した通り、Expo側で対応されました。 そのため、このConfig Pluginsは不要になったので削除しました。

Proguardルールの更新

各ルールが現在も必要か、コメントのリンク先の更新などが無いかを確認しました。

react-native-svg用ルールの削除

react-native-svg v13.7.0からライブラリ側で自動的にルールを含めるようになりました。

そのため、app.config.jsexpo-build-propertiesプラグインのandroid.extraProguardRulesでルールを追加する必要はなくなったので削除しました。

app.config.js
 -keep class expo.modules.ExpoModulesPackageList { *; }
-
-# https://github.com/software-mansion/react-native-svg#problems-with-proguard
--keep public class com.horcrux.svg.** {*;}
`,
enableProguardInReleaseBuilds: true,

Expoの更新履歴確認と対応

ExpoのCHANGELOGを参照して、Expo SDKとExpoが管理するライブラリの更新内容を確認しました。

ここまでの対応以外に追加で必要なものはありませんでした。

React Nativeの更新履歴確認と対応

React NativeのCHANGELOGを参照して、React Nativeの更新内容を確認しました。

ここまでの対応以外に追加で必要なものはありませんでした。

expo-template-blank-typescriptの更新履歴確認と対応

expo-template-blank-typescriptの更新履歴を確認しました。

npm install expo@^49.0.0npx expo install --fixで更新される依存ライブラリのアップグレードが主な変更でした。そのため、このアプリで特別な対応は必要ありませんでした。

expo-template-bare-minimumの更新履歴確認と対応

このアプリではConfig Pluginsに対応しているので、expo-template-bare-minimumの更新に伴う個別の対応は基本的に必要ありません。 ただし、以下の場合は個別に対応する必要があるため、この観点に絞ってexpo-template-bare-minimumの更新履歴を確認しました。

  • このアプリで作成しているConfig Pluginsによる変更と、expo-template-bare-minimumの更新に伴う変更が競合した場合
  • Prebuild時に生成・更新されないファイル
    • android/, ios/以外のファイル(.gitignoreなど)

.gitignoreの更新

expo-template-bare-minimumの以下のコミットで、.gitignoreが更新されていました。

大きな変更は、重複の削除でした。 つまり、Android, Xcode関連ファイルは android/, ios/.gitignore に記載されているため削除されました。 このアプリにもこの変更を取り込みました。

.gitignore
-# Xcode
-#
-build/
-*.pbxuser
-!default.pbxuser
-*.mode1v3
-!default.mode1v3
-*.mode2v3
-!default.mode2v3
-*.perspectivev3
-!default.perspectivev3
-xcuserdata
-*.xccheckout
-*.moved-aside
-DerivedData
-*.hmap
-*.ipa
-*.xcuserstate
-project.xcworkspace
-
-# Android/IntelliJ
-#
-build/
-.idea
-.gradle
-local.properties
-*.iml
-*.hprof
注意

このアプリでは、prebuild時のファイルコピー処理に不具合があり、prebuild/ディレクトリの一部ファイルがignoreされなくなりました。 不具合はandroid/,ios/ディレクトリの.gitignoreprebuild/ディレクトリにコピーされないもので、以下のPull Requestで対処しました。

手動管理しているライセンスの更新

このアプリでは、使用しているライブラリのライセンス一覧を出力するスクリプトを用意しています。詳細は、こちらを参照してください。

managed-license.jsの更新

ライセンス情報が不足しており補完したい、あるいは、開発時のみ使用するため除外したいライブラリとバージョンをmanaged-license.jsで管理しています。

ライセンス情報が不足しているライブラリなどは、以下のコマンドを実行することで確認できます。

  • node .script/check-licenses.js

実行した結果、いくつかのライブラリのライセンス情報を更新する必要があったので以下を実施しました。

  • 使用ライブラリの名前更新
  • 使用ライブラリのバージョン更新
  • 使用ライブラリのライセンスファイルURL更新
  • 新規ライブラリ情報の追加
  • 使用しなくなったライブラリ情報の削除

新規ライセンスへの対応

このアプリでは、アプリに使用しても問題ないライセンスを管理してチェックできるようにしています。

今回のExpo SDKアップグレードでは、Mozilla Public License 2.0MPL-2.0)のライブラリが増えました。 MPL-2.0は準コピーレフト型ライセンスであり、該当ライブラリ以外のソースコードの公開義務が発生しないため、使用可としました。 そのライセンス名(MPL-2.0)をcheck-licenses.jslicenseWhitelistに追加しています。