ANTIGRAVITY LABEN
記事一覧/アプリ開発
アプリ開発/2026-04-05上級

Antigravity × Compose Multiplatform 実装ガイド:UI共有からDesktop対応まで、統合クロスプラットフォーム開発2026

Compose Multiplatform(CMP)と Antigravity AI IDE を組み合わせ、iOS・Android・Desktop のUI層を共有する高品質クロスプラットフォームアプリを構築する実践ガイド。設計パターン・Antigravity活用・自動テスト・リリースフローまでを網羅。

compose-multiplatformkotlin6ios35android27desktop2cross-platformantigravity435kmpcmp

取り組みの背景:Compose Multiplatform が変えるクロスプラットフォーム開発

Kotlin Multiplatform(KMP)がビジネスロジックの共有を実現したのに対し、Compose Multiplatform(CMP) は UI 層そのものを共有できる革命的なフレームワークです。JetBrains が開発した CMP を使えば、iOS・Android・Desktop(JVM)・Web(Wasm)のすべてで同一の Composable 関数を動作させることができます。

2026年現在、CMP は 1.7 系がリリースされ、iOS サポートが Production Stable に到達しました。Airbnb や Autodesk などの大企業も本番採用を進め、Flutter に代わる第一選択肢として注目を集めています。

そしてこの複雑な CMP の設定・実装・最適化を劇的に加速させるのが Google Antigravity です。Antigravity のエージェントは、Gradle のマルチモジュール構成、expect/actual パターン、iOS フレームワーク生成、さらには Compose の状態管理まで深く理解しています。

本記事は KMP の基礎知識がある中〜上級者向けに、CMP のプロダクション実装を Antigravity とともに習得するための完全ガイドです。Antigravity での CMP 基礎を学びたい方は、まず「Kotlin Multiplatform × Antigravity 完全ガイド」をご参照ください。


前提知識・環境準備

必要な知識

  • Kotlin の基礎文法(コルーチン・Flow の理解があれば理想的)
  • Jetpack Compose の基本(@ComposableStateViewModel の概念)
  • KMP の基本構造(commonMainandroidMainiosMain の役割)

開発環境

  • Antigravity(最新版)
  • Android Studio Meerkat 以降(Android ビルド確認用)
  • Xcode 26(iOS ビルド・シミュレータ確認用)
  • JDK 17 以上
  • Gradle 8.9 以上

Antigravity のターミナルで環境を確認します。

# JDK バージョン確認
java -version
# Gradle バージョン確認(wrapper 使用推奨)
./gradlew --version
# Kotlin バージョン確認
kotlinc -version

Compose Multiplatform の概念:KMP との違いを理解する

KMP と CMP の関係を正確に理解することが、設計ミスを防ぐ最初の一歩です。

KMP(Kotlin Multiplatform)

  • ビジネスロジック・データ層・ドメイン層の共有が主目的
  • UI は各プラットフォームのネイティブ(SwiftUI / Jetpack Compose)を使用
  • commonMain でインターフェースを定義し expect/actual でプラットフォーム実装を提供

CMP(Compose Multiplatform)

  • KMP の上位概念。UI 層まで含めて共有する
  • commonMain に書いた Composable がそのまま iOS・Android・Desktop で動作
  • プラットフォーム固有の UI が必要な箇所のみ expect/actual で差し替え

モジュール構成のベストプラクティス

Antigravity エージェントに「CMP のプロダクション向けモジュール構成を提案して」と依頼すると、以下のような構成を自動生成してくれます。

project/
├── composeApp/                  ← CMP メインモジュール
│   ├── src/
│   │   ├── commonMain/          ← 全プラットフォーム共通
│   │   │   ├── kotlin/
│   │   │   │   ├── ui/          ← 共有 Composable
│   │   │   │   ├── viewmodel/   ← 共有 ViewModel
│   │   │   │   └── di/          ← Koin DI 設定
│   │   │   └── resources/       ← 共有リソース
│   │   ├── androidMain/         ← Android 固有
│   │   ├── iosMain/             ← iOS 固有
│   │   └── desktopMain/         ← Desktop 固有
│   └── build.gradle.kts
├── shared/                      ← ビジネスロジック(純粋 KMP)
│   ├── src/
│   │   ├── commonMain/
│   │   ├── androidMain/
│   │   └── iosMain/
│   └── build.gradle.kts
└── settings.gradle.kts

