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が参加しました
記事一覧/開発ツール
開発ツール/2026-03-26上級

Rork Max × Server-Driven UI — バックエンドからUIをリアルタイム制御する次世代アーキテクチャ

Server-Driven UI(SDUI)をRork Maxで実装する方法を解説。バックエンドからUIコンポーネントをJSON定義で配信し、アプリ更新なしで画面レイアウトを動的に変更する設計パターンを紹介します。

rork-max41server-driven-uiarchitecture6react-native12dynamic-uibackend3JSONdesign-pattern

プレミアム記事

Server-Driven UI とは何か — なぜ今モバイル開発で注目されているのか

モバイルアプリ開発において、UI の変更のたびに App Store / Google Play の審査を待つという従来のリリースサイクルは、ビジネスのスピードとの間に大きなギャップを生んでいます。Server-Driven UI(SDUI)は、この課題を根本から解決するアーキテクチャです。

SDUI の核心はシンプルです。UI のレイアウト・構成・表示条件をサーバーサイドの JSON レスポンスとして定義し、クライアント(アプリ)はその JSON を解釈してコンポーネントをレンダリングするという設計パターンです。Airbnb、Shopify、Lyft といった大手テック企業がプロダクション環境で採用しており、A/B テストの即時切り替えやパーソナライズド UI の配信に活用されています。

Rork Max は React Native / Expo ベースのネイティブアプリを生成するため、SDUI パターンとの相性が非常に良好です。ここで扱うのはRork Max プロジェクトに SDUI を導入するための設計原則、JSON スキーマ、レンダリングエンジン、バックエンド構成までを体系的に解説します。

SDUI の設計原則 — 3つの基本レイヤー

SDUI アーキテクチャは以下の3層で構成されます。

レイヤー1: スキーマ定義層(Contract Layer)

サーバーとクライアント間の「契約」となる JSON スキーマを定義します。このスキーマが SDUI の要であり、慎重な設計が求められます。

// types/sdui.ts — SDUI コンポーネントの型定義
type SDUIComponentType =
  | 'hero_banner'
  | 'product_grid'
  | 'text_block'
  | 'cta_button'
  | 'carousel'
  | 'feature_list'
  | 'testimonial'
  | 'spacer';
 
interface SDUIComponent {
  id: string;
  type: SDUIComponentType;
  props: Record<string, unknown>;
  children?: SDUIComponent[];
  visibility?: {
    conditions: VisibilityCondition[];
    operator: 'AND' | 'OR';
  };
  analytics?: {
    impressionEvent: string;
    tapEvent: string;
  };
}
 
interface VisibilityCondition {
  field: string;        // 例: "user.plan", "device.platform"
  operator: 'eq' | 'neq' | 'gt' | 'lt' | 'in';
  value: string | number | string[];
}
 
// サーバーレスポンスのルート型
interface SDUIScreenResponse {
  screenId: string;
  version: number;
  ttl: number;          // キャッシュ有効期限(秒)
  components: SDUIComponent[];
  metadata: {
    title: string;
    analytics_screen_name: string;
  };
}

レイヤー2: レンダリングエンジン層(Rendering Layer)

JSON を受け取り、対応する React Native コンポーネントに変換するエンジンです。

// components/sdui/SDUIRenderer.tsx
import React from 'react';
import { View } from 'react-native';
import { HeroBanner } from './HeroBanner';
import { ProductGrid } from './ProductGrid';
import { TextBlock } from './TextBlock';
import { CTAButton } from './CTAButton';
import { Carousel } from './Carousel';
import { FeatureList } from './FeatureList';
 
// コンポーネントレジストリ — 新しいコンポーネントはここに追加するだけ
const COMPONENT_REGISTRY: Record<string, React.ComponentType<any>> = {
  hero_banner: HeroBanner,
  product_grid: ProductGrid,
  text_block: TextBlock,
  cta_button: CTAButton,
  carousel: Carousel,
  feature_list: FeatureList,
};
 
interface SDUIRendererProps {
  components: SDUIComponent[];
  context: UserContext;  // ユーザー情報(プラン・デバイス等)
}
 
export function SDUIRenderer({ components, context }: SDUIRendererProps) {
  return (
    <View style={{ flex: 1 }}>
      {components
        .filter((comp) => evaluateVisibility(comp.visibility, context))
        .map((comp) => {
          const Component = COMPONENT_REGISTRY[comp.type];
          if (!Component) {
            // 未知のコンポーネントは安全にスキップ(前方互換性)
            console.warn(`Unknown SDUI component: ${comp.type}`);
            return null;
          }
          return (
            <Component
              key={comp.id}
              {...comp.props}
              analytics={comp.analytics}
            >
              {comp.children && (
                <SDUIRenderer components={comp.children} context={context} />
              )}
            </Component>
          );
        })}
    </View>
  );
}
 
