> ## Documentation Index
> Fetch the complete documentation index at: https://docs.userpilot.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Push Notifications

> Set up and customize push notifications with the Userpilot MAUI SDK

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](https://run.userpilot.io/settings/mobile) before setting up push notifications in your app.

To obtain the required keys and configuration details, refer to the [iOS Push Notification Guide](../ios-push-notification-setup-guide).

### Setup

**Step 1. Enable Push Notifications Capability**

Add the `aps-environment` entitlement to your `Entitlements.plist` file at `Platforms/iOS/Entitlements.plist`:

```xml theme={null}
<?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>
```

<Tip>
  **Note**

  Change `development` to `production` when publishing to the App Store.
</Tip>

**Step 2. Enable Background Remote Notifications**

Add the `remote-notification` background mode to your `Info.plist` at `Platforms/iOS/Info.plist`:

```xml theme={null}
<!-- 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:

```xml theme={null}
<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.

```csharp theme={null}
// 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](https://run.userpilot.io/settings/mobile) before setting up push notifications in your app.

To obtain the required keys and configuration details, refer to the [Android Push Notification Guide](../android-push-notification-setup-guide).

### Setup

**Step 1. Firebase Project Configuration**

Follow the steps in the official Google documentation on [How to add Firebase to your project](https://firebase.google.com/docs/android/setup).

**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.):

```xml theme={null}
<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 theme={null}
<?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 theme={null}
<?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.

```csharp theme={null}
// 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`):

```proguard theme={null}
# 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`:

```xml theme={null}
<ProguardConfiguration Include="Platforms\Android\proguard.cfg" />
```

<Frame>
  [**For any questions or concerns please reach out to support@userpilot.com**](mailto:support@userpilot.com)
</Frame>
