スマートフォンハードウェアの呼び出し:カメラ、GPSとプッシュ通知

もしあなたのサービスがテキストとボタンの表示だけで済むのであれば、RWD対応のモバイル版ウェブサイトで十分です。 私たちがわざわざ「ネイティブアプリ」を開発する理由は、スマートフォンハードウェアへのアクセスが必要だからです:**カメラ、GPS位置情報、プッシュ通知、生体認証(Face ID/指紋)**など。

従来のReact Native開発では、これらのハードウェア機能を連携させるために、iOSのInfo.plistやAndroidのAndroidManifest.xmlを直接編集する必要があり、非常に面倒でエラーも発生しやすかったです。 良い知らせは、Expo SDKがこれらの面倒な作業をすべて引き受けてくれることです!

このレッスンでは、最もよく使われる3つのハードウェア機能を学びます。

1. 権限リクエスト(Permissions)の黄金法則

どのハードウェアにアクセスする前にも、AppleとGoogleの規定に従う必要があります:必ずユーザーの同意を得ること

権限なしに直接ハードウェアAPIを呼び出すと、アプリがクラッシュ(Crash)します。

Expoのほとんどのハードウェアモジュールは、usePermissions()のようなHookを提供しており、これをエレガントに処理できます:

  1. 現在の権限状態を確認
  2. まだ確認していない場合、システムダイアログでユーザーに尋ねる
  3. ユーザーが拒否した場合、なぜこの権限が必要かを説明するテキストを表示し、システム設定で有効にするよう誘導

2. 実践1:カメラの起動と写真選択(Image Picker)

ユーザーに写真を撮影させたり、アルバムから写真を選択してプロフィール画像をアップロードさせます。

パッケージのインストール:

npx expo install expo-image-picker

コード実装���

import { useState } from 'react';
import { Button, Image, View, Alert } from 'react-native';
import * as ImagePicker from 'expo-image-picker';

export default function CameraScreen() {
  const [image, setImage] = useState<string | null>(null);

  // 1. カメラ権限をリクエストする関数
  const requestPermissionAndPick = async () => {
    const { status } = await ImagePicker.requestCameraPermissionsAsync();
    
    if (status !== 'granted') {
      Alert.alert('権限が必要', '写真を撮影するにはカメラ権限が必要です!');
      return;
    }

    // 2. カメラを起動
    let result = await ImagePicker.launchCameraAsync({
      mediaTypes: ImagePicker.MediaTypeOptions.Images, // 動画ではなく写真のみに制限
      allowsEditing: true, // 撮影後にトリミングを許可
      aspect: [4, 3], // トリミング比率
      quality: 0.8, // 画像品質を圧縮(0-1)して帯域を節約
    });

    if (!result.canceled) {
      // 3. 撮影した写真のURIをStateに保存して表示
      setImage(result.assets[0].uri);
    }
  };

  return (
    <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
      <Button title="カメラを開いて写真を撮る" onPress={requestPermissionAndPick} />
      {image && (
        <Image source={{ uri: image }} style={{ width: 300, height: 300, marginTop: 20, borderRadius: 10 }} />
      )}
    </View>
  );
}

ヒント:ユーザーにアルバムから写真を選択させたい場合は、launchCameraAsynclaunchImageLibraryAsyncに置き換えるだけです!

3. 実践2:GPS位置情報の取得(Location)

UberやFoodpandaのような地図機能を作る最初のステップは、ユーザーの現在地を知ることです。

パッケージのインストール:

npx expo install expo-location

コード実装:

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

export default function LocationScreen() {
  const [location, setLocation] = useState<Location.LocationObject | null>(null);
  const [errorMsg, setErrorMsg] = useState<string | null>(null);

  useEffect(() => {
    (async () => {
      // 1. 位置情報権限をリクエスト(フォアグラウンド使用権限)
      let { status } = await Location.requestForegroundPermissionsAsync();
      if (status !== 'granted') {
        setErrorMsg('位置情報権限が拒否されたため、サービスを提供できません');
        return;
      }

      // 2. 現在位置の座標を取得
      let currentLocation = await Location.getCurrentPositionAsync({});
      setLocation(currentLocation);
    })();
  }, []);

  return (
    <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
      {errorMsg ? (
        <Text style={{ color: 'red' }}>{errorMsg}</Text>
      ) : location ? (
        <>
          <Text>あなたの緯度:{location.coords.latitude}</Text>
          <Text>あなたの経度:{location.coords.longitude}</Text>
        </>
      ) : (
        <ActivityIndicator size="large" color="#0000ff" />
      )}
    </View>
  );
}

4. 実践3:プッシュ通知(Push Notifications)

プッシュ通知はユーザーを呼び戻す(Retargeting)最も強力な武器です。 Expoでは、AppleのAPNsやGoogleのFCMと直接戦う必要はありません。Expo Push Notificationsサービスを使用すれば、両プラットフォームの送信ロジックを統合してくれます!

パッケージのインストール:

npx expo install expo-notifications expo-device

動作原理:

  1. アプリが初めて起動した時、システムにプッシュ通知権限を要求
  2. 専用のExpoPushTokenを取得(これはスマートフォンの住所のようなもの)
  3. このTokenをバックエンドデータベース(例:Supabase)に保存
  4. プッシュ通知を送信したい時、バックエンドからExpoのAPIサーバーにHTTPリクエストを送信し、このTokenを添付すると、Expoがユーザーのスマートフォンに通知を配信!
import * as Notifications from 'expo-notifications';

// アプリがフォアグラウンドにある時の通知動作を設定
Notifications.setNotificationHandler({
  handleNotification: async () => ({
    shouldShowAlert: true, // 画面上部に通知をポップアップ表示
    shouldPlaySound: true, // 通知音を再生
    shouldSetBadge: false,
  }),
});

// ローカルプッシュ通知をトリガー(ネットワーク経由せず、アラームやリマインダーに適している)
async function scheduleLocalNotification() {
  await Notifications.scheduleNotificationAsync({
    content: {
      title: "新しいメッセージがあります!📬",
      body: 'これはVibe Tutorのデモプログラムによってトリガーされたテスト通知です。',
      data: { url: '/chat/123' }, // 非表示データを添付可能。通知クリック時にこのデータを使ってページ遷移
    },
    trigger: { seconds: 5 }, // 5秒後にトリガー
  });
}

[!CAUTION] プッシュ通知の落とし穴 iOSシ���ュレーター(Simulator)は実際のリモートプッシュ通知を受信できません!完全なプッシュ通知機能をテストするには、アプリをコンパイルして「実機のiPhone」にインストールする必要があります。

これで、あなたのアプリは目(カメラ)と方向感覚(GPS)を手に入れました。次の章では、アプリ内の複雑なデータフローとAPI連携を管理する方法——**状態管理(State Management)**を学びます。

完全なチュートリアルをロック解除

このチャプターは有料コンテンツです。プロジェクトに参加して、10以上の神レベルのPromptや実際のソースコード例を含む、5000字以上の深い分析をロック解除してください!