RORK LABEN
PLAY — Google Play の target API level 36 要件が昨日8月31日に発効しました。今日以降、新規アプリと既存アプリの更新は Android 16 対応が必須ですVISIBILITY — API 35 のままのアプリは掲載こそ続きますが、新しい Android 版のユーザーには表示されなくなります。エラーが出ないまま新規インストールだけが減る点に注意が要りますEXTENSION — 間に合わなかった場合は、Play Console から2026年11月1日までの延長申請が出せます。恒久対応の計画とセットで進めるのが実務的ですAPPLE — Apple 側は9月9日にイベント、iOS 27 の正式リリースは9月14日と報じられています。生成したアプリの iOS 27 実機確認はリリース週の前に済ませておきたいところですEXPO — Expo が expo-paste-input を公開しました(8月28日)。React Native の TextInput に画像・GIF・ステッカーの貼り付けを追加するネイティブモジュールですEAS — EAS Observe が8月20日に GA になりました。クラッシュや性能の観測を、ビルドや配信と同じ EAS 上で持てるようになっていますPLAY — Google Play の target API level 36 要件が昨日8月31日に発効しました。今日以降、新規アプリと既存アプリの更新は Android 16 対応が必須ですVISIBILITY — API 35 のままのアプリは掲載こそ続きますが、新しい Android 版のユーザーには表示されなくなります。エラーが出ないまま新規インストールだけが減る点に注意が要りますEXTENSION — 間に合わなかった場合は、Play Console から2026年11月1日までの延長申請が出せます。恒久対応の計画とセットで進めるのが実務的ですAPPLE — Apple 側は9月9日にイベント、iOS 27 の正式リリースは9月14日と報じられています。生成したアプリの iOS 27 実機確認はリリース週の前に済ませておきたいところですEXPO — Expo が expo-paste-input を公開しました(8月28日)。React Native の TextInput に画像・GIF・ステッカーの貼り付けを追加するネイティブモジュールですEAS — EAS Observe が8月20日に GA になりました。クラッシュや性能の観測を、ビルドや配信と同じ EAS 上で持てるようになっています
記事一覧/開発ツール
開発ツール/2026-04-26中級

Rork で Google Places API を使ったお店検索アプリを作る — 位置情報連携の実践ガイド

Rork と Google Places API を組み合わせて、現在地から近くのお店を検索・地図表示するアプリを作る方法を解説します。動作確認済みのコードとつまずきやすいポイントを丁寧に紹介します。

Google Places API位置情報3地図React Native234Expo194外部API2

Rork でアプリを作り始めると、いずれ「現在地から近くのお店を探せる機能が欲しい」という場面に出会います。

飲食店検索、観光スポット案内、近くのサービス一覧 — 位置情報とスポット検索を組み合わせたアイデアは豊富です。ただ、地図コンポーネントと外部 API を同時に動かすのは、初めてだと少し複雑に感じるかもしれません。

完成したコードはそのまま使えるよう、コメントと期待する動作も記載しています。

Google Cloud で API キーを用意する

まず Google Cloud Console から Places API を有効化し、API キーを取得します。

  1. Google Cloud Console にアクセスし、新しいプロジェクトを作成します
  2. 「API とサービス」→「ライブラリ」で「Places API」を検索して有効化します
  3. 「認証情報」から API キーを作成します。本番運用では、アプリのバンドル ID(iOS)またはパッケージ名(Android)で制限をかけることをおすすめします
# .env ファイルに追記(API キーはコードに直接書かない)
EXPO_PUBLIC_GOOGLE_PLACES_API_KEY=YOUR_GOOGLE_PLACES_API_KEY

EXPO_PUBLIC_ プレフィックスをつけると、React Native のコード内でそのまま process.env.EXPO_PUBLIC_GOOGLE_PLACES_API_KEY として参照できます。.gitignore.env を追加するのも忘れずに。

なお、API キーを取得しただけでは不十分で、Google Cloud の課金アカウントを有効化しておく必要があります。これを見落とすと、後述する REQUEST_DENIED エラーの原因になります。

Rork でプロジェクトを作成する

Rork Companion を起動し、以下のようなプロンプトで初期構成を生成します。

