# Native platforms (Android · iOS) — NOT done until the platform build passes

Editing the code is not enough on native; a migration that "looks done" here routinely fails to build or isn't actually wired. You MUST, before declaring done:
- **Bump the sample's build toolchain to the core skill's floors FIRST** (an old sample toolchain is the #1 native build failure). Android: set `gradle/wrapper/gradle-wrapper.properties` `distributionUrl` to **Gradle ≥ 8.11**, plus **AGP ≥ 8.9.1 · compileSdk 36 · minSdk 28 · Kotlin ≥ 2.1** (per the family `-core` skill's build floors — a stale wrapper gives the opaque `checkDebugAarMetadata` / "Gradle version" error). iOS: resolve the SPM (or pods) graph. Flutter: swap the dep in `pubspec.yaml`, then `flutter pub get`; the settings file is an **asset** — `cometchat-settings.json` at the project root AND listed under `flutter: assets:` in `pubspec.yaml`, or the build fails with "No file or variants found for asset".
- **The wrapper file may refuse every write.** `gradle/wrapper/gradle-wrapper.properties` is a protected path: `Edit`, `Write` and a Bash `sed` against it can each be refused. Attempt it anyway, and if every route is refused, say **exactly which commands were refused** in the report instead of reporting the bump as done — a stale wrapper is the #1 Android build failure (AGP >= 8.9.1 needs Gradle >= 8.11.1), so a silent omission here costs the whole build. **Keep shell metacharacters out of the commands you run:** a `|` (even as a sed delimiter, or inside an alternation like `(bin|all)`), a `{a,b}` brace expansion, a `$(...)` substitution or a `VAR=x cmd` env prefix is parsed as shell syntax by the command-permission layer and the WHOLE command is refused, silently. Use `/` delimiters, character classes, plain literals and separate lines before concluding an edit is impossible.
- **Confirm the kit dependency is added AND `initFromSettings` is wired** in the platform's app entry — Android `Application.onCreate`, iOS `AppDelegate`/`App`, Flutter `main`. "No kit dependency" and "no `initFromSettings` call" mean the migration is incomplete, not done.
- **Port `toCometChatId` to the CLIENT language** (Kotlin/Swift/Dart — verbatim port in `references/concept-map.md` §IDs), in its own module (Flutter: `lib/cometchat/ids.dart`; Android: `…/cometchat/Ids.kt`; iOS: `CometChat/Ids.swift`), and **call it at login** — not only in the JS data script. **The UID is `toCometChatId(<the app's existing Sendbird user id>)`** — the `SendbirdUIKit.connect('…')` / `SendbirdChat.connect` id or the app's stored user id. The core skill's "never invent a UID / `cometchat-uid-1` for a fresh app" advice does NOT apply to a migration: the identity already exists, keep it (single-prompt contract → *Keep every identity source*).
- **Update `LICENSE`/attribution/README** — a vendor copyright line is residue too.
- **RUN the platform build** (`./gradlew :app:assembleDebug` · `xcodebuild … build` · `flutter analyze && flutter build web` or `flutter build apk --debug`) and fix EVERY error. A native migration is not done until its own build passes. **Then run it** (§Verify it works): Flutter → `flutter run -d web-server --web-port 8765` via the Bash tool's **background mode** (`run_in_background`), then `sleep 20` and **Read** its output file (repeat ×3) until "is available at" or an exception shows, then **stop that task** and continue. No shell loops, `&`, `$(…)` or `timeout` (denied under headless permissions; `timeout` is absent on macOS), and never park the migration on a notification (headless: that ends the run).
- **NEVER text-replace inside `*.xcodeproj/project.pbxproj` or `*.xcscheme`.** They are structured build graphs, not manifests: a blind find-and-replace (including a residue scrub) silently breaks the build in ways the compiler cannot report. Edit only the SPM `XCRemoteSwiftPackageReference` blocks and the product-name strings you actually mean to change, and leave every `PBXFileReference`, `productReference`, Products-group child and scheme `BuildableName` intact — a product is `Foo.app` / `Foo.appex`, never bare `Foo`. **Verify after editing:** the app target still has a `productReference`, the Products group still lists it, and the scheme's `BuildableName` still ends in `.app`. If these are missing, `xcodebuild` still reports **BUILD SUCCEEDED** while Xcode's Run silently does nothing — there is no error message anywhere, so the build passing is not evidence they survived.
