reis-mobile 0.9.0 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (77) hide show
  1. package/.claude-plugin/marketplace.json +2 -2
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/CHANGELOG.md +20 -0
  4. package/README.md +46 -21
  5. package/THIRD_PARTY_NOTICES.md +33 -0
  6. package/agents/mobile-release-engineer.md +2 -0
  7. package/agents/mobile-staff-engineer.md +17 -3
  8. package/core/router/intent-detector.mjs +3 -2
  9. package/core/router/intents.mjs +51 -2
  10. package/package.json +1 -1
  11. package/skills/mobile-analytics/SKILL.md +55 -0
  12. package/skills/mobile-analytics/references/android.md +9 -0
  13. package/skills/mobile-analytics/references/flutter.md +10 -0
  14. package/skills/mobile-analytics/references/ios.md +9 -0
  15. package/skills/mobile-analytics/references/kotlin-multiplatform.md +8 -0
  16. package/skills/mobile-analytics/references/react-native.md +9 -0
  17. package/skills/mobile-auth/SKILL.md +55 -0
  18. package/skills/mobile-auth/references/android.md +10 -0
  19. package/skills/mobile-auth/references/flutter.md +9 -0
  20. package/skills/mobile-auth/references/ios.md +10 -0
  21. package/skills/mobile-auth/references/kotlin-multiplatform.md +9 -0
  22. package/skills/mobile-auth/references/react-native.md +9 -0
  23. package/skills/mobile-billing/SKILL.md +58 -0
  24. package/skills/mobile-billing/references/android.md +11 -0
  25. package/skills/mobile-billing/references/flutter.md +11 -0
  26. package/skills/mobile-billing/references/ios.md +11 -0
  27. package/skills/mobile-billing/references/kotlin-multiplatform.md +9 -0
  28. package/skills/mobile-billing/references/react-native.md +10 -0
  29. package/skills/mobile-ci/SKILL.md +49 -0
  30. package/skills/mobile-ci/references/android.md +8 -0
  31. package/skills/mobile-ci/references/fastlane/beta.md +75 -0
  32. package/skills/mobile-ci/references/fastlane/match.md +288 -0
  33. package/skills/mobile-ci/references/fastlane/release.md +113 -0
  34. package/skills/mobile-ci/references/fastlane/setup-fastlane.md +150 -0
  35. package/skills/mobile-ci/references/fastlane/snapshot.md +394 -0
  36. package/skills/mobile-ci/references/fastlane/xcode-cloud.md +110 -0
  37. package/skills/mobile-ci/references/flutter.md +8 -0
  38. package/skills/mobile-ci/references/ios.md +9 -0
  39. package/skills/mobile-ci/references/kotlin-multiplatform.md +8 -0
  40. package/skills/mobile-ci/references/react-native.md +8 -0
  41. package/skills/mobile-firebase/SKILL.md +3 -1
  42. package/skills/mobile-hardware/SKILL.md +58 -0
  43. package/skills/mobile-hardware/references/android.md +12 -0
  44. package/skills/mobile-hardware/references/flutter.md +10 -0
  45. package/skills/mobile-hardware/references/ios.md +11 -0
  46. package/skills/mobile-hardware/references/kotlin-multiplatform.md +9 -0
  47. package/skills/mobile-hardware/references/react-native.md +10 -0
  48. package/skills/mobile-migration/SKILL.md +66 -0
  49. package/skills/mobile-migration/references/android.md +9 -0
  50. package/skills/mobile-migration/references/flutter.md +10 -0
  51. package/skills/mobile-migration/references/ios.md +10 -0
  52. package/skills/mobile-migration/references/kotlin-multiplatform.md +9 -0
  53. package/skills/mobile-migration/references/react-native.md +10 -0
  54. package/skills/mobile-networking/SKILL.md +50 -0
  55. package/skills/mobile-networking/references/android.md +10 -0
  56. package/skills/mobile-networking/references/flutter.md +9 -0
  57. package/skills/mobile-networking/references/ios.md +10 -0
  58. package/skills/mobile-networking/references/kotlin-multiplatform.md +9 -0
  59. package/skills/mobile-networking/references/react-native.md +11 -0
  60. package/skills/mobile-notifications/SKILL.md +51 -0
  61. package/skills/mobile-notifications/references/android.md +10 -0
  62. package/skills/mobile-notifications/references/flutter.md +10 -0
  63. package/skills/mobile-notifications/references/ios.md +11 -0
  64. package/skills/mobile-notifications/references/kotlin-multiplatform.md +9 -0
  65. package/skills/mobile-notifications/references/react-native.md +10 -0
  66. package/skills/mobile-observability/SKILL.md +1 -1
  67. package/skills/mobile-offline-sync/SKILL.md +2 -0
  68. package/skills/mobile-privacy/SKILL.md +54 -0
  69. package/skills/mobile-privacy/references/android.md +10 -0
  70. package/skills/mobile-privacy/references/flutter.md +9 -0
  71. package/skills/mobile-privacy/references/ios.md +10 -0
  72. package/skills/mobile-privacy/references/kotlin-multiplatform.md +9 -0
  73. package/skills/mobile-privacy/references/react-native.md +9 -0
  74. package/skills/mobile-release/SKILL.md +1 -0
  75. package/skills/mobile-release/references/billing.md +2 -0
  76. package/skills/mobile-release/references/ci-cd.md +2 -0
  77. package/skills/mobile-security/SKILL.md +2 -0