現在地を取得して、半径 500m 以内のカフェを検索し、
地図上にマーカーで表示するアプリを作ってください。
マーカーをタップすると店名と住所が表示される構成にしてください。
API 呼び出しには fetch を使い、状態管理は useState と useEffect で行ってください。

生成されたコードの中で最初に確認すべきは、expo-location が依存関係に含まれているかどうかです。位置情報の取得にはこのパッケージが必要で、OS のパーミッション処理も含まれています。

現在地の取得と周辺スポット検索を実装する

位置情報の取得と API 呼び出しをカスタムフックに分離すると、コンポーネント側がすっきりします。

import * as Location from 'expo-location';
import { useState, useEffect } from 'react';
 
type Place = {
  place_id: string;
  name: string;
  vicinity: string;
  geometry: {
    location: { lat: number; lng: number };
  };
};
 
export function useNearbyPlaces() {
  const [places, setPlaces] = useState<Place[]>([]);
  const [userLocation, setUserLocation] = useState<{ lat: number; lng: number } | null>(null);
  const [error, setError] = useState<string | null>(null);
  const [loading, setLoading] = useState(true);
 
  useEffect(() => {
    (async () => {
      // パーミッションを要求する
      const { status } = await Location.requestForegroundPermissionsAsync();
      if (status !== 'granted') {
        setError('位置情報のアクセスが許可されていません');
        setLoading(false);
        return;
      }
 
      // 現在地を取得する
      const location = await Location.getCurrentPositionAsync({
        accuracy: Location.Accuracy.Balanced,
      });
      const { latitude: lat, longitude: lng } = location.coords;
      setUserLocation({ lat, lng });
 
      // Google Places API で周辺のカフェを検索する
      const apiKey = process.env.EXPO_PUBLIC_GOOGLE_PLACES_API_KEY;
      const radius = 500;
      const type = 'cafe';
      const url =
        `https://maps.googleapis.com/maps/api/place/nearbysearch/json` +
        `?location=${lat},${lng}&radius=${radius}&type=${type}&language=ja&key=${apiKey}`;
 
      const response = await fetch(url);
      if (!response.ok) {
        setError('スポット情報の取得に失敗しました');
        setLoading(false);
        return;
      }
 
      const data = await response.json();
      // 正常時: { results: [{ name, vicinity, geometry, ... }], status: "OK" }
      setPlaces(data.results ?? []);
      setLoading(false);
    })();
  }, []);
 
  return { places, userLocation, error, loading };
}

このフックはエラーハンドリングも含んでいます。パーミッション拒否・ネットワーク障害のどちらが起きても error に文字列がセットされ、コンポーネント側でユーザーに通知できます。

地図にマーカーを表示する

フックを使うと、マップコンポーネント自体はシンプルに保てます。

import MapView, { Marker, PROVIDER_GOOGLE } from 'react-native-maps';
import { View, Text, StyleSheet } from 'react-native';
import { useNearbyPlaces } from './useNearbyPlaces';
 
export default function NearbyPlacesMap() {
  const { places, userLocation, error, loading } = useNearbyPlaces();
 
  if (loading) return <Text style={styles.status}>現在地を取得中...</Text>;
  if (error) return <Text style={styles.status}>{error}</Text>;
  if (!userLocation) return null;
 
  return (
    <View style={styles.container}>
      <MapView
        style={styles.map}
        provider={PROVIDER_GOOGLE}
        initialRegion={{
          latitude: userLocation.lat,
          longitude: userLocation.lng,
          latitudeDelta: 0.01,
          longitudeDelta: 0.01,
        }}
        showsUserLocation
      >
        {places.map((place) => (
          <Marker
            key={place.place_id}
            coordinate={{
              latitude: place.geometry.location.lat,
              longitude: place.geometry.location.lng,
            }}
            title={place.name}
            description={place.vicinity}
          />
        ))}
      </MapView>
    </View>
  );
}
 
const styles = StyleSheet.create({
  container: { flex: 1 },
  map: { flex: 1 },
  status: { flex: 1, textAlign: 'center', marginTop: 100, fontSize: 16 },
});

期待する動作: 端末の現在地を中心に地図が表示され、500m 圏内のカフェが赤いピンでマーキングされます。ピンをタップすると店名と住所のポップアップが現れます。

実装でつまずきやすい2つのポイント