この分離により、composeApp モジュールが UI 責務を、shared モジュールがビジネスロジックを担当する明確な境界を確立できます。


プロジェクトのセットアップ:Antigravity エージェントとの協働

KMP Wizard のセットアップ

kmp.jetbrains.com の Wizard で生成したテンプレートを Antigravity で開きます。Antigravity は .gradle.kts ファイルを開いた瞬間に依存関係を解析し、即座にコード補完とエラー検出を開始します。

Antigravity エージェントによる build.gradle.kts の設定

プロジェクトルートで以下のプロンプトを使うと、最新バージョンの CMP 依存関係を自動設定できます。

@agent
composeApp/build.gradle.kts を開いて、以下を設定してください:
- Compose Multiplatform 1.7.x の最新安定版
- Koin 4.x(DI)
- Ktor 3.x(ネットワーク)
- SQLDelight 2.x(ローカル DB)
- Coil 3.x(画像読み込み)
各バージョンは libs.versions.toml で一元管理してください。

Antigravity は libs.versions.toml(Version Catalog)を自動生成し、build.gradle.kts でのバージョン管理を一元化します。

# libs.versions.toml(Antigravity 生成例)
[versions]
compose-multiplatform = "1.7.0"
kotlin = "2.1.0"
koin = "4.0.0"
ktor = "3.0.3"
sqldelight = "2.0.2"
coil = "3.0.4"
 
[libraries]
compose-multiplatform = { module = "org.jetbrains.compose:compose-multiplatform-gradle-plugin", version.ref = "compose-multiplatform" }
koin-core = { module = "io.insert-koin:koin-core", version.ref = "koin" }
koin-compose = { module = "io.insert-koin:koin-compose", version.ref = "koin" }
ktor-client-core = { module = "io.ktor:ktor-client-core", version.ref = "ktor" }
ktor-client-darwin = { module = "io.ktor:ktor-client-darwin", version.ref = "ktor" }
ktor-client-okhttp = { module = "io.ktor:ktor-client-okhttp", version.ref = "ktor" }
sqldelight-runtime = { module = "app.cash.sqldelight:runtime", version.ref = "sqldelight" }
coil-compose = { module = "io.coil-kt.coil3:coil-compose", version.ref = "coil" }

共有 UI コンポーネントの実装パターン

Design Token による一貫したデザインシステム

commonMain に Design Token を定義することで、全プラットフォームで統一されたデザインを実現します。

// commonMain/kotlin/ui/theme/AppTheme.kt
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.darkColorScheme
import androidx.compose.material3.lightColorScheme
import androidx.compose.runtime.Composable
import androidx.compose.ui.graphics.Color
 
private val LightColors = lightColorScheme(
    primary = Color(0xFF0066FF),
    secondary = Color(0xFF6B9FFF),
    surface = Color(0xFFF8FAFF),
    background = Color(0xFFFFFFFF),
    onPrimary = Color.White,
    onSurface = Color(0xFF1A1A2E)
)
 
private val DarkColors = darkColorScheme(
    primary = Color(0xFF4D94FF),
    secondary = Color(0xFF9BB8FF),
    surface = Color(0xFF1A1A2E),
    background = Color(0xFF0D0D1A),
    onPrimary = Color.White,
    onSurface = Color(0xFFE8EEFF)
)
 
@Composable
fun AppTheme(
    darkTheme: Boolean = isSystemInDarkTheme(),
    content: @Composable () -> Unit
) {
    MaterialTheme(
        colorScheme = if (darkTheme) DarkColors else LightColors,
        content = content
    )
}

Antigravity の AI はシステムダークテーマの検出を expect/actual で実装するよう自動提案します。

Screen レベルの Composable 設計

CMP では画面単位のコンポーネントを commonMain に集約します。

// commonMain/kotlin/ui/screens/HomeScreen.kt
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import org.koin.compose.viewmodel.koinViewModel
 