// 期待される出力: JSON 定義に応じたコンポーネントが動的にレンダリングされる
// 例: hero_banner → <HeroBanner title="..." />, product_grid → <ProductGrid items={[...]} />

レイヤー3: データ配信層(Delivery Layer)

バックエンドから JSON を配信し、クライアントがキャッシュ付きで取得する仕組みです。

// hooks/useSDUIScreen.ts — 画面データの取得とキャッシュ管理
import { useState, useEffect, useCallback } from 'react';
import AsyncStorage from '@react-native-async-storage/async-storage';
 
const SDUI_CACHE_PREFIX = 'sdui_cache_';
 
export function useSDUIScreen(screenId: string) {
  const [screen, setScreen] = useState<SDUIScreenResponse | null>(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState<Error | null>(null);
 
  const fetchScreen = useCallback(async () => {
    try {
      // 1. キャッシュを先にチェック(オフライン対応)
      const cached = await AsyncStorage.getItem(
        `${SDUI_CACHE_PREFIX}${screenId}`
      );
      if (cached) {
        const parsed = JSON.parse(cached);
        const isExpired =
          Date.now() - parsed.cachedAt > parsed.data.ttl * 1000;
        if (!isExpired) {
          setScreen(parsed.data);
          setLoading(false);
          return;
        }
      }
 
      // 2. サーバーから最新データを取得
      const response = await fetch(
        `https://api.example.com/sdui/screens/${screenId}`,
        {
          headers: {
            'X-App-Version': '2.1.0',
            'X-Platform': Platform.OS,
          },
        }
      );
      const data: SDUIScreenResponse = await response.json();
 
      // 3. キャッシュに保存
      await AsyncStorage.setItem(
        `${SDUI_CACHE_PREFIX}${screenId}`,
        JSON.stringify({ data, cachedAt: Date.now() })
      );
 
      setScreen(data);
    } catch (err) {
      setError(err as Error);
      // フォールバック: キャッシュが古くても表示する
      const cached = await AsyncStorage.getItem(
        `${SDUI_CACHE_PREFIX}${screenId}`
      );
      if (cached) {
        setScreen(JSON.parse(cached).data);
      }
    } finally {
      setLoading(false);
    }
  }, [screenId]);
 
  useEffect(() => {
    fetchScreen();
  }, [fetchScreen]);
 
  return { screen, loading, error, refetch: fetchScreen };
}

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

この記事の続きを読む

この先には、実装コードやベンチマーク結果など、実務でお役に立てる内容をご用意しています。このサイトは広告を掲載しておらず、サーバーや開発にかかる費用はメンバーの皆様のご支援で成り立っています。もしお役に立てていましたら、ご支援いただけますと大変ありがたいです。

この記事で得られること
Server-Driven UI の設計原則と JSON スキーマ定義を基礎から実装レベルまで理解できる
アプリストア審査なしで UI を即時更新するリリースフローを構築できる
Airbnb・Shopify が採用した SDUI パターンを Rork Max プロジェクトに応用する具体的手法を習得できる
Stripe による安全な決済 · いつでもキャンセル可能

この記事を購入する

この先の内容をすべてお読みいただけます。一度のご購入で、いつでも何度でもアクセスできます。このサイトは広告を掲載しておらず、皆さまのご支援がサーバー費用などの運営を支えています。

または
メンバーシップなら全記事が読み放題 →
シェア

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

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

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

関連記事

開発ツール2026-07-12
取り消しを押しても戻らない——編集履歴を安全に巻き戻すUndo/Redoの設計
状態を丸ごと保存するUndoは、数十手でメモリを圧迫します。コマンド履歴とスナップショットを使い分け、微調整の合体・上限・セッション跨ぎの永続化まで備えたUndo/Redoを、動くTypeScriptで設計します。
開発ツール2026-06-23
オフラインで書いた投稿が、復帰した瞬間にもう一つ増える——再送に強い送信アウトボックスの設計
永続キューで再送するだけでは、失われた応答が二重投稿を生みます。冪等キー・一時IDの付け替え・毒メッセージの隔離を備えた送信アウトボックスを、動くTypeScriptで設計します。
開発ツール2026-05-22
Rork Max のオブザーバビリティスタック設計 — Sentry・Crashlytics・Cloudflare Logs を一本化する個人開発者の運用知見
Rork Max で運用するアプリの障害検知・原因特定・収益保護を一気通貫で設計するオブザーバビリティスタックを、Sentry・Crashlytics・Cloudflare Logs の役割分担と障害シナリオ別の追跡経路を軸に解説します。
📚RECOMMENDED BOOKS
大規模言語モデル入門
山田育矢
LLM開発
生成AIプロンプトエンジニアリング入門
我妻幸長
プロンプト
Claude CodeによるAI駆動開発入門
平川知秀
AI駆動開発
※ アフィリエイトリンクを含みます
もっと見る →