第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-camera、expo-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、独自のネイティブ機能など)が必要になった時は、
- 既存のサードパーティライブラリを探す ― React Native Directory(https://reactnative.directory/)で検索
- 自分でExpo Modulesを書く ― Swift/Kotlinでネイティブ実装し、JS側にAPIを公開
- 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アプリ作りに入っていきます。