【Expo】SDK 52 正式リリース

# はじめに

こんにちは、梅雨です。

2024/11/13に Expo SDK 52が公開されました。

https://expo.dev/changelog/2024/11-12-sdk-52

今回の記事では、Expo SDK 52で新たに使用可能になった機能などについて解説してきいたいと思います。

# New Architecture が利用可能に

> The New Architecture is now enabled by default for all new projects. Starting with SDK 52, when you create a new project with npx create-expo-app, you will see that newArchEnabled is set to true in your app.json.

ドキュメントによると、SDK 52のリリースによってデフォルトで **New Architecture** が利用可能になるようです。

New Architecture とは、Meta によって開発が行われている React Native における新しい内部構造のことであり、React Native 0.68から試験的にオプトインされています。

Expo には SDK 51から試験的にオプトインされていましたが、今回の SDK 52からは公式に New Architecture の使用が推奨されます。

New Architecture の導入によって、アプリケーションの起動時間やメモリ使用量が大幅に削減されることが見込まれています。

https://reactnative.dev/architecture/landing-page

また、SDK 52より前のバージョンで開発が行われていたプロジェクトに関しても、SDK 52へのアップデートによってNew Architectureの使用が可能になります。

`app.json` の中で `newArchEnabled` プロパティを `false` にすることで明示的に不使用とすることもできます。

# `expo-video` 正式リリース

SDK 51 から beta 版として公開されていた `expo-video` ライブラリが正式に安定版としてリリースされました。

https://docs.expo.dev/versions/v52.0.0/sdk/video

以前から提供されていたビデオコンポーネントである `expo-av` からの移行が推奨されています。

