Configure push notifications to receive, display, and handle Userpilot push notifications on iOS and Android.
The Userpilot SDK supports push notifications on both iOS and Android to help you deliver targeted messages and enhance user engagement.
iOS Setup
Prerequisites
Configure your iOS push settings in the Userpilot Settings Studio before setting up push notifications in your app.
To obtain the required keys and configuration details, refer to the iOS Push Notification Guide.
Setup
Step 1. Enable Push Notifications Capability
Add the aps-environment entitlement to your Entitlements.plist file at Platforms/iOS/Entitlements.plist:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<!-- Push Notifications capability -->
<key>aps-environment</key>
<string>development</string>
</dict>
</plist>
NoteChange development to production when publishing to the App Store.
Step 2. Enable Background Remote Notifications
Add the remote-notification background mode to your Info.plist at Platforms/iOS/Info.plist:
<!-- Background Modes: enable remote (push) notifications delivery in background -->
<key>UIBackgroundModes</key>
<array>
<string>remote-notification</string>
</array>
Step 3. Configure Code Signing in the .csproj
Add the signing configuration to your .csproj file to use the provisioning profile you created:
<PropertyGroup Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'ios'">
<!-- Team and signing identity -->
<CodesignKey>Apple Development: Your Name (XXXXXXXXXX)</CodesignKey>
<CodesignProvision>Your Provisioning Profile Name</CodesignProvision>
<TeamId>YOUR_TEAM_ID</TeamId>
<!-- Entitlements with aps-environment for push notifications -->
<CodesignEntitlements>Platforms\iOS\Entitlements.plist</CodesignEntitlements>
</PropertyGroup>
Step 4. Enable Automatic Push Configuration
In your AppDelegate.cs, call EnableAutomaticPushConfig() before the SDK is set up. This enables method swizzling so the Userpilot SDK automatically handles registering for remote notifications, receiving the device push token, and handling notification responses.
// Platforms/iOS/AppDelegate.cs
using Foundation;
[Register("AppDelegate")]
public class AppDelegate : MauiUIApplicationDelegate
{
protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp();
public override bool FinishedLaunching(UIKit.UIApplication application, NSDictionary? launchOptions)
{
// MUST be called BEFORE Userpilot SDK setup
Userpilot.UserpilotSdk.EnableAutomaticPushConfig();
return base.FinishedLaunching(application, launchOptions);
}
}
Android Setup
Prerequisites
Configure your Android push settings in the Userpilot Settings Studio before setting up push notifications in your app.
To obtain the required keys and configuration details, refer to the Android Push Notification Guide.
Setup
Step 1. Firebase Project Configuration
Follow the steps in the official Google documentation on How to add Firebase to your project.
Step 2. Register google-services.json in the .csproj
Add the GoogleServicesJson build action in your .csproj so .NET MAUI processes it and generates the required Android string resources (google_app_id, gcm_defaultSenderId, etc.):
<ItemGroup Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'android'">
<GoogleServicesJson Include="Platforms\Android\google-services.json" />
</ItemGroup>
Step 3. Add the Userpilot Firebase Messaging Service and Push Notification Permissions
Add the required permissions and the Userpilot Firebase Messaging Service to your AndroidManifest.xml at Platforms/Android/AndroidManifest.xml:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application android:allowBackup="true" android:supportsRtl="true">
<!-- Userpilot push notification service (handles Firebase messages) -->
<service
android:name="com.userpilot.pushNotifications.UserpilotFirebaseMessagingService"
android:exported="false">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
</application>
<!-- Required for push notifications on Android 13+ (API 33) -->
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
</manifest>
Step 4. Configure Notification Appearance
Create a resource file at Platforms/Android/Resources/values/userpilot.xml to customize the notification appearance:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- Small icon displayed in the notification bar -->
<drawable name="userpilot_notification_small_icon">@drawable/userpilot_ic_notification</drawable>
<!-- Accent color applied to notification UI elements -->
<color name="userpilot_notification_color">#6765E8</color>
<!-- Lock screen visibility (true = visible) -->
<bool name="userpilot_notification_channel_lock_screen_visibility">true</bool>
<!-- Enable notification lights -->
<bool name="userpilot_notification_channel_enable_light">true</bool>
<!-- Enable vibration -->
<bool name="userpilot_notification_channel_enable_vibration">true</bool>
<!-- Notification channel configuration -->
<string name="userpilot_notification_channel_id">com.userpilot.general.channel</string>
<string name="userpilot_notification_channel_name">General</string>
<string name="userpilot_notification_channel_description">Default channel used for app messages</string>
<!-- Importance level (0 = NONE, 5 = MAX) -->
<integer name="userpilot_notification_channel_importance">3</integer>
<!-- Push notification deep link key -->
<string name="userpilot_push_notification">userpilot_push_notification</string>
</resources>
Step 5. Handle Push Notification Intents in MainActivity
Configure your MainActivity.cs to forward push notification intents to the Userpilot SDK. Use LaunchMode.SingleTop to ensure deep links are routed to the existing activity instance.
// Platforms/Android/MainActivity.cs
using Android.App;
using Android.Content;
using Android.Content.PM;
using Android.OS;
[Activity(
Theme = "@style/Maui.SplashTheme",
MainLauncher = true,
LaunchMode = LaunchMode.SingleTop,
ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation |
ConfigChanges.UiMode | ConfigChanges.ScreenLayout |
ConfigChanges.SmallestScreenSize | ConfigChanges.Density)]
[IntentFilter(
new[] { Intent.ActionView },
Categories = new[] { Intent.CategoryDefault, Intent.CategoryBrowsable },
DataScheme = "userpilot_push_notification",
DataHost = "sdk")]
public class MainActivity : MauiAppCompatActivity
{
protected override void OnCreate(Bundle? savedInstanceState)
{
base.OnCreate(savedInstanceState);
// Handle launch intent (cold start from push notification)
if (Intent != null)
{
Userpilot.UserpilotSdk.HandleIntent(Intent);
}
}
protected override void OnNewIntent(Intent? intent)
{
base.OnNewIntent(intent);
// Handle intent when app is already running (warm start from push notification)
if (intent != null)
{
Userpilot.UserpilotSdk.HandleIntent(intent);
}
}
}
Using ProGuard / R8 (Android)
If you are using R8 or ProGuard for code shrinking, add the following rules to your ProGuard configuration file (for example, Platforms/Android/proguard.cfg):
# Keep Userpilot SDK classes
-keep class com.userpilot.** { *; }
-keep class com.microsoft.mauiuserpilot.** { *; }
# Keep Kotlin classes needed by Userpilot
-keep class kotlin.** { *; }
-keep class kotlinx.** { *; }
# Keep MAUI classes
-keep class crc*.** { *; }
-keep class mono.** { *; }
-keep class android.runtime.** { *; }
# Keep callbacks and interfaces
-keepclassmembers class * implements com.microsoft.mauiuserpilot.UserpilotSdk$Companion$NavigationCallback {
<methods>;
}
-keepclassmembers class * implements com.microsoft.mauiuserpilot.UserpilotSdk$Companion$AnalyticsCallback {
<methods>;
}
-keepclassmembers class * implements com.microsoft.mauiuserpilot.UserpilotSdk$Companion$ExperienceCallback {
<methods>;
}
# Don't warn about missing classes in libraries
-dontwarn okhttp3.**
-dontwarn okio.**
-dontwarn javax.annotation.**
-dontwarn org.conscrypt.**
-dontwarn com.squareup.moshi.**
-dontwarn androidx.**
# Keep OkHttp and Moshi for network calls
-keep class com.squareup.moshi.** { *; }
-keep class okhttp3.** { *; }
-keep class okio.** { *; }
# Keep Coil image loading library (used by Userpilot SDK for experience images)
-keep class coil.** { *; }
-keep class coil.base.** { *; }
-keep class coil.util.** { *; }
-keep class coil.request.** { *; }
-keep class coil.decode.** { *; }
-keep class coil.fetch.** { *; }
-keep class coil.map.** { *; }
-keep class coil.memory.** { *; }
-keep class coil.network.** { *; }
-keep class coil.size.** { *; }
-keep class coil.transform.** { *; }
-keep class coil.transition.** { *; }
-keep class coil.disk.** { *; }
-dontwarn coil.**
# Keep AndroidSVG (used by Coil for SVG support)
-keep class com.caverock.androidsvg.** { *; }
-dontwarn com.caverock.androidsvg.**
# Firebase
-keep class com.google.firebase.** { *; }
-dontwarn com.google.firebase.**
# Allow duplicate definitions - R8 will use the first one it finds
-ignorewarnings
Then reference it in your .csproj:
<ProguardConfiguration Include="Platforms\Android\proguard.cfg" />