コンテンツにスキップ
Webフロントエンドエンジニアのための React Native 実践入門
Esc
navigateopen⌘Jpreview
このページの内容

第11章 ネイティブ機能をさらっと使う

カメラや位置情報、通知といった機能をnpm installの感覚で導入でき、権限まわりの作法も身につきます。

モバイルアプリならではの機能 ― カメラ、画像ピッカー、位置情報、通知など ― は、Expo Modulesエコシステムを使えば「Webでライブラリをnpm installする感覚」で導入できます。本章では全体像と代表的な機能の使い方を、サラッと触る程度に紹介します。

Expoモジュールエコシステムの全体像

Expoが公式に提供しているモジュール群は数十あります。expo-という名前の付くライブラリがそれで、npx expo installコマンドでまとめて管理できます。

npx expo install expo-camera expo-image-picker expo-location expo-notifications

このコマンドの利点は、現在のExpo SDKに合ったバージョンを自動で選んでくれることです。npm installで個別バージョンを指定するより事故が起きにくいので、Expoモジュールに限らずReact Native向けのライブラリはnpx expo installを使うのが原則です。

主要なモジュールをカテゴリ別に挙げると、

  • メディア: expo-camera / expo-image-picker / expo-image / expo-audio(音声) / expo-video(動画)
  • 位置・センサー: expo-location / expo-sensors / expo-haptics
  • 通知: expo-notifications
  • 認証: expo-local-authentication(指紋・Face ID) / expo-secure-store
  • ストレージ・ファイル: expo-file-system / expo-sharing
  • デバイス情報: expo-device / expo-constants / expo-application
  • ハードウェア連携: expo-screen-orientation / expo-keep-awake / expo-battery

「やりたいこと」を思いついた時に、まずexpo-XXXという名前で公式ドキュメントを検索する習慣をつけておくと、最短で見つけられます。

Permissions(権限)の概念

カメラ・位置情報・通知などをアプリで使うには、ユーザーに許可をもらう必要があります。Webにもnavigator.permissionsがありますが、モバイルではより厳格で、権限がないと機能自体が使えないことが多いです。

各モジュールには「現在の権限状態を取得する」「権限を要求する」APIが用意されており、初回利用時にOSのダイアログを出してもらう、という流れになります。

import { useCameraPermissions } from "expo-camera";
import { Pressable, Text } from "react-native";

function CameraGate() {
  const [permission, requestPermission] = useCameraPermissions();

  if (!permission?.granted) {
    return (
      <Pressable onPress={requestPermission}>
        <Text>カメラの利用を許可してください</Text>
      </Pressable>
    );
  }

  // 許可された後の本体UI
  return null;
}

app.jsonへの権限設定

権限の説明文や、Androidに必要なManifest宣言は、app.json(またはapp.config.ts)のexpo配下で設定します。たとえばカメラと位置情報を使うアプリなら、次のように書きます。

{
  "expo": {
    "ios": {
      "infoPlist": {
        "NSCameraUsageDescription": "プロフィール画像の撮影に使用します",
        "NSLocationWhenInUseUsageDescription": "近くのスポット検索に使用します"
      }
    },
    "android": {
      "permissions": ["CAMERA", "ACCESS_FINE_LOCATION"]
    }
  }
}

iOSはここに書いた説明文(Info.plistへの書き込み)がそのまま許可ダイアログに表示されます。空のままだとApp Store審査でリジェクトされるので、本番アプリでは必ず適切な文面を書いてください。

なお、Expoモジュール側にも便利なConfig Plugin(expo-cameraexpo-locationなど)が用意されており、plugins配列に追加するだけで上記の設定を自動でやってくれるケースが多くあります。

{
  "expo": {
    "plugins": [
      ["expo-camera", { "cameraPermission": "プロフィール画像の撮影に使用します" }],
      ["expo-location", { "locationWhenInUsePermission": "近くのスポット検索に使用します" }]
    ]
  }
}

各ライブラリのドキュメントに「Config Plugin」のセクションがあるので、そちらの記法に従うのが安全です。

カメラ ― expo-camera

写真を撮る、動画を撮る、QRコードを読むといった用途に使います。

import { CameraView, useCameraPermissions } from "expo-camera";
import { Pressable, Text, View } from "react-native";

function ScannerScreen() {
  const [permission, requestPermission] = useCameraPermissions();

  if (!permission?.granted) {
    return (
      <Pressable onPress={requestPermission}>
        <Text>カメラを許可</Text>
      </Pressable>
    );
  }

  return (
    <View style={{ flex: 1 }}>
      <CameraView
        style={{ flex: 1 }}
        barcodeScannerSettings={{ barcodeTypes: ["qr"] }}
        onBarcodeScanned={({ data }) => console.log("scanned:", data)}
      />
    </View>
  );
}

CameraViewコンポーネントを画面に貼るだけで、リアルタイムのカメラプレビューが表示されます。QRコードの読み取り、写真撮影(takePictureAsync)、ズームやフラッシュ制御などもプロパティとメソッドで対応できます。

画像ピッカー ― expo-image-picker

ユーザーの写真ライブラリから画像を選ぶ、もしくはカメラを起動して写真を撮ってもらう機能です。

import * as ImagePicker from "expo-image-picker";
import { Image, Pressable, Text } from "react-native";
import { useState } from "react";