@@ -0,0 +1,10 @@
1
+ # Authentication on Android
2
+
3
+ - Inspect the identity provider and resolved Credential Manager dependencies before choosing a sign-in API. Verify credential type and provider support on the app's OS/device range.
4
+ - Passkey registration/authentication exchanges server-generated request data and sends the response back for server verification. Validate the relying-party/domain association; a credential selector is not backend authorization.
5
+ - Give UI-bound credential/browser operations a valid host lifetime. Preserve attempt state across recreation as the SDK prescribes and distinguish user cancellation from invalid credentials.
6
+ - Coordinate logout with SDK credential/session state and the backend. Clearing a local credential preference does not revoke a remote session.
7
+ - Check [identity guides](../../mobile-android/references/identity.md) when restoring credentials or retrieving verified email; these features are separate from account merging.
8
+ - Test cancellation, no credential, provider unavailability, process recreation and account switching, including cached data isolation.
9
+
10
+ Official reference: [Credential Manager](https://developer.android.com/identity/credential-manager).
@@ -0,0 +1,9 @@
1
+ # Authentication in Flutter
2
+
3
+ - Inspect the installed provider plugin and the app's session state owner. Use its auth-state stream once at the appropriate lifetime; avoid separate login state in each screen.
4
+ - Verify native callback configuration on Android and iOS alongside Dart routing. A successful provider callback is not evidence the backend session was established.
5
+ - Restore secure credentials before making account-scoped requests; do not show another account's cached content while restoration is unresolved.
6
+ - Passkey support depends on the actual plugin and host versions. Trace its registration/assertion response to backend verification; do not replace this with a local biometric boolean.
7
+ - Cancel/dispose listeners and invalidate in-flight refresh/login results on logout. Test the session state owner separately from widget navigation, then test the native callback in a device build.
8
+
9
+ Reuse [Firebase Auth guidance](../../mobile-firebase/references/flutter/auth.md) when installed and [secure token storage](../../mobile-security/references/flutter/secure-token-store.md). Official reference: [Flutter app links](https://docs.flutter.dev/cookbook/navigation/set-up-app-links).
@@ -0,0 +1,10 @@
1
+ # Authentication on iOS
2
+
3
+ - Use the provider-supported AuthenticationServices flow. For browser login, verify `ASWebAuthenticationSession` ownership, presentation context and callback configuration for the installed SDK/deployment target.
4
+ - For passkeys, configure the associated domain/relying party and verify responses on the server. Model cancellation, missing credentials and recovery explicitly.
5
+ - Treat Sign in with Apple identifiers and credentials through the provider contract. Do not depend on receiving profile fields on every sign-in, or equate a relay email with authority to merge accounts.
6
+ - Inspect Keychain accessibility and access groups against foreground/background needs. Keychain presence alone does not prove the server session is valid; define behavior across reinstall/account change.
7
+ - Guard shared refresh state across suspension points; invalidate late completions when the account changes.
8
+ - Test cancellation, return from browser, restored session, unavailable credentials and reauthentication with a configured test account.
9
+
10
+ Official references: [AuthenticationServices](https://developer.apple.com/documentation/authenticationservices), [ASWebAuthenticationSession](https://developer.apple.com/documentation/authenticationservices/aswebauthenticationsession).
@@ -0,0 +1,9 @@
1
+ # Authentication in Kotlin Multiplatform
2
+
3
+ - Share session models and backend exchanges where appropriate; host apps own browser presentation, credential prompts, secure storage and callback registration.
4
+ - Define typed results for success, cancellation, reauthentication and failure at the host boundary. A shared caller must not infer success because a native sheet closed.
5
+ - Use one session coordinator across shared callers. An actor/mutex boundary still needs session-generation checks after suspended backend operations.
6
+ - Never put a client secret or native UI dependency in `commonMain`. Passkeys still require backend challenges and verification; expose platform ceremonies through interfaces/target implementations.
7
+ - Test shared transition/race logic in `commonTest`; verify Android credential and iOS browser/passkey flows separately using [Android](android.md) and [iOS](ios.md).
8
+
9
+ Official reference: [Kotlin platform-specific declarations](https://kotlinlang.org/docs/multiplatform/multiplatform-expect-actual.html).
@@ -0,0 +1,9 @@
1
+ # Authentication in React Native and Expo
2
+
3
+ - Reuse the existing provider/auth library and secure native storage. Check callback schemes, app links and build configuration in both hosts, including Expo config plugins where used.
4
+ - In Expo, check the installed AuthSession/provider integration and test in a development build with the actual redirect. Do not assume Expo Go reproduces production schemes or native passkey support.
5
+ - Let the session owner coordinate refresh; a component remount must not start a second independent renewal. Abort or invalidate the old account's requests before clearing query caches and exposing another account.
6
+ - Native passkey APIs need a supported bridge and a server ceremony. JS token parsing or a biometric result cannot substitute for server verification.
7
+ - Test cancellation and linking conflicts in state logic, then callback routing and secure storage in a native build. Check startup before the navigation container becomes ready.
8
+
9
+ Official references: [Expo authentication](https://docs.expo.dev/guides/authentication/), [React Native security](https://reactnative.dev/docs/security). Reuse [Firebase Auth](../../mobile-firebase/references/react-native/auth.md) when that provider is installed.
@@ -0,0 +1,58 @@
1
+ ---
2
+ name: mobile-billing
3
+ description: Implements and reviews in-app purchases and subscriptions across Flutter, Android, iOS, React Native and Kotlin Multiplatform. Use for product catalogs, purchase and restore flows, pending or interrupted purchases, server-side verification, acknowledgement, account binding, plan changes and store sandbox tests. Store submission belongs to mobile-release; account deletion to mobile-privacy.
4
+ intents: [billing]
5
+ stacks: ["*"]
6
+ ---
7
+
8
+ # Mobile Billing
9
+
10
+ Trace each purchase from the product query to the entitlement your backend records. Reuse the [project brief](../../docs/agent-context.md), then inspect the billing client setup, the purchase listener, the backend verification endpoint and every screen that reads entitlement before changing a flow. The store-side lifecycle (subscription states, server notifications, acknowledgement deadlines, sandbox tools) is in the [billing lifecycle reference](../mobile-release/references/billing.md); this skill applies it to the app's code.
11
+
12
+ ## Pick the reference
13
+
14
+ | Project | Read |
15
+ |---|---|
16
+ | Flutter | [references/flutter.md](references/flutter.md) |
17
+ | Android | [references/android.md](references/android.md) |
18
+ | iOS | [references/ios.md](references/ios.md) |
19
+ | React Native / Expo | [references/react-native.md](references/react-native.md) |
20
+ | Kotlin Multiplatform | [references/kotlin-multiplatform.md](references/kotlin-multiplatform.md) |
21
+
22
+ Flutter and React Native apps also need the Android and iOS references for store configuration and native behavior. Confirm the billing library version from the lock file; client APIs change across major versions.
23
+
24
+ ## Build the purchase inventory
25
+
26
+ Record for each product: store product id, type (consumable, non-consumable, auto-renewable or non-renewing subscription), base plans and offers or subscription group, the call that starts the purchase, the listener that receives results, the backend endpoint that verifies, the code that reads entitlement and the acknowledge, consume or finish call. Mark store console and backend evidence you cannot read as unknown.
27
+
28
+ ## The purchase is a state machine
29
+
30
+ - Register the purchase listener at startup, before any purchase UI, for the life of the process. Results arrive outside the paywall: renewals, deferred payments, Ask to Buy approvals, purchases from another device and purchases interrupted by process death.
31
+ - Model idle, purchasing, pending, verifying, granted, failed and cancelled. A user cancellation is a normal outcome: no error dialog and no retry.
32
+ - A pending purchase grants nothing. Show it as pending and grant only after the store reports the payment completed.
33
+ - Send the purchase token or signed transaction to the backend with the app account id. The backend verifies it with the store and records the entitlement idempotently, keyed by the store's purchase identifier (`purchaseToken` on Google Play, `transactionId` and `originalTransactionId` on the App Store), so a purchase delivered again by the listener, a restore or the next launch grants once.
34
+ - Acknowledge, consume or finish only after the backend confirms the record. On the next launch, query unfinished or unacknowledged purchases and resume verification; this is the recovery path for a crash between payment and record.
35
+ - Bind the purchase to the account that started it with the store's account field (`obfuscatedAccountId` on Google Play, `appAccountToken` on the App Store). A result that arrives after sign-out or an account switch is reconciled by the backend, never attached to whoever is signed in now.
36
+
37
+ ## Entitlement and catalog
38
+
39
+ - Screens read entitlement from the backend. Cache the last known state for offline use with its timestamp, and decide explicitly what an expired cache allows.
40
+ - Display prices, currencies and offers only from the store's product details. Handle products missing from the current storefront.
41
+ - Upgrades, downgrades and plan changes follow each store's rules (replacement modes on Google Play, subscription group levels on the App Store). The backend links the replaced purchase to the new one.
42
+ - Provide restore: a visible restore action on iOS and a purchase query on launch and resume on Android. Refunds and revocations arrive through server notifications; the app shows the backend state and does not revoke on its own.
43
+
44
+ ## Failure scenarios to test
45
+
46
+ Purchase interrupted by process death; verification failing on a network error and retried with the same token; the same purchase delivered twice; a pending purchase completed days later while the app is closed; user cancellation; a product id not found; an account switch during a purchase; a refund notification; access kept during a grace period or billing retry; restore on a fresh install.
47
+
48
+ ## Verify and deliver
49
+
50
+ Use each store's sandbox: Google Play license testers on a testing track, StoreKit configuration files in Xcode and Sandbox accounts. Test the backend by replaying server notification payloads. Unit-test the purchase state machine against a fake billing client.
51
+
52
+ Return the purchase inventory with `path:symbol` evidence, the implemented transitions, test results and any unverified store console or backend configuration. Whether digital goods must use store billing depends on the market and changes often: check the current store policy instead of designing from memory. Use [mobile-release](../mobile-release/SKILL.md) for submission, [mobile-privacy](../mobile-privacy/SKILL.md) for account deletion versus cancellation, [mobile-security](../mobile-security/SKILL.md) for tampered clients and [mobile-analytics](../mobile-analytics/SKILL.md) for conversion events.
53
+
54
+ ## Official sources
55
+
56
+ - [Google Play Billing integration](https://developer.android.com/google/play/billing/integrate)
57
+ - [StoreKit in-app purchase](https://developer.apple.com/documentation/storekit/in-app-purchase)
58
+ - [App Store Server Notifications](https://developer.apple.com/documentation/appstoreservernotifications)
@@ -0,0 +1,11 @@
1
+ # Billing on Android
2
+
3
+ - Read the Play Billing Library version from the version catalog or Gradle files. Version upgrades and their removed APIs are in the [Play guides](../../mobile-android/references/play.md).
4
+ - Build one `BillingClient` with a `PurchasesUpdatedListener` and pending purchases enabled through `PendingPurchasesParams`. Play Billing Library 8 adds `enableAutoServiceReconnection()`; with it enabled, do not call `startConnection()` again from `onBillingServiceDisconnected`. Without it, reconnect before the next call.
5
+ - Query products with `queryProductDetailsAsync`. A subscription purchase needs the `offerToken` of the chosen offer in `BillingFlowParams`; set `setObfuscatedAccountId` with the app account id.
6
+ - Grant only when `getPurchaseState()` is `PURCHASED` and the backend has verified the `purchaseToken`. `PENDING` purchases complete later and arrive through the listener or the next query.
7
+ - After the backend records the purchase, call `acknowledgePurchase` for non-consumables and subscriptions or `consumeAsync` for consumables. Purchases not acknowledged within three days are refunded.
8
+ - Call `queryPurchasesAsync` on startup and on resume to recover purchases completed while the app was closed or killed.
9
+ - Test with license testers and a build uploaded to a testing track with the release package name and signing key.
10
+
11
+ Official references: [integrate the library](https://developer.android.com/google/play/billing/integrate), [test billing](https://developer.android.com/google/play/billing/test).
@@ -0,0 +1,11 @@
1
+ # Billing in Flutter
2
+
3
+ - Confirm the plugin in `pubspec.lock`: `in_app_purchase` with its Android and StoreKit implementations, or a vendor SDK. Read that version's documentation; the APIs below are from `in_app_purchase`.
4
+ - Listen to `InAppPurchase.instance.purchaseStream` from an app-level owner created at startup, not from the paywall widget. Cancel that `StreamSubscription` only when the owner is disposed.
5
+ - Check `isAvailable()` before `queryProductDetails()`, and handle the ids returned in `notFoundIDs`.
6
+ - Handle every `PurchaseStatus`: `pending`, `purchased`, `restored`, `error` and `canceled`. Send `verificationData.serverVerificationData` to the backend for purchased and restored items, then call `completePurchase` when `pendingCompletePurchase` is true.
7
+ - For consumables, pass `autoConsume: false` to `buyConsumable`: the default consumes the product right after a successful purchase, without waiting for your backend. On Android, consume after the backend records the purchase through `InAppPurchaseAndroidPlatformAddition.consumePurchase`.
8
+ - Pass the account identifier through `PurchaseParam.applicationUserName`, and confirm how the installed platform implementation forwards it to each store.
9
+ - Put the plugin behind an app interface so unit and widget tests can drive every purchase status with a fake stream. Store behavior needs device builds against the sandboxes in [Android](android.md) and [iOS](ios.md).
10
+
11
+ Official reference: [in_app_purchase](https://pub.dev/packages/in_app_purchase).
@@ -0,0 +1,11 @@
1
+ # Billing on iOS
2
+
3
+ - Use StoreKit 2 unless the deployment target or an existing integration requires the original API. The basic purchase call is in the [StoreKit section](../../mobile-ios/references/platform-features.md).
4
+ - Start a long-lived task over `Transaction.updates` at launch, before any purchase UI. It delivers renewals, Ask to Buy approvals, refunds and purchases made on other devices.
5
+ - Purchase with `product.purchase(options:)` including `.appAccountToken(_:)` set to the account's UUID. Handle `.success`, `.pending` and `.userCancelled`; grant only a `.verified` transaction.
6
+ - Send the signed transaction (`jwsRepresentation`) to the backend and call `transaction.finish()` after the backend records it. Iterate `Transaction.unfinished` at launch to resume interrupted verifications.
7
+ - Read `Transaction.currentEntitlements` and the subscription `status` to display state, but let the backend decide access. Distinguish `inGracePeriod` and `inBillingRetryPeriod` from `expired` and `revoked`.
8
+ - Offer restore through `AppStore.sync()` behind an explicit user action; it can prompt for the Apple Account.
9
+ - Test with a StoreKit configuration file in the scheme, then Sandbox and TestFlight.
10
+
11
+ Official references: [In-App Purchase](https://developer.apple.com/documentation/storekit/in-app-purchase), [StoreKit testing in Xcode](https://developer.apple.com/documentation/xcode/setting-up-storekit-testing-in-xcode).
@@ -0,0 +1,9 @@
1
+ # Billing in Kotlin Multiplatform
2
+
3
+ - Keep product ids, the purchase state machine, the entitlement model and backend verification calls in `commonMain` when the project shares that logic. Keep `BillingClient` in Android code and StoreKit in the iOS app.
4
+ - StoreKit 2 is a Swift-only API, so Kotlin/Native cannot call it through Objective-C interop. Implement the iOS store client in Swift and inject it into shared code through an interface the shared module exports.
5
+ - Define one shared result type for purchased, pending, cancelled and failed, and map each host's results into it without losing the store purchase identifier.
6
+ - Start each host's listener at app launch and forward results to the shared owner. Each host keeps its own acknowledge or finish call, made after the backend confirms the record.
7
+ - Test the shared state machine in `commonTest` with a fake store client. Test each host against its store sandbox separately; an Android pass does not prove StoreKit behavior.
8
+
9
+ Official references: [platform-specific declarations](https://kotlinlang.org/docs/multiplatform/multiplatform-expect-actual.html), [Swift and Objective-C interop](https://kotlinlang.org/docs/native-objc-interop.html).
@@ -0,0 +1,10 @@
1
+ # Billing in React Native and Expo
2
+
3
+ - Confirm the library in `package.json` and the lockfile (`react-native-iap`, a vendor SDK such as RevenueCat's, or native modules). Check its support for the installed React Native version and the New Architecture.
4
+ - In-app purchases need native code: Expo Go cannot run them, so use a development build. Add store capabilities and permissions through the library's config plugin or the native project files.
5
+ - Open the store connection and register purchase listeners in an app-root owner, not in the paywall screen, and remove them only when that owner unmounts. Keep listener callbacks idempotent: React Strict Mode runs effects twice in development.
6
+ - Send the purchase token or signed transaction to the backend. Call the library's finish or acknowledge function only after the backend records it, marking consumables as such.
7
+ - Ignore late results for an account generation that is no longer active, and let the backend reconcile them.
8
+ - Test the purchase state machine in Jest with the native module mocked. Store behavior needs native builds against the [Android](android.md) and [iOS](ios.md) sandboxes.
9
+
10
+ Official reference: [Expo development builds](https://docs.expo.dev/develop/development-builds/introduction/). Store rules for digital goods are in the [platform guide](../../mobile-rn/references/platform-features.md).
@@ -0,0 +1,49 @@
1
+ ---
2
+ name: mobile-ci
3
+ description: Sets up and reviews mobile CI/CD and fastlane automation across Flutter, Android, iOS, React Native and Kotlin Multiplatform. Use for Fastfile lanes, Match signing, TestFlight beta uploads, App Store submission, Snapshot screenshots, Xcode Cloud or build and deployment pipelines.
4
+ intents: [deployment]
5
+ stacks: ["*"]
6
+ ---
7
+
8
+ # Mobile CI
9
+
10
+ Connect the app's existing build, test, signing and distribution steps into a reproducible pipeline. Use [mobile-release](../mobile-release/SKILL.md) for release readiness and rollout decisions.
11
+
12
+ ## Choose the references
13
+
14
+ Load the app's stack reference, then only the fastlane guide needed for the task. Cross-platform apps also need the reference for each native target being shipped.
15
+
16
+ | Need | Read |
17
+ |---|---|
18
+ | Flutter | [references/flutter.md](references/flutter.md) |
19
+ | Android, including a cross-platform Android host | [references/android.md](references/android.md) |
20
+ | iOS, including a cross-platform iOS host | [references/ios.md](references/ios.md) |
21
+ | React Native or Expo | [references/react-native.md](references/react-native.md) |
22
+ | Kotlin Multiplatform | [references/kotlin-multiplatform.md](references/kotlin-multiplatform.md) |
23
+ | Pipeline jobs, caches, credentials and artifact retention | [Shared CI/CD guide](../mobile-release/references/ci-cd.md) |
24
+ | Initialize fastlane and define iOS lanes | [Setup](references/fastlane/setup-fastlane.md) |
25
+ | iOS certificates and provisioning profiles | [Match](references/fastlane/match.md) |
26
+ | TestFlight internal and external testing | [Beta](references/fastlane/beta.md) |
27
+ | App Store submission and metadata | [Release](references/fastlane/release.md) |
28
+ | Capture, frame and upload App Store screenshots | [Snapshot](references/fastlane/snapshot.md) |
29
+ | Xcode Cloud workflow integration | [Xcode Cloud](references/fastlane/xcode-cloud.md) |
30
+
31
+ ## Workflow
32
+
33
+ 1. Inspect existing workflows, Fastfile, Appfile, Matchfile, Gemfile.lock, platform lock files, schemes, flavors and environment configuration. Identify working directories and actual artifact paths before writing commands.
34
+ 2. Establish the requested scope: pipeline setup, local verification, beta upload or production submission. Preserve existing lanes and signing conventions; do not replace the whole Fastfile with an example.
35
+ 3. Separate validation from signed builds and uploads. Use pinned toolchains, lock-file-based caches, protected release jobs, secret storage and retained symbols as described in the shared CI/CD guide.
36
+ 4. Adapt the selected reference to the detected platform. The imported fastlane guides describe iOS workflows; Android needs its own Gradle tasks, keystore and Play destination.
37
+ 5. Check lane definitions, dependencies, action parameters and workflow syntax before execution. Run the project's relevant local checks, then report what was verified locally and what still needs a CI or store run. A configured pipeline is not evidence of a successful upload.
38
+
39
+ ## Applying the upstream examples
40
+
41
+ The fastlane references preserve the instructions from `greenstevester/fastlane-skill`; their frontmatter was removed and the Xcode Cloud link relocated. Read them as examples, with these integration rules:
42
+
43
+ - Use the project's Ruby/Bundler/fastlane versions and `bundle exec fastlane` when a Gemfile exists. Verify compatibility from the lock file and current fastlane documentation rather than applying the upstream blanket claim about Bundler 4 or replacing the installation with Homebrew.
44
+ - Resolve `/setup-fastlane` and references to the `match`, `beta`, `release` and `snapshot` skills through the table above. These are references, not separately installed commands. Embedded `!` shell snippets and `${ARGUMENTS}` placeholders are upstream notation, not automatic preflight results.
45
+ - Inspect each lane before invoking it: the setup and Match examples define different `release` behavior. Confirm the exact tested build rather than submitting whichever build is newest. Existing session authorization determines whether builds, uploads, store submission or automatic release are in scope.
46
+ - Keep Match read-only in CI. Certificate revocation (`match nuke`), simulator erasure, package removal and screenshot-directory replacement are destructive recovery examples, not routine setup steps; diagnose first and require explicit authorization for those actions.
47
+ - Verify action options with the installed version's help or official documentation. In particular, check the `app_store_connect_api_key` action's content parameter rather than copying the Xcode Cloud example's `key:` blindly. Never print private keys or passwords.
48
+ - Confirm current screenshot dimensions and accepted devices with Apple's linked specifications and installed simulators. Treat processing/review times and StoreKit storefront behavior as claims to verify, not guarantees. Screenshot fixtures must represent the product accurately.
49
+ - The Xcode Cloud guide describes lifecycle scripts but does not ship them. Create or inspect those scripts for the actual project; do not assume the setup guide generated them. Follow the team's configured triggers and managed signing, and avoid rebuilding or uploading the same artifact twice.
@@ -0,0 +1,8 @@
1
+ # Android CI
2
+
3
+ Read the [shared pipeline guide](../../mobile-release/references/ci-cd.md) and [Android release reference](../../mobile-release/references/android.md).
4
+
5
+ - Resolve the Gradle wrapper, JDK, module, variant and signing configuration from the project. Run its existing lint and test tasks before the release bundle task.
6
+ - Keep the upload keystore and Play credentials in CI secrets; untrusted pull requests must not receive them. Preserve the distinction between the upload key and Play App Signing.
7
+ - Use the actual AAB path and package identifier in the Android lane. The imported iOS `gym`, `pilot`, `match` and `snapshot` examples do not implement Android builds or uploads.
8
+ - Upload through the project's fastlane Play lane with an explicit track and release status. Retain the exact AAB, mapping and native symbols. Coordinate version codes across concurrent runs and retries.
@@ -0,0 +1,75 @@
1
+ > Adapted from the `beta` skill in [greenstevester/fastlane-skill](https://github.com/greenstevester/fastlane-skill) (MIT).
2
+
3
+ ## TestFlight Beta Release
4
+
5
+ Build and upload the iOS app to TestFlight for beta testing.
6
+
7
+ ### Pre-flight Checks
8
+ - Fastlane installed: !`fastlane --version 2>/dev/null | grep "fastlane " | head -1 || echo "✗ Not installed - run: brew install fastlane"`
9
+ - Fastfile exists: !`ls fastlane/Fastfile 2>/dev/null && echo "✓ Found" || echo "✗ Not found - run /setup-fastlane first"`
10
+ - App-specific password: !`[ -n "$FASTLANE_APPLE_APPLICATION_SPECIFIC_PASSWORD" ] && echo "✓ Set" || echo "⚠️ Not set - export FASTLANE_APPLE_APPLICATION_SPECIFIC_PASSWORD='xxxx-xxxx-xxxx-xxxx'"`
11
+
12
+ ### Arguments: ${ARGUMENTS:-none}
13
+
14
+ ---
15
+
16
+ ## What This Does
17
+
18
+ 1. **Syncs certificates** via Match (appstore type) — *only once you've run the `match` skill; the base `setup-fastlane` lane skips this*
19
+ 2. **Increments build number** (unless `--skip-build-increment`)
20
+ 3. **Builds release archive** with gym
21
+ 4. **Uploads to TestFlight** via pilot
22
+ 5. **Optionally distributes to external testers** (via the separate `beta_external` lane)
23
+
24
+ ---
25
+
26
+ ## Commands
27
+
28
+ ### Standard Beta (Internal Testers)
29
+ Run from your project directory (where `fastlane/` lives):
30
+ ```bash
31
+ fastlane beta
32
+ ```
33
+
34
+ ### Skip Build Number Increment
35
+ ```bash
36
+ fastlane beta skip_build_increment:true
37
+ ```
38
+
39
+ ### External Testers (with changelog)
40
+ ```bash
41
+ fastlane beta_external changelog:"Bug fixes and performance improvements"
42
+ ```
43
+
44
+ ---
45
+
46
+ ## Troubleshooting
47
+
48
+ ### "No value found for 'username'"
49
+ Set your Apple ID in `fastlane/Appfile`:
50
+ ```ruby
51
+ apple_id("your@email.com")
52
+ ```
53
+
54
+ ### "Please sign in with an app-specific password"
55
+ 1. Go to https://account.apple.com → Sign-In & Security → App-Specific Passwords
56
+ 2. Generate a password named "Fastlane"
57
+ 3. Export it:
58
+ ```bash
59
+ export FASTLANE_APPLE_APPLICATION_SPECIFIC_PASSWORD='xxxx-xxxx-xxxx-xxxx'
60
+ ```
61
+
62
+ ### rsync error during export
63
+ If you see `--extended-attributes: unknown option`, Homebrew rsync conflicts with Xcode:
64
+ ```bash
65
+ brew uninstall rsync # Use system rsync
66
+ ```
67
+
68
+ ---
69
+
70
+ ## After Upload
71
+
72
+ - Build will appear in TestFlight within 1-5 minutes
73
+ - Internal testers are notified automatically
74
+ - External testers require `beta_external` lane or manual distribution in App Store Connect
75
+
@@ -0,0 +1,288 @@
1
+ > Adapted from the `match` skill in [greenstevester/fastlane-skill](https://github.com/greenstevester/fastlane-skill) (MIT).
2
+
3
+ ## Code Signing with Match
4
+
5
+ Set up Fastlane Match to manage iOS code signing certificates and provisioning profiles in a shared Git repository.
6
+
7
+ ### Pre-flight Checks
8
+ - Fastlane installed: !`fastlane --version 2>/dev/null | grep "fastlane " | head -1 || echo "✗ Not installed - run: brew install fastlane"`
9
+ - Fastfile exists: !`ls fastlane/Fastfile 2>/dev/null && echo "✓ Found" || echo "✗ Not found - run /setup-fastlane first"`
10
+ - Existing Matchfile: !`ls fastlane/Matchfile 2>/dev/null && echo "✓ Already configured" || echo "○ Not configured yet"`
11
+ - Git available: !`git --version 2>/dev/null | head -1 || echo "✗ Git not installed"`
12
+
13
+ ### Arguments: ${ARGUMENTS:-setup}
14
+
15
+ ---
16
+
17
+ ## What is Match?
18
+
19
+ Match stores your iOS certificates and provisioning profiles in a **private Git repository**, encrypted with a passphrase. Benefits:
20
+
21
+ - **Team sharing**: Everyone uses the same certificates (no more "works on my machine")
22
+ - **CI/CD ready**: Clone the repo in your pipeline, no manual cert management
23
+ - **Revoke protection**: Prevents accidental certificate revocation
24
+ - **Audit trail**: Git history shows who changed what and when
25
+
26
+ ---
27
+
28
+ ## Step 1: Create a Private Git Repository
29
+
30
+ Create a **private** repository to store your encrypted certificates:
31
+
32
+ ```bash
33
+ # GitHub CLI (recommended)
34
+ gh repo create certificates --private
35
+
36
+ # Or manually at github.com/new (select Private)
37
+ ```
38
+
39
+ **Repository naming conventions:**
40
+ - `certificates` or `ios-certificates`
41
+ - `fastlane-certs`
42
+ - `{company}-signing`
43
+
44
+ > **Security**: This repo will contain encrypted certificates. Keep it private and limit access to team members who need to build the app.
45
+
46
+ ---
47
+
48
+ ## Step 2: Initialize Match
49
+
50
+ Run match init to create your Matchfile:
51
+
52
+ ```bash
53
+ fastlane match init
54
+ ```
55
+
56
+ When prompted:
57
+ 1. **Storage mode**: Select `git`
58
+ 2. **Git URL**: Enter your private repo URL (e.g., `git@github.com:yourorg/certificates.git`)
59
+
60
+ This creates `fastlane/Matchfile`:
61
+
62
+ ```ruby
63
+ git_url("git@github.com:yourorg/certificates.git")
64
+
65
+ storage_mode("git")
66
+
67
+ type("development") # Default type, can be overridden per-lane
68
+
69
+ # app_identifier(["com.yourcompany.app"]) # Optional: limit to specific apps
70
+ # username("user@example.com") # Optional: Apple ID
71
+ ```
72
+
73
+ ---
74
+
75
+ ## Step 3: Generate Certificates
76
+
77
+ Generate certificates for each distribution type:
78
+
79
+ ### Development (for debugging on devices)
80
+ ```bash
81
+ fastlane match development
82
+ ```
83
+
84
+ ### App Store (for TestFlight and App Store)
85
+ ```bash
86
+ fastlane match appstore
87
+ ```
88
+
89
+ ### Ad Hoc (for direct device distribution)
90
+ ```bash
91
+ fastlane match adhoc
92
+ ```
93
+
94
+ **First run prompts:**
95
+ 1. **Apple ID**: Your Apple Developer account email
96
+ 2. **Passphrase**: Create a strong passphrase to encrypt certificates (save this securely!)
97
+
98
+ > **Important**: Save the passphrase in a password manager. You'll need it for CI/CD and new team members.
99
+
100
+ ---
101
+
102
+ ## Step 4: Integrate with Fastfile
103
+
104
+ Update your lanes to use Match before building:
105
+
106
+ ```ruby
107
+ default_platform(:ios)
108
+
109
+ platform :ios do
110
+ desc "Sync all certificates"
111
+ lane :sync_signing do
112
+ match(type: "development")
113
+ match(type: "appstore")
114
+ end
115
+
116
+ desc "Install signing assets on CI (read-only)"
117
+ lane :certificates do
118
+ setup_ci # temp keychain on CI; no-op locally
119
+ match(type: "appstore", readonly: true)
120
+ end
121
+
122
+ desc "Build for TestFlight"
123
+ lane :beta do |options|
124
+ setup_ci # temp keychain on CI; no-op locally
125
+ match(type: "appstore", readonly: true)
126
+ increment_build_number unless options[:skip_build_increment]
127
+ gym(scheme: "YourApp", export_method: "app-store")
128
+ pilot(skip_waiting_for_build_processing: true)
129
+ end
130
+
131
+ desc "Build for App Store"
132
+ lane :release do
133
+ setup_ci # temp keychain on CI; no-op locally
134
+ match(type: "appstore", readonly: true)
135
+ increment_build_number
136
+ gym(scheme: "YourApp", export_method: "app-store")
137
+ deliver(submit_for_review: false, force: true)
138
+ end
139
+ end
140
+ ```
141
+
142
+ **Key pattern**: Use `readonly: true` in build lanes to prevent accidental certificate regeneration.
143
+
144
+ **CI keychain**: `setup_ci` creates a temporary keychain on CI runners (and is a no-op locally) so `match` can import certs without keychain-permission errors. Call it before `match` in any lane that runs on CI.
145
+
146
+ ---
147
+
148
+ ## Step 5: Onboard Team Members
149
+
150
+ New team members run:
151
+
152
+ ```bash
153
+ # Clone and decrypt existing certificates (readonly)
154
+ fastlane match development --readonly
155
+ fastlane match appstore --readonly
156
+ ```
157
+
158
+ They'll need:
159
+ 1. Access to the private certificates repository
160
+ 2. The Match passphrase
161
+ 3. Apple Developer team membership
162
+
163
+ **Readonly mode** ensures they can't accidentally revoke or regenerate certificates.
164
+
165
+ ---
166
+
167
+ ## Step 6: CI/CD Setup
168
+
169
+ Set these environment variables in your CI/CD system:
170
+
171
+ ```bash
172
+ # Required
173
+ MATCH_PASSWORD="your-match-passphrase"
174
+ MATCH_GIT_URL="git@github.com:yourorg/certificates.git"
175
+
176
+ # For App Store Connect (choose one method)
177
+ # Method 1: App-specific password
178
+ FASTLANE_USER="your@appleid.com"
179
+ FASTLANE_APPLE_APPLICATION_SPECIFIC_PASSWORD="xxxx-xxxx-xxxx-xxxx"
180
+
181
+ # Method 2: API Key (recommended for CI)
182
+ APP_STORE_CONNECT_API_KEY_KEY_ID="ABC123"
183
+ APP_STORE_CONNECT_API_KEY_ISSUER_ID="xyz-xyz-xyz"
184
+ APP_STORE_CONNECT_API_KEY_KEY="-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----"
185
+ ```
186
+
187
+ ### GitHub Actions Example
188
+
189
+ ```yaml
190
+ - name: Install certificates
191
+ run: fastlane ios certificates # runs setup_ci + match(readonly: true)
192
+ env:
193
+ MATCH_PASSWORD: ${{ secrets.MATCH_PASSWORD }}
194
+ MATCH_GIT_URL: ${{ secrets.MATCH_GIT_URL }}
195
+ ```
196
+
197
+ ### Xcode Cloud
198
+
199
+ Add to `ci_scripts/ci_post_clone.sh`:
200
+ ```bash
201
+ # Install Fastlane and sync certificates
202
+ brew install fastlane
203
+ fastlane ios certificates # setup_ci + match(readonly: true)
204
+ ```
205
+
206
+ Set `MATCH_PASSWORD` in Xcode Cloud environment variables.
207
+
208
+ ---
209
+
210
+ ## Troubleshooting
211
+
212
+ ### "Couldn't decrypt the repo"
213
+ Wrong passphrase. Verify `MATCH_PASSWORD` is correct.
214
+
215
+ ### "Code signing error: No provisioning profiles"
216
+ Run `fastlane match appstore` (without `--readonly`) to generate profiles.
217
+
218
+ ### "Your certificate has been revoked"
219
+ Someone revoked certs in Apple Developer portal. Regenerate:
220
+ ```bash
221
+ fastlane match nuke development # Removes all development certs
222
+ fastlane match development # Regenerates
223
+ ```
224
+
225
+ ### "Multiple teams found"
226
+ Specify team in Matchfile:
227
+ ```ruby
228
+ team_id("ABCD1234")
229
+ ```
230
+
231
+ ### "Unable to find app with bundle identifier"
232
+ Register the app first (SKU and username are required):
233
+ ```bash
234
+ fastlane produce create -u your@appleid.com -a com.yourcompany.app -n "Your App Name" --sku YOUR_SKU
235
+ ```
236
+
237
+ ---
238
+
239
+ ## Match Commands Reference
240
+
241
+ ```bash
242
+ # Setup
243
+ fastlane match init # Create Matchfile
244
+ fastlane match development # Generate dev certs
245
+ fastlane match appstore # Generate App Store certs
246
+ fastlane match adhoc # Generate Ad Hoc certs
247
+
248
+ # Team use (readonly - won't modify certs)
249
+ fastlane match development --readonly
250
+ fastlane match appstore --readonly
251
+
252
+ # Maintenance
253
+ fastlane match nuke development # Revoke all dev certs
254
+ fastlane match nuke distribution # Revoke all dist certs
255
+ fastlane match change_password # Change encryption passphrase
256
+
257
+ # Debugging
258
+ fastlane match development --verbose # Detailed output
259
+ ```
260
+
261
+ ---
262
+
263
+ ## Security Best Practices
264
+
265
+ 1. **Private repository**: Never make the certificates repo public
266
+ 2. **Strong passphrase**: Use 20+ characters, store in password manager
267
+ 3. **Limit access**: Only team members who build should have repo access
268
+ 4. **Rotate periodically**: Change passphrase annually with `match change_password`
269
+ 5. **API keys over passwords**: Use App Store Connect API keys for CI/CD
270
+
271
+ ---
272
+
273
+ ## Files Created
274
+
275
+ ```
276
+ fastlane/
277
+ └── Matchfile # Match configuration
278
+
279
+ # In your certificates repo:
280
+ certs/
281
+ ├── development/ # Development certificates
282
+ └── distribution/ # App Store/Ad Hoc certificates
283
+ profiles/
284
+ ├── development/ # Development provisioning profiles
285
+ ├── appstore/ # App Store provisioning profiles
286
+ └── adhoc/ # Ad Hoc provisioning profiles
287
+ ```
288
+