![](https://expo.dev/static/changelog/2024-10-24/video-features.png)

```bash
$ npx expo install expo-video
```

```json:app.json
{
  "expo": {
    "plugins": [
      [
        "expo-video",
        {
          "supportsBackgroundPlayback": true,
          "supportsPictureInPicture": true
        }
      ]
    ],
  }
}
```

`VideoView` という UI コンポーネントと `useVideoPlayer` というフックが使用できます。

```tsx/app/(tabs)/index.tsx
import { useEvent } from "expo";
import { useVideoPlayer, VideoView } from "expo-video";
import { StyleSheet, View, Button } from "react-native";

const videoSource =
  "https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4";

const VideoScreen = () => {
  const player = useVideoPlayer(videoSource, (player) => {
    player.loop = true;
    player.play();
  });

  const { isPlaying } = useEvent(player, "playingChange", {
    isPlaying: player.playing,
  });

  return (
    <View style={styles.contentContainer}>
      <VideoView
        style={styles.video}
        player={player}
        allowsFullscreen
        allowsPictureInPicture
      />
      <View style={styles.controlsContainer}>
        <Button
          title={isPlaying ? "Pause" : "Play"}
          onPress={() => {
            if (isPlaying) {
              player.pause();
            } else {
              player.play();
            }
          }}
        />
      </View>
    </View>
  );
};

const styles = StyleSheet.create({
  contentContainer: {
    flex: 1,
    padding: 10,
    alignItems: "center",
    justifyContent: "center",
    paddingHorizontal: 50,
  },
  video: {
    width: 350,
    height: 275,
  },
  controlsContainer: {
    padding: 10,
  },
});

export default VideoScreen;
```

![expo-video-001.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2671591/8a5c0497-b4b9-affe-641a-53c73fb8dc6c.gif)

### Picture-in-Picture (PiP) モード

Picture-in-Pictureモードは、動画を小さなウィンドウに縮小して、他のアプリやコンテンツを見ながら動画を視聴することを可能にする機能です。

ネイティブの機能であるためシミュレータでは使用できませんでしたが、実機で試したところ写真のように Picture-in-Picture モードで再生することができました。

<img width=320 src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2671591/d1b07b6b-dbb1-8af1-d4cd-ed4f6de34e15.jpeg">

### Now Playing Notification への表示

コントロールセンターの表示に関しては以下のようにメタデータを指定することで実装できます。

```tsx
const videoSource: VideoSource = {
  uri: "https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4",
  metadata: {
    title: "Big Buck Bunny",
    artwork:
      "https://i.vimeocdn.com/video/20963649-f02817456fc48e7c317ef4c07ba259cd4b40a3649bd8eb50a4418b59ec3f5af5-d?mw=3000&mh=1245&q=70",
  },
};
```

また、プレイヤーの `showNowPlayingNotification` プロパティを `true` にする必要があります。（これはデフォルトで `true` にして欲しいような気もする。）

```diff_tsx
const player = useVideoPlayer(videoSource, (player) => {
+   player.showNowPlayingNotification = true;
  player.loop = true;
  player.play();
});
```

<img width=320 src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2671591/c8f042ae-0007-8017-dc7a-474e13f69416.png">

# `expo-audio` beta 版リリース

`expo-audio` は、モバイルデバイス上で音声の録音、再生、音量やピッチの調整などを行うことができるライブラリです。

```bash
$ npx expo install expo-audio
```

```json:app.json
{
  "expo": {
    "plugins": [
      [
        "expo-audio",
        {
          "microphonePermission": "Allow $(PRODUCT_NAME) to access your microphone."
        }
      ]
    ]
  }
}
```

`useAudioPlayer()` というフックが使用できます。

```tsx
import { View, StyleSheet, Button } from "react-native";
import { useAudioPlayer } from "expo-audio";

const App = () => {
  const player = useAudioPlayer({
    uri: "./assets/songs/maou_inst_14_shining_star.mp3",
  });

  return (
    <View style={styles.container}>
      <Button
        title="Play Sound"
        onPress={() => {
          player.play();
        }}
      />
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: "center",
    backgroundColor: "#ecf0f1",
    padding: 10,
  },
});

export default App;
```

しかし、残念ながら手元のデバイスで音楽の再生を行うことはできませんでした。何か実装に問題があるのか、バグなのかは分かりませんが、引き続き調査を続けてみようと思います。

何かわかった方はコメントで教えていただきたいです。

# `expo-file-system/next` beta 版リリース

`expo-file-system/next` は既存の `expo-file-system` ライブラリを使いやすく再構築したものであり、Expo 上でのファイル操作を簡単に行うことのできるライブラリです。

```bash
$ npx expo install expo-file-system
```

```tsx
import { File, Paths } from "expo-file-system/next";
import { View } from "react-native";

const Home = () => {
  try {
    const file = new File(Paths.cache, "example.txt");
    if (!file.exists) file.create();
    file.write(new Date().toISOString());
    console.log(file.text());
  } catch (error) {
    console.error(error);
  }

  return <View></View>;
};

export default Home;
```

# カメラとデータベース関連ライブラリの改善
SDK 52では、`expo-camera` および `expo-sqlite` ライブラリが改善され、パフォーマンスや機能が向上しました。

### `expo-camera`

SDK 51 でリリースされた `expo-camera/next` が `expo-camera` としてリリースされました。リアルタイムの画像処理や高解像度の写真撮影がより効率的に行えるようになります。

### `expo-sqlite`

SQLite のデータベースを shared container に保存できるようになりました。これによって、ウィジェットなどからのデータアクセスが可能になります。

# iOS 18に対応

iOS 18で新たに利用可能になったダークアイコンおよび色合い調アイコンがExpoでも使用可能になりました。

```diff_json:app.json
{
  "expo": {
    "ios": {
-       "icon": "./assets/images/icon.png",
+       "icon": {
+         "light": "./assets/images/icon.png",
+         "dark": "./assets/images/icon-dark.png",
+         "tinted": "./assets/images/icon-tinted.png"
+       }
    }
  }
}
```

# DOM Components

`"use dom"` ディレクティブをファイルの先頭に記述することによって、DOM コンポーネントを使用できるようになりました。

```tsx
"use dom";

const Home = () => {
  return (
    <div>
      <p>Hello, world!</p>
    </div>
  );
};

export default Home;
```

DOMコンポーネントを使用することで、ウェブからネイティブへの段階的な移行が非常に簡単になります。

# おわりに

以上が、Expo SDK 52 のリリースで加わった変更のうち、自分が特に注目した機能となります。

これ以外にもさまざまな機能が使えるようになっているため、気になる方是非リリースノートをご確認ください。

最後までお読みいただきありがとうございました。