Overview
KalmForge.LocalNotifications wraps the official Unity com.unity.mobile.notifications package via reflection, so the SDK compiles without it and silently no-ops on platforms that don't support it. Templates authored on the dashboard are fetched on boot, cached on disk, and scheduled automatically when the app goes to the background.
Install the package
- Window → Package Manager → Add by name:
com.unity.mobile.notifications. - iOS: capabilities are enabled by the build post-processor that ships with the SDK.
- Android: the SDK uses the channel id
"default"unless you override it on a notification.
LocalNotifications logs a one-shot warning and returns. Your code paths stay safe.Requesting permission
1bool granted = await LocalNotifications.RequestPermissionAsync();2if (!granted) Debug.Log("Player declined notifications");On iOS this prompts for badge + sound + alert. On Android 13+ this requests POST_NOTIFICATIONS. Older platforms return true immediately.
Scheduling a notification
1LocalNotifications.Schedule(new LocalNotification {2 Id = "energy_full",3 Title = "Your energy is full!",4 Body = "Come back and play.",5 FireAt = System.DateTime.Now.AddHours(2),6 Channel = "default",7 DeepLink = "myapp://energy",8});910// Replace by id (same Id cancels the previous schedule before scheduling again):11LocalNotifications.Schedule(new LocalNotification { Id = "energy_full", /* ... */ });1213// Cancel:14LocalNotifications.Cancel("energy_full");15LocalNotifications.CancelAll();FireAt is local device time.Dashboard templates
Author re-engagement templates on the dashboard (title, body, trigger, deep-link, Android channel). Sync once on boot - they're cached for offline use and re-scheduled on every app close:
1await LocalNotifications.SyncTemplatesAsync(); // device language2await LocalNotifications.SyncTemplatesAsync("fr"); // explicit override34// Manually schedule one template before close, e.g. with a custom fire time:5LocalNotifications.ScheduleTemplate("daily_streak", System.DateTime.Now.AddHours(20));Triggers supported on the dashboard:
- delay -
now + N seconds. - time_of_day -
HH:mm, optionally restricted to ISO weekdays (Mon=1). - on_demand - never auto-scheduled; trigger via
ScheduleTemplate(key).
Lifecycle
- App launch → all previously scheduled local notifications are cancelled (so they don't fire while the player is active).
- App close / pause to background → every cached template is re-scheduled per its trigger.
- Manual
Schedule()calls survive across these transitions because the cancellation step only clears the SDK's known ids when launching, not when backgrounding.
Remote push setup
KalmForge.RemotePush acquires the platform push token (APNs on iOS, FCM on Android), registers it with the dashboard, and lets you send campaigns from Project → Notifications → Campaigns. Four steps: configure dashboard credentials, run the in-Editor Setup Wizard for Android + iOS client config, enable APNs on the App ID, then call RegisterAsync() at runtime.
google-services.json / GoogleService-Info.plistinto Assets/, patches AndroidManifest.xml, generates iOS entitlements + an Xcode post-processor, and adds theHAS_FIREBASE_PUSH_NOTIFICATIONS scripting define. The steps below explain what it does and how to do it manually if you prefer. See the Getting Started → Project Setup Wizard section for the full walkthrough.1. Configure credentials on the dashboard
Open Project → Notifications → Setup and run the wizard. You need:
- Android (FCM) - a Firebase service account JSON (Firebase Console → Project Settings → Service accounts → Generate new private key). This is not the same file as
google-services.json; the service account key is server-side credentials, thegoogle-services.jsonships inside the app. - iOS (APNs) - a
.p8auth key from developer.apple.com (Certificates, Identifiers & Profiles → Keys → +), plus your Team ID, Key ID, app Bundle ID, and whether you're targeting sandbox (development builds) or production.
2. Android: Firebase + google-services.json
Easiest path: run the Setup Wizard's Firebase and Config files steps - it imports Firebase Cloud Messaging and copies google-services.json to Assets/google-services.json for you. Manual setup:
- In the Firebase Console, add an Android app to the same Firebase project whose service account JSON you uploaded to the dashboard. Use your app's package name (e.g.
com.studio.game). - Download the generated
google-services.jsonand drop it into your Unity project at:The file must sit directly underexampleC#1Assets/google-services.jsonAssets/at the root - Firebase's Unity build processor looks for it there. Do not rename it, nest it underResources/, or commit it toStreamingAssets/. The wizard's Config filesstep provides a dropzone that handles this automatically. - Install Firebase Cloud Messaging for Unity(
com.google.firebase.messaging) from the Firebase Unity SDK, or let the wizard's Firebase step pull it from the KalmForge SDK store. Importing the package also pulls in Firebase Core, which readsgoogle-services.jsonat build time. - The wizard's Android step patches
Assets/Plugins/Android/AndroidManifest.xmlwithPOST_NOTIFICATIONS,RECEIVE_BOOT_COMPLETED, the FCM intent filter, and the default notification channel meta-data. If you maintain the manifest yourself, mirror those entries by hand.
google-services.json in Assets/ belongs to a different Firebase project than the service account JSON uploaded to the dashboard, FCM will accept the device token but every send will be rejected with SenderId mismatch.3. iOS: APNs entitlements
Run the Setup Wizard's iOS step - it creates Assets/KalmForge/iOS/Entitlements.entitlements with aps-environment set, plus Assets/KalmForge/Editor/KalmForgePushPostProcess.cs, which is invoked by Unity on every iOS build to add the Push Notifications capability, the entitlements file, and UIBackgroundModes = remote-notification to the generated Xcode project. Then:
- In the Apple Developer portal, enable the Push Notifications capability on the App ID matching your Unity Bundle Identifier.
- The wizard-generated post-processor adds
UIBackgroundModes = remote-notificationandNSUserNotificationsUsageDescriptionto the generatedInfo.plist. No game-side changes required. - In Xcode, confirm the Push Notifications capability is listed under Signing & Capabilities. If it isn't, add it - Unity occasionally drops it when the bundle ID changes.
- Match the sandbox toggle in the dashboard to your build: development builds (
aps-environment = development) must use sandbox, App Store / TestFlight builds must use production. The wrong environment yieldsBadDeviceTokenon send.
4. Register the device token
After requesting notification permission, callRemotePush.RegisterAsync(). Safe to call on every launch - the dashboard upserts by token.
1using KalmForge;23bool granted = await LocalNotifications.RequestPermissionAsync();4if (!granted) return;56// Optional segmentation properties (string / number / bool).7var props = new System.Collections.Generic.Dictionary<string, object> {8 { "level", 12 },9 { "vip", true },10};1112bool ok = await RemotePush.RegisterAsync(props);13Debug.Log($"Push registered: {ok}");Already have a token from your own provider? Skip acquisition and register it directly:
1await RemotePush.RegisterTokenAsync(token, platform: "android", properties: props);API reference
| Name | Type | Description |
|---|---|---|
| RequestPermissionAsync() | Task<bool> | Prompt for permission on iOS / Android 13+. |
| Schedule(LocalNotification) | void | Schedule (or replace by Id) a single notification. |
| Cancel(id) | void | Cancel one previously scheduled notification. |
| CancelAll() | void | Cancel everything the SDK has scheduled. |
| SyncTemplatesAsync(language?) | Task | Fetch + cache enabled templates. Auto-rescheduled on app close. |
| ScheduleTemplate(key, fireAt?) | void | Schedule one cached template, optionally overriding its fire time. |
| ScheduleAllTemplates() | void | Manually re-schedule every cached template now. |
| CacheFileName | string (const) | "kalmforge_push_templates.json". |
| Name | Type | Description |
|---|---|---|
| Id | string | Required. Used for de-dup and cancellation. |
| Title | string | Notification title. |
| Body | string | Notification body. |
| FireAt | DateTime | Local device time. Past values are ignored. |
| Channel | string | Android channel id. Defaults to "default". |
| DeepLink | string | Optional payload delivered when the user taps the notification. |
REST endpoint
1GET /api/public/sdk/push/templates?lang=en2Headers: X-API-Key: kf_xxx_yyy34Response:5{6 "templates": [7 {8 "key": "daily_streak",9 "title": "Don't lose your streak!",10 "body": "Tap to claim today's bonus.",11 "trigger": { "type": "time_of_day", "time_of_day": "19:00", "weekdays": [1,2,3,4,5] },12 "android_channel": "default",13 "deep_link": "myapp://daily"14 }15 ]16}