ZERO_RESULTS または REQUEST_DENIED が返ってくる場合: API キーの取得だけでは足りません。Google Cloud の課金アカウントが有効になっていないと、正しいキーを使っていてもリクエストが弾かれます。Google Cloud Console の「お支払い」から課金アカウントをリンクし、Places API が「有効」ステータスになっているかを確認してください。無料枠があるので実費が発生するわけではありませんが、アカウントの紐付けは必須です。

Android で地図が白紙になる場合: PROVIDER_GOOGLE を使った MapView は、Android では google-services.json がプロジェクトルートに存在していることが求められます。Rork でビルドする際にこのファイルが配置されていないと、エラーメッセージなしに白紙の画面が表示されます。iOS では同様の問題は起きにくいですが、Android 向けにビルドする場合は事前に確認しておくと安心です。

位置情報アプリの詳細な実装パターンについては、Rork の外部 API 連携ガイドも参考にしてみてください。地図以外の外部サービスとの連携にも応用できる考え方がまとまっています。

アプリをさらに発展させるアイデア

このチュートリアルで作った「近くのカフェを地図に表示するアプリ」は、そのままリリースできる MVP として使えます。次のステップとして試してみると面白いと思うものをいくつか挙げます。

カテゴリ切り替えボタン(カフェ/レストラン/コンビニ)を追加すると、汎用性が大幅に上がります。type パラメーターを変えるだけなので実装は簡単です。

お気に入り登録機能については、Supabase を使ったスポット共有アプリの実装例が参考になります。友人とリストを共有する機能も視野に入るかもしれません。

また、place_id を使って Places API の詳細エンドポイントを叩くと、写真・営業時間・評価・電話番号も取得できます。詳細画面まで作り込むと、リリースできるアプリに近づきます。

全体を振り返って

今日試してみるとしたら、まず Google Cloud Console で API キーを取得して課金アカウントをリンクし、このコードをそのまま Rork に貼り付けてみてください。実際に自分のいる場所の周辺にピンが立つ様子を見ると、次にやりたいことが自然と浮かんできます。

位置情報アプリは、使う人が「いまいる場所」を起点にするため、リアルな体験と直結します。ぜひ動かしてみてください。

シェア

お読みいただきありがとうございます

Rork Lab は広告なしで運営しており、サーバー費用などの運営コストはメンバーシップのご支援で賄っています。実装コード・ベンチマーク・本番設計パターンなど、実務でお役立ていただける記事を毎日更新しています。もし読んでよかったと感じていただけましたら、ぜひご覧ください。

  • コピー&ペーストで使える実装コード付き
  • 毎日新しい上級ガイドを追加
  • ¥580/月 または ¥2,480 の永久アクセス
メンバーシップを見る →

もしこの記事がお役に立ちましたら、チップ(¥150)で応援いただけると大変励みになります。広告なしでの運営を続けるため、皆さまのご支援が大きな力になっています。

関連記事

開発ツール2026-09-01
expo-paste-input で画像を貼り付けられる入力欄を作り、消える file:// を documents へ逃がす
チャット入力に画像やGIFを貼り付けられるようにする expo-paste-input の実装手順です。onPaste が返す file:// は一時ファイルで、送信までの間に消えることがあります。保存先を移す実装と、実機で確かめる順番をまとめました。
開発ツール2026-08-31
画面ロックから3分後、expo-audio の環境音は静かに止まっていました
expo-audio の音が画面ロックで止まる原因を、ビルド設定・オーディオセッション・ロック画面連携の三層に分けて切り分けます。Android で約3分後に止まるのは、ドキュメントに書かれた止まり方です。
開発ツール2026-08-24
ダークモードの確認を DevTools に寄せて、実機で見るべき場所が4か所に減りました
Expo SDK 57 の React Native DevTools に入ったライト/ダークのエミュレーションで、端末設定の往復をやめました。差し替わるのは JS が報告する値だけで、実機でしか確認できない場所が残ります。その境界を1画面で切り分ける方法をまとめました。
📚RECOMMENDED BOOKS
大規模言語モデル入門
山田育矢
LLM開発
生成AIプロンプトエンジニアリング入門
我妻幸長
プロンプト
Claude CodeによるAI駆動開発入門
平川知秀
AI駆動開発
※ アフィリエイトリンクを含みます
もっと見る →