feat(mobile): スマホアプリのネイティブ化 — Capacitor 8 + 買い切りIAP実配線 + iOS/Android CI#9
feat(mobile): スマホアプリのネイティブ化 — Capacitor 8 + 買い切りIAP実配線 + iOS/Android CI#91llum1n4t1s wants to merge 4 commits into
Conversation
- Capacitor 6→8 アップグレード(@capacitor/* 8.4.1・app8.1/preferences8.0)。保守される IAP プラグインが Cap8 必須のため。mobile はネイティブ未ビルド=アップグレードの好機。 - iap.js: @capgo/native-purchases(StoreKit2/Play Billing 直叩き・外部SaaS不要)で initIap/purchase/restore を実配線。所有判定は iOS=currentEntitlements・Android= purchaseState"1"&acknowledged。ストア照会結果を Preferences にキャッシュ(オフライン即時表示)。 web(dev)は従来の localStorage 解錠(本番は import.meta.env.DEV で dead code=バイパス防止)。 - main.js: onBuy を未解錠時に「解禁」と誤表示しないよう堅牢化。QRカメラのコメントを 「iOS 14.3+ で getUserMedia 動作・barcode-scanner 差し替え不要」と確認した内容へ更新。 - README: Cap8/IAP配線/CI を実態に更新。 回帰: _sync_repro 223 / _mobile_crud_repro 15 / _mobile_sync_repro 9(実relay e2e)緑。 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- mobile-android.yml: Cap8 テンプレが JavaVersion.VERSION_21 を使うため JDK 17→21。 AndroidManifest へ CAMERA(QRスキャナ)に加え BILLING(@Capgo課金)も注入。 - mobile-ios.yml(新規): macOS・SPM。cap add ios→Info.plist へ NSCameraUsageDescription 注入→署名なし simulator コンパイル検証。実機.ipa/署名/申請は証明書投入後。 Cap8 は Xcode26+ 要求=runner の Xcode 次第。 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (2)
✅ Files skipped from review due to trivial changes (1)
🚧 Files skipped from review as they are similar to previous changes (1)
📝 WalkthroughSummary by CodeRabbitリリースノート
ウォークスルーCapacitor 6から8へ依存を更新し、 変更内容Capacitor 8アップグレード&ネイティブIAP&CI/CD対応
シーケンス図sequenceDiagram
participant UI as main.js (onBuy)
participant IAP as iap.js
participant Plugin as `@capgo/native-purchases`
participant Prefs as Capacitor Preferences
UI->>IAP: initIap()
IAP->>Prefs: キャッシュ読み込み → _unlocked即時反映
IAP->>Plugin: getPurchases({onlyCurrentEntitlements: true})
Plugin-->>IAP: purchases[]
IAP->>IAP: queryOwned() で PRODUCT_ID 所有判定
IAP->>Prefs: 解錠キャッシュ書き込み
UI->>IAP: purchase()
IAP->>Plugin: purchaseProduct(PRODUCT_ID)
Plugin-->>IAP: result
IAP->>IAP: 成立確認、不確実時はqueryOwned()で再確定
IAP->>Prefs: 解錠キャッシュ書き込み
IAP-->>UI: ok: true / false
alt ok === false
UI->>UI: 「購入が確認できませんでした。」表示して早期リターン
else ok === true
UI->>UI: renderPairing() + 解禁メッセージ表示
end
関連する可能性のあるPR
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Code Review
This pull request upgrades Capacitor to version 8 and implements native In-App Purchases (IAP) for a non-consumable product using @capgo/native-purchases, complete with offline caching via Capacitor Preferences. The review feedback highlights three critical issues in the IAP implementation: a potential type mismatch when validating the Android purchase state (comparing numeric 1 with string "1"), a security risk where pending or deferred transactions (such as "Ask to Buy") could bypass validation, and an issue where temporary billing support check failures would overwrite the offline cache and lock out valid users.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
There was a problem hiding this comment.
Actionable comments posted: 4
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.github/workflows/mobile-ios.yml:
- Line 20: The runs-on field in the mobile-ios.yml workflow uses macos-latest
which can change Xcode versions unpredictably when GitHub updates the runner
image, making it impossible to guarantee the Xcode 26+ requirement mentioned
elsewhere in the workflow. Replace the runs-on: macos-latest value with a
specific macOS version runner (such as macos-14 or macos-13) that consistently
provides the required Xcode 26+ version, or alternatively add an explicit Xcode
version pinning step in the workflow to ensure reproducibility and meet the
stated Xcode requirements.
- Line 38: Replace the `dangerouslyAllowAllBuilds=true` configuration in the
pnpm install command (line 38 of mobile-ios.yml) with the
`onlyBuiltDependencies` based allowlist approach that is already implemented in
the pnpm-workspace.yaml configuration file. Apply the same pattern fix to
mobile-android.yml to ensure both mobile workflows use the consistent, more
secure dependency build script execution policy instead of allowing all builds.
In `@mobile/src/iap.js`:
- Around line 113-119: The purchase success determination on line 115 uses a
ternary operator that bypasses the strict ownership verification in queryOwned()
when the tx exists and productIdentifier matches PRODUCT_ID. Instead of the
conditional ok ? true : await queryOwned() logic, always call queryOwned() to
ensure the final ownership confirmation is performed regardless of the initial
productIdentifier check. This ensures that strict verification conditions (such
as PENDING status and acknowledgement completion on Android) are always
validated before setting _unlocked to true and saving to the cache.
- Around line 61-64: The Android ownership check in the Capacitor platform
branch uses a loose validation for the isAcknowledged property that allows
undefined values to pass through, violating Google Play Billing requirements. In
the condition that checks both purchaseState and isAcknowledged, change the
`p.isAcknowledged !== false` check to strictly require the acknowledged status
by checking for `p.isAcknowledged === true` instead. This ensures that only
explicitly acknowledged purchases are considered valid, preventing
unacknowledged purchases from being treated as owned.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: bdf24111-915d-4fa1-a129-141583f9550c
⛔ Files ignored due to path filters (1)
mobile/pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (6)
.github/workflows/mobile-android.yml.github/workflows/mobile-ios.ymlmobile/README.mdmobile/package.jsonmobile/src/iap.jsmobile/src/main.js
iap.js(課金): - Android 所有判定: purchaseState は数値 1 / 文字列 "1" / "PURCHASED" を許容、isAcknowledged は厳密 true を 要求(!==false は undefined を通し、3日で自動払戻しされる未承認購入を所有扱いにする穴)。 - purchase: productIdentifier 一致では解錠せず必ず queryOwned() で確定(iOS Ask to Buy 等の deferred を 未承認のまま解禁しない)。 - isBillingSupported の throw を握り潰さず伝播=initIap が catch して Preferences キャッシュを維持 (一時障害/オフラインで購入者をロックアウトしない)。 CI: - mobile-ios.yml: runs-on を macos-latest→macos-15 固定(イメージ更新による Xcode 非決定性を排除)。 - 両 mobile CI: --config.dangerouslyAllowAllBuilds=true を廃し mobile/pnpm-workspace.yaml の allowBuilds(esbuild のみ)で許可。--ignore-workspace も外す(付けると allowBuilds が読まれず ignored builds)。 検証: vite build / _sync_repro 223 / _mobile_crud_repro 15 緑。 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
There was a problem hiding this comment.
🧹 Nitpick comments (1)
.github/workflows/mobile-android.yml (1)
45-46: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win
pnpm installは--frozen-lockfileを付けて再現性を固定してください。Line 46 はロックファイル差分をCIで見逃す可能性があるため、依存解決の非決定性を避ける設定にした方が安全です。
差分案
- name: Install deps - run: pnpm install + run: pnpm install --frozen-lockfile🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In @.github/workflows/mobile-android.yml around lines 45 - 46, In the Install deps step where pnpm install is executed, add the --frozen-lockfile flag to the run command to ensure dependency resolution is deterministic and prevent lockfile drift in CI. Update the pnpm install command to include --frozen-lockfile as an argument to guarantee reproducible builds and catch any unintended lockfile changes.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In @.github/workflows/mobile-android.yml:
- Around line 45-46: In the Install deps step where pnpm install is executed,
add the --frozen-lockfile flag to the run command to ensure dependency
resolution is deterministic and prevent lockfile drift in CI. Update the pnpm
install command to include --frozen-lockfile as an argument to guarantee
reproducible builds and catch any unintended lockfile changes.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 60dc6477-835f-44ea-8663-4298cff0ea6f
📒 Files selected for processing (4)
.github/workflows/mobile-android.yml.github/workflows/mobile-ios.ymlmobile/pnpm-workspace.yamlmobile/src/iap.js
✅ Files skipped from review due to trivial changes (1)
- mobile/pnpm-workspace.yaml
🚧 Files skipped from review as they are similar to previous changes (2)
- .github/workflows/mobile-ios.yml
- mobile/src/iap.js
…性固定) CodeRabbit nitpick 対応。両 mobile CI の install を frozen-lockfile 化=lockfile と package.json の不整合を CI で検出し、依存解決を再現可能にする。ローカルで通過確認済み。 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
概要
スマホアプリ(
mobile/)のネイティブ化を前進。Capacitor 6→8 アップグレード、買い切り IAP の実配線、iOS/Android ビルド CI 整備。実機ビルド・署名・ストア申請(ゆろ君の環境依存)以外を完了。変更
Capacitor 8 アップグレード(chore)
@capacitor/*を 8.4.1 系へ。保守される IAP プラグインが Cap8 必須(@Capgo も RevenueCat も peer>=8.0.0)かつ mobile はまだネイティブ未ビルド=アップグレードの好機。買い切り IAP 実配線(
src/iap.js)currentEntitlements(別 Apple ID 漏洩防止)/ Android=purchaseState"1"&acknowledged。ストア照会結果を Preferences にキャッシュ(オフライン即時表示)。import.meta.env.DEVで dead code 化=無課金バイパス防止。onBuyを未解錠時に「解禁」と誤表示しないよう堅牢化。iOS カメラ(調査で方針確定)
NSCameraUsageDescriptionを注入(Android の CAMERA 注入と対称)。CI
mobile-android.yml: JDK17→21(Cap8 が JavaVersion.VERSION_21)、AndroidManifest へ CAMERA + BILLING 注入。mobile-ios.yml(新規): macOS・SPM。cap add ios→Info.plist 注入→署名なし simulator コンパイル検証。検証
_sync_repro223 /_mobile_crud_repro15 /_mobile_sync_repro9(実 relay e2e・暗号化往復)すべて緑。vite build(Cap8)緑、cap add android(Cap8・minSdk24/compileSdk36/@Capgo 検出)緑。残(ゆろ君の環境/手作業)
jp.nephilim.petarin.sync(non-consumable・¥500)を App Store Connect / Play Console に登録。🤖 Generated with Claude Code