RORK LABEN
TOOLING — Rorkの開発者向けリポジトリが動き続けています。rork-xcodeが7月16日、rork-deviceが7月15日、rork-plistが7月13日に更新されましたOPUS46 — RorkでClaude Opus 4.6が稼働しています。Rork MaxはClaude Codeを土台にアプリを組み立てる設計ですSIM — ブラウザ上で動くクラウドのiOSシミュレータを備え、実機へのインストールは1クリック、App Storeへの提出は2クリックと案内されていますMAX — Rork MaxはReact Nativeではなく純粋なSwiftを出力します。iPhone・iPad・Apple Watch・Apple TV・Vision Pro、そしてiMessageまでが射程ですNATIVE — HealthKit、ARKitとLiDAR、NFC、Dynamic Island、Live Activities、Metalによる3D、Core MLのオンデバイス推論まで扱えますSEED — RorkはLeft Lane Capitalが主導する1,500万ドルのシードラウンドを実施し、Peak XVとa16z Speedrunが参加しましたTOOLING — Rorkの開発者向けリポジトリが動き続けています。rork-xcodeが7月16日、rork-deviceが7月15日、rork-plistが7月13日に更新されましたOPUS46 — RorkでClaude Opus 4.6が稼働しています。Rork MaxはClaude Codeを土台にアプリを組み立てる設計ですSIM — ブラウザ上で動くクラウドのiOSシミュレータを備え、実機へのインストールは1クリック、App Storeへの提出は2クリックと案内されていますMAX — Rork MaxはReact Nativeではなく純粋なSwiftを出力します。iPhone・iPad・Apple Watch・Apple TV・Vision Pro、そしてiMessageまでが射程ですNATIVE — HealthKit、ARKitとLiDAR、NFC、Dynamic Island、Live Activities、Metalによる3D、Core MLのオンデバイス推論まで扱えますSEED — RorkはLeft Lane Capitalが主導する1,500万ドルのシードラウンドを実施し、Peak XVとa16z Speedrunが参加しました
記事一覧/Rork入門
Rork入門/2026-04-05中級

Rork でマッチングアプリを作る:スワイプUIとチャット機能の実装チュートリアル

Rork を使ってマッチングアプリを作る方法を解説。スワイプUIの実装、Supabase を使ったマッチング判定、リアルタイムチャット機能まで、ステップバイステップで紹介します。

マッチングアプリスワイプUISupabase33React Native209チュートリアル23

マッチングアプリは、現代で最も需要の高いアプリカテゴリーのひとつです。「いいね」「スキップ」のスワイプ操作、マッチング通知、そしてリアルタイムチャット——これらを個人開発で実現するのは難しそうに感じるかもしれません。しかし、Rork を使えば、コーディング経験が少なくてもマッチングアプリの核となる機能を構築できます。

このチュートリアルで作るもの

  • ユーザープロフィールカードのスワイプUI(右スワイプ=いいね、左スワイプ=スキップ)
  • 相互にいいねした際のマッチング判定
  • マッチング相手とのリアルタイムチャット(Supabase Realtime)
  • プロフィール画像のアップロード(Supabase Storage)

前提知識と環境準備

このチュートリアルを進めるには、以下が必要です。

  • Rork アカウント(無料プランでも開始可能)
  • Supabase アカウント(無料枠あり)
  • React Native の基本的な理解(必須ではないが、あると理解が深まります)

Rork の基本的な使い方がまだわからない方は、まず Rork 入門:ゼロからアプリを作る方法 を先にご覧ください。

Supabase プロジェクトの初期設定

Supabase でデータベースを構築します。マッチングアプリに必要なテーブルは次の3つです。

  • profiles:ユーザープロフィール(名前、年齢、自己紹介、画像URL)
  • swipes:スワイプの記録(誰が誰を「いいね」or「スキップ」したか)
  • matches:マッチしたペアの記録
  • messages:チャットメッセージ

以下の SQL を Supabase の SQL Editor で実行してください。

-- プロフィールテーブル
create table profiles (
  id uuid references auth.users primary key,
  name text not null,
  age integer,
  bio text,
  avatar_url text,
  created_at timestamptz default now()
);
 
-- スワイプ記録テーブル
create table swipes (
  id uuid default gen_random_uuid() primary key,
  swiper_id uuid references profiles(id),
  swiped_id uuid references profiles(id),
  direction text check (direction in ('like', 'pass')),
  created_at timestamptz default now(),
  unique(swiper_id, swiped_id)
);
 
