← Files OneSignalARCHIVED FILE

skills/credentials/references/platform-matrix.md

6.39 KB · Sep 30, 2026 · 22:50 UTC

↓ Download file

# Per-platform automation matrix

What the agent can do vs. what stays human, per platform. Verified against SDK repos, example apps, and official docs (July 2026). The honest promise: the agent writes all integration code and does API-side provisioning; the human does the external-console steps below, guided.

## Summary table

| Platform | Agent automates | Human must do | Notes |
|---|---|---|---|
| **Web** (most automatable) | `<script src="https://cdn.onesignal.com/sdks/web/v16/OneSignalSDK.page.js" defer>` + `OneSignal.init({appId})` via `OneSignalDeferred`; create `OneSignalSDKWorker.js` containing one line `importScripts("https://cdn.onesignal.com/sdks/web/v16/OneSignalSDK.sw.js");` placed in `public/` (maps to origin root on Next/CRA/Vite/Vue/Angular) | Dashboard web-platform config (Site URL must EXACTLY match origin); confirm deployed site serves the worker same-origin over HTTPS with `Content-Type: application/javascript` | **Signup/onboarding does NOT provision the web platform** — until the dashboard step happens the SDK fails init with `App not configured for web push` (sync `code: 2`); probe `GET /sync/{app_id}/web` (api-reference), or provision via the write-once credentials endpoint (`chrome_web_origin`). SW must be same-origin — no CDN/subdomain. Subdir placement needs `serviceWorkerPath` + `serviceWorkerParam.scope`. PWA conflict: only one SW per scope. localhost testing works with a separate app + `allowLocalhostAsSecureOrigin: true`. Frameworks: react-onesignal / onesignal-vue3 / onesignal-ngx npm packages. |
| **Expo** (best mobile) | `npx expo install onesignal-expo-plugin` + `npm i react-native-onesignal`; app.json: plugin FIRST in plugins array, `mode`, `smallIcons`; init in `App.tsx`/`_layout.tsx` | Apple .p8 + Firebase JSON procurement; EAS credentials must match; dev build (push doesn't work in Expo Go) | Config plugin generates NSE, entitlements, App Group, UIBackgroundModes at prebuild — zero manual Xcode. Expo SDK 53+/RN 0.79+ New Architecture. |
| **Android** | Gradle dep `com.onesignal:OneSignal:<exact Stable from releases.json>` (e.g. `5.9.1` — **exact pin, never a version range**); Application subclass with `OneSignal.initWithContext(this, APP_ID)`; register in AndroidManifest `android:name`; `requestPermission` call | Firebase console: create project (if none), generate **service-account JSON**; (agent uploads it via API) | **`google-services.json` is NOT required for OneSignal** — FCM v1 credentials are server-side only (the upstream ai-prompt requiring it is a known bug; only keep it if the app itself uses Firebase client SDKs). `POST_NOTIFICATIONS` is manifest-merged by the SDK — no edit. Play-services emulator OK for testing. **Version + Kotlin floor:** resolve the exact pin with `scripts/resolve_sdk_version.py android` (never compose the line by hand — ranges break the build). The SDK's OpenTelemetry submodule transitively pulls a newer `kotlin-stdlib` than its POM admits (5.9.1 resolves to 2.2.20), so the host needs a Kotlin compiler that can read that metadata — check it with `scripts/android_kotlin_check.py . --deps -` (fed a `:app:dependencies` run) and surface any required toolchain bump as a separately-approved change; never half-bump to a version still below the resolved stdlib. |
| **iOS native** | SPM (`OneSignal-XCFramework` repo, map `OneSignalFramework`→app) or Podfile; `OneSignal.initialize(appId, withLaunchOptions:)` in AppDelegate/adaptor; Info.plist `UIBackgroundModes remote-notification`; entitlements text; debug-only verification helper | Apple Developer portal: paid account, Push capability on App ID, generate **.p8** (+ Key ID/Team ID); Xcode GUI: signing, capabilities toggle, and **NSE target creation** (File>New>Target — not reliably text-editable); physical-device test (launch from Xcode) + the notification permission tap | NSE is OPTIONAL for minimal install (needed only for rich media / confirmed receipt / badges) — OneSignal's own AI prompt skips it. Never hardcode a fallback App ID. Remote push testing: physical device (human launches), or a simulator on an Apple-silicon Mac that the verify skill boots, installs, and launches itself via `simctl` (Xcode 14+ simulators there receive real sandbox APNs pushes; Intel-Mac simulators do not) — only the permission tap stays human. |
| **React Native / Flutter / Cordova / Capacitor** | Package install (`react-native-onesignal` / `onesignal_flutter` / `onesignal-cordova-plugin` / `@onesignal/capacitor-plugin` + `npx cap sync` — exact Stable version from releases.json, no ranges/carets); init call in entry file; Podfile NSE pod line; version bumps (RN 0.79+ New Arch, Flutter 3.29+) | Everything in the iOS-native human column (these wrappers inherit the full native iOS GUI flow); Firebase JSON procurement | Capacitor: set `ios.handleApplicationNotifications: false` in capacitor.config. Android side is handled by the wrapper plugins — no manual gradle/manifest edits documented. |
| **Unity** | Init `OneSignal.Initialize("APP_ID")` in a MonoBehaviour; icon assets | GUI-bound install (Package Manager/Asset Store), Player Settings gradle-template toggles | Low human friction but low agent-automatability. Unity 2022.3+, Android API 33+. |

## Credentials the human procures (agent validates + uploads via API)

| Credential | Where the human gets it | Agent then |
|---|---|---|
| Apple APNs **.p8** key + Key ID + Team ID | Apple Developer portal → Keys (paid account; one-time download; 10–15 min propagation on new keys) | uploads via `POST /api/v1/apps/{id}/credentials` (`apns_p8` + `apns_key_id` + `apns_team_id` + `apns_bundle_id`, app-scoped key, write-once); verifies via test send |
| Firebase **service-account JSON** | Firebase console → Project settings → Service accounts → Generate private key (enable FCM v1 API if prompted) | base64-encodes + uploads (`fcm_v1_service_account_json`); never commits the file — add to `.gitignore` |
| Email: SPF/DKIM/DMARC DNS records | Their DNS provider (values from dashboard; up to 24 h propagation) | can only guide + re-check status |
| SMS sender | Carrier registration (days–weeks; outside anyone's control) | guide only |

## Activation ladder the skills drive (all measurable today)

SDK initialized → first subscription (`notification_types >= 1`) → **External ID set** (highest-leverage, most-skipped) → first message sent → **first message DELIVERED (`successful >= 1`) to an identified subscriber = ACTIVATED** — the terminal rung.

SHA-256: 60d7f98406d1a9e23ecd8ce528af348768ea743cb4fff2457dc056b060828900