Skip to main content

Charlie Notifications Module

Overview

Provides a simple way of adding locally scheduled notifications to a project.

Installing

  • Import package from Package Manager UI.
  • Go to Project Settings > Mobile Notifications > Android:
    • Make sure that Reschedule on Device Restart is enabled.
    • You can set Schedule at exact time as Everything. It will help notifications' timing.
    • Make sure that Notification Icons have at least two icons that named as icon_0 (for the small one) and icon_1 (for the large one)
  • Go to Project Settings > Mobile Notifications > iOS:
    • Make sure that Request Authorization on App Launch is disabled.
    • Make sure that Enable Push Notifications is enabled.
    • Make sure that Enable Release Environment for APS is enabled.

How to use

  • Call Charlie.Instance.Initialize() in the appropriate place.
    • It handles authorization and permission request automatically.
    • If Meteor package is present, make sure that Meteor is initialized before Charlie.
  • Use the Charlie.GetBuilder() method to create a notification builder. See Notification
  • Use methods of the notification builder to configure the notification
  • Schedule the notification locally by calling Build() on the notification builder.

Ask For Permission Manually

Charlie is only initialized when the user grants notification permission. Therefore, the permission is asked when Charlie.Instance.Initialize() call is made. Make sure to set Manual Notification Permission Request to true in the configuration.

  • Open Matchingham > Notifications in the editor.
  • Set Manual Notification Permission Request to true.
    • Provide a remote value for manualNotificationPermissionRequest.
  • Call Charlie.Instance.Initialize() when you want to initialize Charlie from game code.

How does it Work?

Charlie works as a proxy object to schedule notifications for the current platform. Platform specific logic and types are merged in unified data structures and are translated to their platform specific counterparts by the Charlie module.

Let's pretend we have a game manager that initializes our game at awake.

public class GameManager : MonoBehaviour
{
public static bool IsFirstSession { get; private set; }

private void Awake()
{
CheckFirstSession();

// Remote config module
Meteor.Instance.Initialize();
Meteor.Instance.WhenReady(_ =>
{
// Now remote config is ready

// Initialize notifications module
Charlie.Instance.Initialize();
Charlie.Instance.WhenReady(_ =>
{
// On iOS and Android 13+, notifications module will block this call if auth
// request is necessary and will auto prompt the user.
// This method will be called after user responds to prompt
NotifyGameReady();
});
});
}
}

Let's assume we want to implement a notification that is fired 3 hours after first session and repeats in a daily interval afterwards. Following code would achieve it.

private void OnFocusStateChanged(bool hasFocus)
{
if (hasFocus)
{
if (GameManager.IsFirstSession)
{
Charlie.CancelNotification(1);
}
}
else
{
if (GameManager.IsFirstSession)
{
Charlie.GetBuilder()
.Override() // Override notification if it was already scheduled
.ShowInForeground() // Show notification on foreground (iOS specific)
.WithId(1) // Set notification ID
.WithTitle("My Notification") // Set notification title
.WithSubTitle("My Notification Subtitle") // Set notification sub title
.WithBody("Here goes the notification message") // Set notification body
.WithSmallIcon("icon_name") // Name of small icon to use (Android specific)
.WithLargeIcon("icon_name") // Name of large icon to use (Android specific)
.WithDeliveryDelay(TimeSpan.FromDays(2)) // Set how long after the notification will be shown
.Repeat(TimeSpan.FromDays(1)) // Mark repeating and set the repeat interval
.Build(); // Build and schedule notification

Charlie.GetBuilder()
.Override() // Override notification if it was already scheduled
.ShowInForeground() // Show notification on foreground (iOS specific)
.WithId(2) // Set notification ID
.WithTitle("My Notification") // Set notification title
.WithSubTitle("My Notification Subtitle") // Set notification sub title
.WithBody("Here goes the notification message") // Set notification body
.WithSmallIcon("icon_name") // Name of small icon to use (Android specific)
.WithLargeIcon("icon_name") // Name of large icon to use (Android specific)
.WithDeliveryDate(DateTime.Now.AddDays(3)) // Set a specific date for the notifciation delivery
.Repeat(TimeSpan.FromDays(1)) // Mark repeating and set the repeat interval
.Build(); // Build and schedule notification
}
}
}

