Zenn
🗂

Expoでネイティブコードを書く

2025/03/20に公開

概要

自分でネイティブコードを書いて、Expo から利用するところまでを書いていきます。
仕組みとか swift の使い方については書かず、サクッと Expo でネイティブコードを動かす部分にフォーカスして書いていきます。

今回利用したサンプルコード

https://github.com/toki-developer/expo-native-module-example

事前準備 プロジェクトの作成

Expo のプロジェクトを作成します。

npx create-expo-app expo-native-code-sample

シンプルにするため今回はプロジェクトをリセットします。

cd expo-native-code-sample
npm run reset-project

動いてることを確認します。

npx expo start

「i」を入力して IOS Simulator で開きました。

.
› Press a │ open Android
› Press i │ open iOS simulator
.
.

i

本題

ネイティブコードを書く準備をする

ネイティブコードを書くための雛形の作成と設定をします。
※ Expo プロジェクトのルートディレクトリで実行。 (例では expo-native-code-sample)

npx create-expo-module --local
今のディレクトリの状態

tree コマンドの実行結果です

tree -I 'node_modules' -L 2
.
├── README.md
├── app
│   ├── _layout.tsx
│   └── index.tsx
├── app-example
│   ├── app
│   ├── components
│   ├── constants
│   ├── hooks
│   └── scripts
├── app.json
├── assets
│   ├── fonts
│   └── images
├── expo-env.d.ts
├── modules
│   └── my-module
├── package-lock.json
├── package.json
└── tsconfig.json

modules/my-module が作成されました!
ここに swift や kotlin のコードを書いていきます。
※ my-module は自分がつけた名前

.
└── modules/my-module
    ├── android   // Android用のネイティブコード
    ├── expo-module.config.json
    ├── index.ts
    ├── ios     // iOS用のネイティブコード
    └── src     // ネイティブコードを呼び出すためのコード

ネイティブコードを Expo から使う

雛形として作成されたネイティブコードを index ページから利用します。

app/index.tsx
 import { Text, View } from "react-native";
+import MyModule from "@/modules/my-module";

export default function Index() {
  return (
    <View
      style={{
        flex: 1,
        justifyContent: "center",
        alignItems: "center",
      }}
    >
-      <Text>Edit app/index.tsx to edit this screen.</Text>
+      <Text>{MyModule.hello()}</Text>
     </View>
   );
 }

コード完全版
app/index.tsx
import { Text, View } from "react-native";
import MyModule from "@/modules/my-module";

export default function Index() {
  return (
    <View
      style={{
        flex: 1,
        justifyContent: "center",
        alignItems: "center",
      }}
    >
      <Text>{MyModule.hello()}</Text>
    </View>
  );
}

ネイティブプロジェクトを生成します。

npx expo prebuild --clean

/android, /iosディレクトリが作成されました!

アプリを起動します。

npm run ios

「Hello world! 👋 」と表示されました!

ネイティブコードを編集する

iOS を対象として、swift のコードを編集していきます。

今回は swift の使い方ではなく、ネイティブコードを書いて Expo から利用することが目的なのでシンプルな修正のみとします。
modules/my-module/ios/MyModule.swifthello 関数が定義されているので書き換えてみます。

modules/my-module/ios/MyModule.swift
    Function("hello") {
-     return "Hello world! 👋"
+     return "Hello Zenn Article 😎"
    }

アプリを再起動します。

npm run ios

swift コードの変更内容が反映されました!

Function()で同期関数、AsyncFunction()で非同期関数の定義ができます。
/modules/my-module/src/MyModule.tsで型の定義がされています。

modules/my-module/src/MyModule.ts
declare class MyModule extends NativeModule<MyModuleEvents> {
  PI: number;
  hello(): string;
  setValueAsync(value: string): Promise<void>;
}

View はこんな感じで使えます。

app/index.tsx
import { Text, View } from "react-native";
import MyModule, { MyModuleView } from "@/modules/my-module";

export default function Index() {
  return (
    <View
      style={{
        flex: 1,
        justifyContent: "center",
        alignItems: "center",
      }}
    >
      <Text>{MyModule.hello()}</Text>
      <MyModuleView />
    </View>
  );
}

MyModuleView の Props の型はmodules/my-module/src/MyModuleView.tsxで定義がされています。MyModuleViewPropsが Props の型になります

modules/my-module/src/MyModuleView.tsx
import { requireNativeView } from "expo";
import * as React from "react";

import { MyModuleViewProps } from "./MyModule.types";

const NativeView: React.ComponentType<MyModuleViewProps> =
  requireNativeView("MyModule");

export default function MyModuleView(props: MyModuleViewProps) {
  return <NativeView {...props} />;
}

おわり

ネイティブコードを書いて、Expo で利用することができるようになりました 👏
swift コードを書いて Expo から利用できるようになったので、Expo でも swift でのみ提供されている API などにアクセスできるようになります 🎉

これで Screen Time API なども利用できるみたいです!
まだまだ理解が浅かったり知識が少ないので、勉強していきます〜

その他

Expo Module のコマンドについて

expo modules はライブラリを作るための機能です。

npx create-expo-module で作成される/android,iosディレクトリと expo prebuildで作成される/android,iosディレクトリは別物なので注意してください。
(自分が最初記事探してた時に混乱した)

Expo アプリケーションにモジュール(ネイティブコード)を追加したい場合は --localを使います。

npx create-expo-module --local

ルートの android・ios ディレクトリについて

こちらはexpo prebuildで自動生成されるものなので、.gitignoreに追加するのがお勧めです。

.gitignore
/ios/
/android/

参考

https://docs.expo.dev/modules/get-started/#adding-a-new-module-to-an-existing-application

GitHubで編集を提案

Discussion

ログインするとコメントできます