function PickImage() {
  const [uri, setUri] = useState<string | null>(null);

  const handlePick = async () => {
    const result = await ImagePicker.launchImageLibraryAsync({
      mediaTypes: ["images"],
      quality: 0.8,
    });
    if (!result.canceled) {
      setUri(result.assets[0].uri);
    }
  };

  return (
    <>
      <Pressable onPress={handlePick}>
        <Text>画像を選ぶ</Text>
      </Pressable>
      {uri && <Image source={{ uri }} style={{ width: 200, height: 200 }} />}
    </>
  );
}

launchImageLibraryAsyncがライブラリから選ぶ用、launchCameraAsyncがカメラ起動用です。SNS投稿や、プロフィール画像変更でよく使う組み合わせです。

位置情報 ― expo-location

現在地を取得したり、位置の変化を監視したりできます。

import * as Location from "expo-location";
import { useEffect, useState } from "react";
import { Text } from "react-native";

function CurrentLocation() {
  const [location, setLocation] = useState<Location.LocationObject | null>(null);

  useEffect(() => {
    (async () => {
      const { status } = await Location.requestForegroundPermissionsAsync();
      if (status !== "granted") return;
      const result = await Location.getCurrentPositionAsync();
      setLocation(result);
    })();
  }, []);

  if (!location) return <Text>位置を取得中...</Text>;
  return (
    <Text>
      緯度: {location.coords.latitude}, 経度: {location.coords.longitude}
    </Text>
  );
}

位置情報は権限のグラデーションが細かく(フォアグラウンドのみ・バックグラウンド含む・正確さレベル)、用途に応じて適切な権限を要求してください。常時取得が必要なケース(運動記録、ナビ系)では追加の設定が要ります。

プッシュ通知 ― expo-notifications

アプリが起動していない時にもユーザーに通知を届ける仕組みです。Expoには通知トークンの取得から、Expoのプッシュサービス経由での配信までを支援する仕組みが揃っています。

import * as Notifications from "expo-notifications";

async function registerForPush() {
  const { status } = await Notifications.requestPermissionsAsync();
  if (status !== "granted") return null;

  const tokenData = await Notifications.getExpoPushTokenAsync();
  console.log(tokenData.data); // ExponentPushToken[xxxx]
  return tokenData.data;
}

このトークンをサーバーに送って保存しておき、配信したいタイミングでExpoのPush APIに対してリクエストを投げると、ユーザーの端末に通知が届きます。

iOSはAPNs、AndroidはFCMの設定が必要ですが、開発初期はExpoが間に立ってくれるので最低限のセットアップで試せます。本格的に運用する段階で、自前のFCM/APNs鍵への切り替えなどを検討してください。

ここで区別しておきたいのが、リモートプッシュ通知とローカル通知の違いです。SDK 53以降、Expo Goはリモートプッシュ通知に対応していません。上のコードのようにリモート配信を試すにはDevelopment Buildが必要です。一方、本書のTODOアプリで使う「指定時刻に端末内で発火するローカル通知」(scheduleNotificationAsync、第14章で扱います)はExpo Goでも動作します。どちらもexpo-notificationsが提供する機能ですが、動く場所が違う点を混同しないようにしてください。

ローカル通知とリモートプッシュ通知の経路の違い

ローカル通知は端末内で完結するのでExpo Goでも試せますが、リモートプッシュはExpo Push Service経由でAPNs/FCMまで届く必要があり、Development Buildが要ります。

デバイス機能の小ネタ ― 触覚フィードバック

モバイルらしさを出す細かい工夫として、expo-hapticsによる触覚フィードバックがあります。

import * as Haptics from "expo-haptics";
import { Pressable, Text } from "react-native";

<Pressable
  onPress={() => Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Medium)}
  style={{ padding: 12 }}
>
  <Text>振動</Text>
</Pressable>

ボタンを押した時に「コトッ」とした触覚を返すだけで、操作の手応えがぐっと良くなります。多用は禁物ですが、重要な操作のフィードバックに使うと体験の質が上がります。

標準モジュールにない機能を使いたい時

Expoの標準モジュールでカバーできない機能(特定のサードパーティSDK、独自のネイティブ機能など)が必要になった時は、

  1. 既存のサードパーティライブラリを探す ― React Native Directory(https://reactnative.directory/)で検索
  2. 自分でExpo Modulesを書く ― Swift/Kotlinでネイティブ実装し、JS側にAPIを公開
  3. Config Pluginsで設定変更を加える ― Info.plistやAndroidManifestの編集をJSから行う

の順で検討します。Expo Modulesの書き方は第19章で扱います。

いずれの場合も、Expo Goでは動かないことが多いのでDevelopment Build(第4章)に切り替える必要があります。

本章のまとめ

  • ネイティブ機能はExpo Modulesで気軽に導入できる(npx expo install expo-XXX)
  • カメラ、画像ピッカー、位置情報、通知、触覚など主要なものはほぼ標準モジュールで揃う
  • 利用には権限の取得が必要で、app.jsonへの説明文設定もセット
  • 標準にない機能は、サードパーティ → 自作Expo Modules → Config Pluginsの順で対応

ここまでで「画面・データ・ネイティブ機能」の基礎は揃いました。次章では、モバイルらしさをぐっと引き上げるアニメーションを、ReanimatedのCSSライクなAPIを軸に扱います。それを終えたら実践編のTODOアプリ作りに入っていきます。

最終更新 2026年7月24日