@Composable
fun HomeScreen(
    viewModel: HomeViewModel = koinViewModel(),
    onNavigateToDetail: (String) -> Unit = {}
) {
    val uiState by viewModel.uiState.collectAsState()
 
    Scaffold(
        topBar = {
            TopAppBar(title = { Text("Compose Multiplatform") })
        }
    ) { paddingValues ->
        when (val state = uiState) {
            is HomeUiState.Loading -> {
                Box(
                    modifier = Modifier.fillMaxSize().padding(paddingValues),
                    contentAlignment = androidx.compose.ui.Alignment.Center
                ) {
                    CircularProgressIndicator()
                }
            }
            is HomeUiState.Success -> {
                LazyColumn(
                    modifier = Modifier.fillMaxSize().padding(paddingValues),
                    contentPadding = PaddingValues(16.dp),
                    verticalArrangement = Arrangement.spacedBy(8.dp)
                ) {
                    items(state.items) { item ->
                        ItemCard(item = item, onClick = { onNavigateToDetail(item.id) })
                    }
                }
            }
            is HomeUiState.Error -> {
                ErrorScreen(message = state.message, onRetry = viewModel::reload)
            }
        }
    }
}

このコードは 1つの Composable で iOS・Android・Desktop すべて動作します。


プラットフォーム固有処理の分離戦略

CMP の設計上最も重要なのが、expect/actual によるプラットフォーム固有処理の分離です。

expect/actual の設計原則

Antigravity にプロンプトを送ると、どの処理を commonMain に置き、どの処理を expect/actual で分離すべきかを自動判定します。

// commonMain: 共通インターフェース定義
expect class PlatformContext
 
expect fun getPlatformName(): String
 
expect fun openUrl(url: String)
 
// -- Android 実装 --
// androidMain:
actual class PlatformContext(val context: android.content.Context)
 
actual fun getPlatformName(): String = "Android ${android.os.Build.VERSION.RELEASE}"
 
actual fun openUrl(url: String) {
    // Android の Intent で外部ブラウザを開く
    val intent = android.content.Intent(
        android.content.Intent.ACTION_VIEW,
        android.net.Uri.parse(url)
    )
    intent.addFlags(android.content.Intent.FLAG_ACTIVITY_NEW_TASK)
    // context は Koin 経由で注入
}
 
// -- iOS 実装 --
// iosMain:
actual class PlatformContext
 
actual fun getPlatformName(): String =
    "iOS ${platform.UIKit.UIDevice.currentDevice.systemVersion}"
 
actual fun openUrl(url: String) {
    val nsUrl = platform.Foundation.NSURL.URLWithString(url) ?: return
    platform.UIKit.UIApplication.sharedApplication.openURL(
        nsUrl,
        options = emptyMap<Any?, Any?>(),
        completionHandler = null
    )
}
 
// -- Desktop 実装 --
// desktopMain:
actual class PlatformContext
 
actual fun getPlatformName(): String =
    "Desktop (${System.getProperty("os.name")} ${System.getProperty("os.version")})"
 
actual fun openUrl(url: String) {
    java.awt.Desktop.getDesktop().browse(java.net.URI(url))
}

カメラ・写真アクセスの実装

モバイルアプリではカメラや写真ライブラリへのアクセスが必要になるケースが多いです。Antigravity エージェントに「iOS・Android・Desktop のカメラアクセスを expect/actual で実装して」と依頼すると、moko-mediapeekaboo ライブラリを使った実装コードを自動生成します。

// commonMain
expect class ImagePicker {
    @Composable
    fun launch(onImageSelected: (ByteArray?) -> Unit)
}
 
// Android: ActivityResultContracts.PickVisualMedia を使用
// iOS: PHPickerViewController を使用
// Desktop: JFileChooser でファイル選択

Antigravity エージェント活用:CMP 開発効率化フロー

ViewModel の自動生成

Antigravity の最大の強みは、commonMain に配置可能な ViewModel の自動生成です。