If we want to schedule a notification after each session, we could do it as follows:

private void OnFocusStateChanged(bool hasFocus)
{
if (hasFocus)
{
if (GameManager.IsFirstSession)
{
Charlie.CancelNotification(2);
}
}
else
{
if (GameManager.IsFirstSession)
{
Charlie.GetBuilder()
.Override() // Override notification if it was already scheduled
.ShowInForeground() // Show notification on foreground (iOS specific)
.WithId(1) // Set notification ID
.WithTitle("My Notification") // Set notification title
.WithSubTitle("My Notification Subtitle") // Set notification sub title
.WithBody("Here goes the notification message") // Set notification body
.WithSmallIcon("icon_name") // Name of small icon to use (Android specific)
.WithLargeIcon("icon_name") // Name of large icon to use (Android specific)
.WithDeliveryDelay(TimeSpan.FromDays(2)) // Set how long after the notification will be shown
.Build(); // Build and schedule notification

Charlie.GetBuilder()
.Override() // Override notification if it was already scheduled
.ShowInForeground() // Show notification on foreground (iOS specific)
.WithId(2) // Set notification ID
.WithTitle("My Notification") // Set notification title
.WithSubTitle("My Notification Subtitle") // Set notification sub title
.WithBody("Here goes the notification message") // Set notification body
.WithSmallIcon("icon_name") // Name of small icon to use (Android specific)
.WithLargeIcon("icon_name") // Name of large icon to use (Android specific)
.WithDeliveryDate(DateTime.Now.AddDays(3)) // Set a specific date for the notifciation delivery
.Build(); // Build and schedule notification
}
}
}

If we want to configure a notification from remote, we can do it by using the Meteor module.

// GameNotificationsConfig.cs
public class GameNotificationsConfig : ScriptableObject
{
[RemoteSetting("myNotificationTitle")]
public string myNotificationTitle;

[RemoteSetting("myNotificationBody")]
public string myNotificationBody;

[RemoteSetting("myNotificationDelayInHours")]
public int myNotificationDelayInHours;
}


// GameManager.cs
public class GameManager : SingletonBehaviour<GameManager>
{
private GameNotificationsConfig notificationsConfig;

public GameNotificationsConfig NotificationsConfig => notificationsConfig;

private void Awake()
{
// You need to add config before initialize call
Meteor.RegisterConfig(notificationsConfig);

Meteor.Intance.Initialize();
Meteor.Instance.WhenReady(_ =>
{
Charlie.Instance.Initialize();
Charlie.Instance.WhenReady(_ =>
{
// Rest of the initialization logic
ContinueInitialization();
});
});
}
}


// GameNotifications.cs
private void OnFocusStateChanged(bool hasFocus)
{
if (hasFocus)
{
Charlie.CancelNotification(1);
}
else
{
Charlie.GetBuilder()
.Override()
.WithId(1)
.WithTitle(notificationConfig.myNotificationTitle)
.WithBody(notificationConfig.myNotificationBody)
.WithDeliveryDelay(TimeSpan.FromHours(notificationConfig.myNotificationDelayInHours))
.Build();
}
}

If you want to send an event when the user opens the game by clicking on the notification, you can use NotificationEventData class, serialize to JSON and setting it as ExtraData.

public sealed class NotificationEventData
{
public string Name;
public Dictionary<string, object> Parameters;
}

private void OnFocusStateChanged(bool hasFocus)
{
if (hasFocus)
{
Charlie.CancelNotification(1);
}
else
{
Charlie.GetBuilder()
.Override()
.WithId(1)
.WithTitle("Title")
.WithBody("Body")
.WithDeliveryDate(DateTime.Now.AddHours(2))
.WithSmallIcon("icon_0")
.WithLargeIcon("icon_1")
.WithExtraData(JsonConvert.SerializeObject(new NotificationEventData
{
Name = "notification_opened",
Parameters = new Dictionary<string, object>
{
{ "notification_id", 1 }
}
}))
.Build();
}
}