-- マッチテーブル
create table matches (
  id uuid default gen_random_uuid() primary key,
  user1_id uuid references profiles(id),
  user2_id uuid references profiles(id),
  created_at timestamptz default now()
);
 
-- メッセージテーブル
create table messages (
  id uuid default gen_random_uuid() primary key,
  match_id uuid references matches(id),
  sender_id uuid references profiles(id),
  body text not null,
  created_at timestamptz default now()
);
 
-- Realtime を有効にする
alter publication supabase_realtime add table messages;

実行後、Supabase ダッシュボードの「Authentication」→「Policies」でそれぞれのテーブルに適切な Row Level Security(RLS)ポリシーを設定します。

スワイプUIの実装

Rork にプロジェクトを作成したら、スワイプUIのプロンプトを入力します。Rork はプロンプトから React Native のコードを生成してくれます。

Rork へのプロンプト例

マッチングアプリのスワイプ画面を作ってください。
- 画面中央にプロフィールカード(写真、名前、年齢、自己紹介)を表示
- 右スワイプで「いいね」、左スワイプで「スキップ」
- React Native Gesture Handler を使ったスムーズなアニメーション
- カード下部に「❌ スキップ」「❤️ いいね」ボタンも配置
- Supabase から profiles テーブルのデータを取得して表示

Rork が生成するコードの骨格はこのようになります。

// screens/SwipeScreen.tsx(Rork 生成コードの例)
import { PanGestureHandler } from 'react-native-gesture-handler';
import Animated, {
  useAnimatedGestureHandler,
  useAnimatedStyle,
  useSharedValue,
  withSpring,
  runOnJS,
} from 'react-native-reanimated';
 
export function SwipeScreen() {
  const translateX = useSharedValue(0);
  const translateY = useSharedValue(0);
 
  const gestureHandler = useAnimatedGestureHandler({
    onActive: (event) => {
      translateX.value = event.translationX;
      translateY.value = event.translationY;
    },
    onEnd: (event) => {
      if (event.translationX > 100) {
        // 右スワイプ:いいね
        runOnJS(handleLike)();
      } else if (event.translationX < -100) {
        // 左スワイプ:スキップ
        runOnJS(handlePass)();
      }
      translateX.value = withSpring(0);
      translateY.value = withSpring(0);
    },
  });
 
  return (
    <PanGestureHandler onGestureEvent={gestureHandler}>
      <Animated.View style={[styles.card, animatedStyle]}>
        {/* プロフィールカードの内容 */}
      </Animated.View>
    </PanGestureHandler>
  );
}

マッチング判定ロジック

スワイプ後、Supabase に記録して相互いいねを確認します。

// utils/swipe.ts
import { supabase } from './supabase';
 
export async function handleSwipe(
  swiperId: string,
  swipedId: string,
  direction: 'like' | 'pass'
) {
  // スワイプを記録
  await supabase.from('swipes').insert({
    swiper_id: swiperId,
    swiped_id: swipedId,
    direction,
  });
 
  if (direction === 'like') {
    // 相手からのいいねが既にあるか確認
    const { data } = await supabase
      .from('swipes')
      .select('id')
      .eq('swiper_id', swipedId)
      .eq('swiped_id', swiperId)
      .eq('direction', 'like')
      .single();
 
    if (data) {
      // 相互いいね → マッチング成立
      await supabase.from('matches').insert({
        user1_id: swiperId,
        user2_id: swipedId,
      });
      return { matched: true };
    }
  }
 
  return { matched: false };
}

マッチング成立時は「マッチしました!」のモーダルを表示し、チャット画面へ誘導します。

リアルタイムチャットの実装

マッチングが成立したら、相手とのチャットが解放されます。Supabase Realtime を使うことで、メッセージがリアルタイムに双方の画面に届く仕組みを実現できます。

// screens/ChatScreen.tsx
import { useEffect, useState } from 'react';
import { supabase } from '../utils/supabase';
 
export function ChatScreen({ matchId }: { matchId: string }) {
  const [messages, setMessages] = useState([]);
 
  useEffect(() => {
    // 既存メッセージを取得
    fetchMessages();
 
    // Realtime サブスクリプション
    const channel = supabase
      .channel(`match:${matchId}`)
      .on(
        'postgres_changes',
        {
          event: 'INSERT',
          schema: 'public',
          table: 'messages',
          filter: `match_id=eq.${matchId}`,
        },
        (payload) => {
          // 新メッセージをリアルタイム反映
          setMessages((prev) => [...prev, payload.new]);
        }
      )
      .subscribe();
 
    return () => supabase.removeChannel(channel);
  }, [matchId]);
 
  const sendMessage = async (body: string) => {
    await supabase.from('messages').insert({
      match_id: matchId,
      sender_id: currentUserId,
      body,
    });
    // Realtime で自動的に相手側に届く
  };
 
  return (
    // チャット UI
  );
}