@agent
HomeViewModel を作成してください。
- Ktor でAPIからアイテムリストを取得(URLは https://api.example.com/items)
- SQLDelight でローカルキャッシュを実装
- UiState は Loading/Success/Error の sealed class
- Koin で依存注入

Antigravity は上記プロンプトから、以下の構造を自動生成します。

  • HomeViewModel.kt(commonMain)
  • HomeUiState.kt(sealed class)
  • ItemRepository.kt(commonMain)
  • ItemRepositoryImpl.kt(commonMain、Ktor + SQLDelight 実装)
  • AppModule.kt(Koin モジュール)
  • HomeScreenTest.kt(unit test)

実際の出力コードには、Ktor のプラットフォーム別 Engine(OkHttp for Android / Darwin for iOS / CIO for Desktop)の設定も含まれています。

Compose Navigation の設定

CMP の Navigation は navigation-compose ライブラリで実装します。

// commonMain/kotlin/navigation/AppNavigation.kt
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.rememberNavController
import androidx.compose.runtime.Composable
 
sealed class Screen(val route: String) {
    object Home : Screen("home")
    object Detail : Screen("detail/{itemId}") {
        fun createRoute(itemId: String) = "detail/$itemId"
    }
    object Settings : Screen("settings")
}
 
@Composable
fun AppNavigation() {
    val navController = rememberNavController()
 
    NavHost(
        navController = navController,
        startDestination = Screen.Home.route
    ) {
        composable(Screen.Home.route) {
            HomeScreen(
                onNavigateToDetail = { itemId ->
                    navController.navigate(Screen.Detail.createRoute(itemId))
                }
            )
        }
        composable(Screen.Detail.route) { backStackEntry ->
            val itemId = backStackEntry.arguments?.getString("itemId") ?: return@composable
            DetailScreen(
                itemId = itemId,
                onBack = { navController.popBackStack() }
            )
        }
        composable(Screen.Settings.route) {
            SettingsScreen()
        }
    }
}

Desktop 対応:JVM Desktop ビルドの実践

CMP の大きな差別化点のひとつが、追加コストほぼゼロで Desktop アプリが生成できることです。

Desktop エントリポイントの設定

// desktopMain/kotlin/main.kt
import androidx.compose.ui.window.Window
import androidx.compose.ui.window.application
import androidx.compose.ui.window.rememberWindowState
import androidx.compose.ui.unit.dp
 
fun main() = application {
    val windowState = rememberWindowState(
        width = 1200.dp,
        height = 800.dp
    )
 
    Window(
        onCloseRequest = ::exitApplication,
        title = "My CMP App",
        state = windowState
    ) {
        // 共通の App Composable を呼び出すだけ
        AppTheme {
            AppNavigation()
        }
    }
}

Desktop 固有のメニューバー実装

Desktop では OS ネイティブのメニューバーを desktopMain に実装します。

// desktopMain/kotlin/main.kt(MenuBar 追加)
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.window.MenuBar
import kotlinx.coroutines.launch
 
Window(
    onCloseRequest = ::exitApplication,
    title = "My CMP App"
) {
    MenuBar {
        Menu("File", mnemonic = 'F') {
            Item("New", shortcut = KeyShortcut(Key.N, meta = true)) { /* ... */ }
            Item("Open", shortcut = KeyShortcut(Key.O, meta = true)) { /* ... */ }
            Separator()
            Item("Quit", shortcut = KeyShortcut(Key.Q, meta = true)) { exitApplication() }
        }
        Menu("Edit", mnemonic = 'E') {
            Item("Preferences") { /* ... */ }
        }
    }
    AppTheme { AppNavigation() }
}

Desktop 配布パッケージの生成

Antigravity は jpackage タスクを使った配布パッケージ生成も支援します。

# macOS 向け .dmg を生成
./gradlew :composeApp:packageDmg
 
# Windows 向け .msi を生成
./gradlew :composeApp:packageMsi
 
# Linux 向け .deb を生成
./gradlew :composeApp:packageDeb

生成された .dmg / .msi / .debcomposeApp/build/compose/binaries/ に出力されます。


テスト自動化戦略

commonMain の Unit テスト

CMP では commonTest に配置したテストが全プラットフォームで実行されます。

// commonTest/kotlin/viewmodel/HomeViewModelTest.kt
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertIs
import kotlinx.coroutines.test.runTest
 
class HomeViewModelTest {
 
    @Test
    fun `初期状態はLoadingであること`() = runTest {
        val fakeRepository = FakeItemRepository()
        val viewModel = HomeViewModel(fakeRepository)
 
        assertIs<HomeUiState.Loading>(viewModel.uiState.value)
    }
 
    @Test
    fun `アイテム取得成功時はSuccessStateになること`() = runTest {
        val fakeItems = listOf(
            Item(id = "1", title = "テストアイテム1"),
            Item(id = "2", title = "テストアイテム2")
        )
        val fakeRepository = FakeItemRepository(items = fakeItems)
        val viewModel = HomeViewModel(fakeRepository)
 
        viewModel.reload()
 
        val state = viewModel.uiState.value
        assertIs<HomeUiState.Success>(state)
        assertEquals(2, state.items.size)
    }
 
    @Test
    fun `API エラー時はErrorStateになること`() = runTest {
        val fakeRepository = FakeItemRepository(shouldThrow = true)
        val viewModel = HomeViewModel(fakeRepository)
 
        viewModel.reload()
 
        assertIs<HomeUiState.Error>(viewModel.uiState.value)
    }
}

Compose UI テスト(Android)

// androidTest での UI テスト
@RunWith(AndroidJUnit4::class)
class HomeScreenTest {
 
    @get:Rule
    val composeTestRule = createComposeRule()
 
    @Test
    fun ローディング中はインジケータが表示される() {
        composeTestRule.setContent {
            AppTheme {
                HomeScreen(viewModel = FakeLoadingViewModel())
            }
        }
        composeTestRule.onNodeWithTag("loadingIndicator").assertIsDisplayed()
    }
}

Antigravity エージェントは Fake の自動生成も行います。「HomeViewModel のテスト用 FakeRepository を作って」と依頼するだけで、適切なスタブが生成されます。


本番リリースフロー

iOS リリース(App Store)

CMP で生成された .xcframework を Xcode プロジェクトに組み込みます。

# iOS Framework 生成
./gradlew :composeApp:linkReleaseFrameworkIosArm64
 
# Xcode Archive → Validate → Distribute App
# Fastlane を使った自動化も可能

Antigravity の Fastlane 連携を使うと、以下のコマンド1つでビルドからアップロードまで完了します。

@agent
Fastlane の Appfile と Matchfile を設定して、
iOS の TestFlight 自動デプロイ lane を作成してください。
証明書は App Store Connect API キー認証を使用すること。

Android リリース(Google Play)

# AAB(Android App Bundle)生成
./gradlew :composeApp:bundleRelease
 
# 署名(keystore 使用)
jarsigner -verbose -sigalg SHA256withRSA \
  -digestalg SHA-256 \
  -keystore release.keystore \
  composeApp/build/outputs/bundle/release/composeApp-release.aab \
  release-key-alias

Desktop 配布(GitHub Releases)

# .github/workflows/desktop-release.yml(Antigravity 自動生成)
name: Desktop Release
 
on:
  push:
    tags:
      - 'v*'
 
jobs:
  build:
    strategy:
      matrix:
        os: [macos-latest, windows-latest, ubuntu-latest]
    runs-on: ${{ matrix.os }}
 
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-java@v4
        with:
          java-version: '17'
          distribution: 'temurin'
 
      - name: Build Desktop Package
        run: |
          if [ "${{ runner.os }}" == "macOS" ]; then
            ./gradlew :composeApp:packageDmg
          elif [ "${{ runner.os }}" == "Windows" ]; then
            ./gradlew :composeApp:packageMsi
          else
            ./gradlew :composeApp:packageDeb
          fi
        shell: bash
 
      - name: Upload Release Asset
        uses: actions/upload-artifact@v4
        with:
          name: desktop-${{ runner.os }}
          path: composeApp/build/compose/binaries/**/*

よくあるエラーと対処法

CMP 開発でよく遭遇するエラーと、Antigravity を使った解決策をまとめます。

エラー1: Unresolved reference: actual のコンパイルエラー

e: ... error: unresolved reference: PlatformContext

原因は expect 宣言に対応する actual が未実装なプラットフォームがある場合です。Antigravity にエラーメッセージをペーストすると、「desktopMainactual class PlatformContext が不足しています」と即座に指摘し、実装テンプレートを生成します。

エラー2: iOS ビルドで Framework not found エラー

Xcode のビルド設定で FRAMEWORK_SEARCH_PATHS$(SRCROOT)/../composeApp/build/cocoapods/framework/ を追加する必要があります。Antigravity は Podfile の設定ミスも検出します。

エラー3: Desktop で ClassNotFoundException が発生

Desktop ビルドでは Shadow JAR の設定が必要な場合があります。

// composeApp/build.gradle.kts
compose.desktop {
    application {
        mainClass = "MainKt"
        nativeDistributions {
            targetFormats(TargetFormat.Dmg, TargetFormat.Msi, TargetFormat.Deb)
            packageName = "MyApp"
            packageVersion = "1.0.0"
            // Desktop 固有の JVM オプション
            jvmArgs("-Xmx512m")
        }
    }
}

エラー4: iOS で画像リソースが表示されない

CMP の画像リソースは commonMain/composeResources/drawable/ に配置する必要があります。androidMain/res/drawable/ に置いても iOS では参照できません。Antigravity はリソースパスのミスを静的解析で検出します。


まとめ

Compose Multiplatform は、1つの Kotlin コードベースで iOS・Android・Desktop をカバーする、2026年最も注目すべきクロスプラットフォームフレームワークです。本記事で解説した主なポイントをまとめます。

  • モジュール構成: composeApp(UI共有)と shared(ビジネスロジック)の明確な分離
  • expect/actual: プラットフォーム固有処理の適切な分離と、Antigravity による自動生成
  • 共有 Composable: テーマ・Navigation・ViewModel を commonMain に集約
  • Desktop 対応: packageDmg / packageMsi / packageDeb でネイティブアプリを配布
  • テスト: commonTest に書いたテストが全プラットフォームで実行
  • リリースパイプライン: Fastlane + GitHub Actions で iOS/Android/Desktop を一括自動化

Antigravity の AI エージェントは CMP の複雑な設定を大幅に簡略化し、expect/actual の生成・テストのスタブ・ビルド設定の最適化を自動で行います。CMP と Antigravity の組み合わせは、個人開発者がひとつのコードベースで3プラットフォームをリリースするという目標を、かつてないほど現実的なものにしています。

CMP プロジェクトの状態管理をさらに深く理解したい方には、「Kotlin × Coroutines/Flow/Room/Hilt 完全ガイド」もあわせてご参照ください。

プロダクション実装に必要な知識が体系的にまとめられています。

シェア

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

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

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

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

関連記事

アプリ開発2026-07-03
ダウンロードサイズの逆行に提出直前で気づかないために — AAB/IPA のサイズ予算をエージェントの週次ゲートで守る
メディエーションSDKやアセットの追加で静かに膨らむダウンロードサイズに、bundletool と App Thinning レポートを使ったサイズ台帳・予算ゲート・増分の内訳特定で歯止めをかける設計をまとめます。
アプリ開発2026-06-22
壁紙ビューアのスライドショーとページ送りスクラバーを iOS から Android へ逆移植する — SnapHelper との双方向同期でつまずいた点
iOS 版の全画面壁紙ビューアにあったスライドショーと下部スクラバーを Android へ逆移植した実装記録。RecyclerView と SnapHelper で現在ページを確定させ、スクラバーと双方向同期し、自動送りとユーザー操作の競合を状態機械で解いた手順を Kotlin の動くコードで共有します。
アプリ開発2026-06-17
ダイアログが重なる前に止める — 課金・レビュー誘導・リワード広告を1か所のゲートで束ねる
ペイウォール・レビュー誘導・リワード広告が同じ瞬間に重なって出る不具合を、優先度つきの中央ゲートで根治した実装記録です。Antigravityのエージェントに散らばったshow()呼び出しの掃き出しを任せ、表示ポリシーは自分で握る線引きで進めました。
📚RECOMMENDED BOOKS
大規模言語モデル入門
山田育矢
LLM開発
生成AIプロンプトエンジニアリング入門
我妻幸長
プロンプト
Claude CodeによるAI駆動開発入門
平川知秀
AI駆動開発
※ アフィリエイトリンクを含みます
もっと見る →