You can find more detailed examples in samples.

One Important thing to note is, Charlie module has a time range configuration in CharlieConfig. This configuration determines which notifications should be scheduled. Range is defined by timeRangeStart and timeRangeEnd fields, any notification with a delivery date outside of the time range defined by these fields will be dropped.

API & Details

Charlie

Methods

  • GetBuilder() : INotificationBuilder : Returns a notification builder that can be used to configure and schedule a notification.

  • CancelNotification(notification: Notification) : void : Cancels a scheduled notification.

  • CancelNotification(id: int) : void : Cancels a scheduled notification.

  • CancelAllScheduledNotifications() : void : Removes all scheduled notifications.

  • CancelAllDisplayedNotifications() : void : Removes all displayed notifications.

  • ValidateNotification() : bool : Validates a notification if it is scheduled

Events

  • NotificationReceived(id: int, data: string) : Invokes when a notification is received while the game is running

  • NotificationClicked(id: int, data: string) : Invokes when the game is opened by the user clicks on the notification

Fields

  • DeviceToken : Device Token (for iOS only: if the user doesn't permit notifications, this will be empty.)

INotificationBuilder

Methods

  • Override() : INotificationBuilder : Sets a flag to override an existing notification with the same id

  • ShowInForeground() : INotificationBuilder : Sets a flag to show the notification in the foreground on iOS platform

  • WithId(string) : INotificationBuilder : Sets the title of the notification

  • WithSubTitle(string) : INotificationBuilder : Sets the title of the notification

  • WithBody(string) : INotificationBuilder : Sets the body of the notification

  • WithSmallIcon(string) : INotificationBuilder : Sets the small icon name for the notification

  • WithLargeIcon(string) : INotificationBuilder : Sets the large icon name of the notification

  • WithExtraData(string) : INotificationBuilder : Sets a data string to be passed when notification events are fired

  • Repeat(TimeSpan) : INotificationBuilder : Marks the notification as a repeating notification and provides the repeat interval

  • WithDeliveryDate(DateTime) : ISpecificDateNotificationBuilder : Marks the notification to be delivered at a specific date & time, and provides the date & time information

  • WithDeliveryDelay(TimeSpan) : IDelayedNotificationBuilder : Marks the notification to be delivered with a delay. Notification will be shown a delay amount of time after the schedule time

Common

Methods

  • Initialize() : Starts module initialization. You need to call this at the appropriate place.

  • WhenInitialized(Action callback) : Allows you to register callback that will be fired only after the module is successfully initialized. Use this to execute logic that requires this module to be initialized first. If the module has already initialized, immediately invokes the callback.

  • WhenFailedToInitialize(Action callback) : Allows you to register callback that will be fired only after the module fails to initialize for any reason. Use this to handle what should happen in case this module fails to initialize. If the module has already failed to initialize, immediately invokes the callback.

  • WhenReady(Action callback) : Combined version of WhenInitialized and WhenFailedToInitialize. Delays execution of callback till module is first initialized or failed to initialize, immediately invoke the callback if it is already initialized or failed to initialize.

Fields

  • State : Initialization state of the module

  • Instance : Instance of the module

  • LateInitialized : When the module needs an internet connection but the player became online while playing the game, this becomes true

  • Ready : If the module is initialized successfully and ready to operate

  • Config : Configuration of the module. See configuration

  • Parameters: SerializableDictionary<key: string, parameters: object> : Extra parameters

Configuration

Go to Matchingham > Notifications

VariableRemote NameDescription
EnablednotificationsEnabledEnabling/disabling the module
AutoInitializeN/AIf enabled, you don't need to call Initialize method manually.
Time Range StartnotificationTimeRangeStartHour of day in a 0-24 hour system. Decimal places determine the fraction of an hour. 7:30 AM means 7.5.
Time Range EndnotificationTimeRangeEndNotifications can only be scheduled if they are between timeRangeStart and timeRangeEnd hours. Hour of day in a 0-24 hour system. Decimal places determine the fraction of an hour. 7:30 AM means 7.5.