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
asEverything
. It will help notifications' timing. - Make sure that
Notification Icons
have at least two icons that named asicon_0
(for the small one) andicon_1
(for the large one)
- Make sure that
- 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.
- Make sure that
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 thatMeteor
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
totrue
.- Provide a remote value for
manualNotificationPermissionRequest
.
- Provide a remote value for
- 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
andWhenFailedToInitialize
. Delays execution ofcallback
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
Variable | Remote Name | Description |
---|---|---|
Enabled | notificationsEnabled | Enabling/disabling the module |
AutoInitialize | N/A | If enabled, you don't need to call Initialize method manually. |
Time Range Start | notificationTimeRangeStart | Hour of day in a 0-24 hour system. Decimal places determine the fraction of an hour. 7:30 AM means 7.5. |
Time Range End | notificationTimeRangeEnd | Notifications 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. |