チャット機能をさらに深掘りしたい方は、Rork でリアルタイムチャットアプリを構築する完全ガイド も参考にしてください。

プロフィール画像のアップロード

ユーザーが自分の写真を登録できる機能も重要です。Supabase Storage を使います。

// utils/uploadAvatar.ts
import * as ImagePicker from 'expo-image-picker';
import { supabase } from './supabase';
import { decode } from 'base64-arraybuffer';
 
export async function uploadAvatar(userId: string): Promise<string | null> {
  const result = await ImagePicker.launchImageLibraryAsync({
    mediaTypes: ImagePicker.MediaTypeOptions.Images,
    allowsEditing: true,
    aspect: [1, 1], // 正方形にトリミング
    quality: 0.8,
    base64: true,
  });
 
  if (result.canceled || !result.assets[0].base64) return null;
 
  const fileName = `avatars/${userId}-${Date.now()}.jpg`;
 
  const { error } = await supabase.storage
    .from('profiles')
    .upload(fileName, decode(result.assets[0].base64), {
      contentType: 'image/jpeg',
      upsert: true,
    });
 
  if (error) throw error;
 
  const { data } = supabase.storage.from('profiles').getPublicUrl(fileName);
  return data.publicUrl;
}

よくあるエラーと対処法

マッチングアプリ開発で遭遇しやすいエラーとその対処法を紹介します。

RLS ポリシーエラー(403 Forbidden)

Supabase で「permission denied for table swipes」などのエラーが出た場合は、RLS ポリシーが未設定か、設定が不正確です。Supabase ダッシュボードの「Authentication → Policies」で、ログイン中のユーザーが自分のデータを読み書きできるポリシーを追加してください。

スワイプアニメーションがカクつく

react-native-reanimatedrunOnUI / runOnJS の呼び分けを確認してください。UI スレッドで実行すべき処理を JS スレッドで行うとカクつきの原因になります。

Supabase Realtime が機能しない

alter publication supabase_realtime add table messages; の SQL を実行しているか確認してください。これを忘れると Realtime のイベントが発火しません。

全体を振り返って

Rork を使えば、スワイプUI・マッチング判定・リアルタイムチャットという、マッチングアプリの核心機能を比較的短期間で構築できます。まずは Supabase でデータ設計を固め、Rork にプロンプトを入力しながらUIを組み上げていくのが最も効率的なアプローチです。

マッチングアプリはプッシュ通知・位置情報・プレミアム課金など、拡張要素も豊富です。MVP(最小限のプロダクト)から始めて、ユーザーの反応を見ながら機能を追加していきましょう。

個人開発でアプリをリリースして収益化する方法については、React Native × Expo アーキテクチャ完全ガイド も参考にしてください。

シェア

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

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

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

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

関連記事

Rork 入門2026-04-19
Rorkで服薬管理アプリを作る — 毎日の薬を飲み忘れないための仕組みをAIで実装する
Rorkを使って服薬管理アプリを作る手順を解説します。薬の登録・服用チェック・リマインダー通知・家族共有まで、プログラミング知識なしで実装できる実践ガイドです。
Rork 入門2026-04-19
Rork で旅行計画アプリを作る — 行き先・スケジュール・持ち物リストを1つに
Rork を使って旅行計画アプリを作るチュートリアルです。行き先一覧・日程スケジュール・持ち物チェックリストを1アプリに統合する方法をプロンプト例とともに解説します。
Rork 入門2026-03-31
Rork で作る睡眠トラッカーアプリ完全チュートリアル — 就寝・起床時刻の記録から睡眠スコア分析まで
Rork を使って睡眠トラッカーアプリを作る完全チュートリアル。就寝・起床時刻の記録、睡眠スコア計算、グラフ表示まで、初心者でも30分で動くアプリが完成します。
📚RECOMMENDED BOOKS
大規模言語モデル入門
山田育矢
LLM開発
生成AIプロンプトエンジニアリング入門
我妻幸長
プロンプト
Claude CodeによるAI駆動開発入門
平川知秀
AI駆動開発
※ アフィリエイトリンクを含みます
もっと見る →