From 295c6f269ffac59ed1f747e8c43abd40536ebdef Mon Sep 17 00:00:00 2001 From: Unity Technologies <@unity> Date: Tue, 5 Sep 2023 00:00:00 +0000 Subject: [PATCH] com.unity.services.push-notifications@4.0.0-pre.1 ## [4.0.0-pre.1] - 2023-09-05 ### Changed - You can now only subscribe to OnNotificationReceived before calling RegisterForPushNotificationsAsync - Once RegisterForPushNotificationsAsync completes, OnNotificationReceived will be invoked if the app was launched from a remote notification - Updated `com.unity.services.analytics` dependency to 5.0.0 - Updated `com.unity.services.core` dependency to 1.10.1 - Added `com.unity.mobile.notifications` version `2.2.0` as a dependency. ### Fixed - Behaviour when the app is launched from a push notification is now consistent between iOS and Android (incoming push notification data is broadcast after RegisterForPushNotificationsAsync flow is complete) ## [3.0.1-pre.2] - 2023-08-15 ### Fixed - Bug fix for PushNotificationsService's OnNotificationReceived not being called on IOS - Bug fix where RegisterForPushNotificationsAsync is stuck when the user disables notification settings. --- CHANGELOG.md | 21 ++ ...y.Services.PushNotifications.Editor.asmdef | 4 +- .../PushNotificationsAndroidLib-release.aar | Bin 34344 -> 35346 bytes ...shNotificationsAndroidLib-release.aar.meta | 31 ++- Plugins/iOS/PushNotificationManager.h | 29 --- Plugins/iOS/PushNotificationManager.h.meta | 80 ------- Plugins/iOS/PushNotificationManager.mm | 212 ------------------ Plugins/iOS/PushNotificationManager.mm.meta | 85 ------- Plugins/iOS/PushNotificationManagerWrapper.h | 11 - .../iOS/PushNotificationManagerWrapper.h.meta | 80 ------- Plugins/iOS/PushNotificationManagerWrapper.mm | 22 -- .../PushNotificationManagerWrapper.mm.meta | 85 ------- Runtime/Analytics/EventsWrapper.cs | 30 --- .../Analytics/IPushNotificationsAnalytics.cs | 23 +- Runtime/Analytics/PushAnalytics.cs | 89 ++++++++ ...nalytics.cs.meta => PushAnalytics.cs.meta} | 0 .../Analytics/PushNotificationAnalytics.cs | 106 --------- Runtime/Android.meta | 8 - Runtime/Android/AndroidPushNotifications.cs | 183 --------------- Runtime/AssemblyInternals.cs | 2 + Runtime/IPushNotificationsService.cs | 21 +- Runtime/MainThreadHelper.cs | 18 +- Plugins/iOS.meta => Runtime/Platforms.meta | 2 +- Runtime/Platforms/AndroidPushNotifications.cs | 166 ++++++++++++++ .../AndroidPushNotifications.cs.meta | 0 Runtime/Platforms/IPlatformLogic.cs | 44 ++++ .../IPlatformLogic.cs.meta} | 2 +- Runtime/Platforms/iOSPushNotifications.cs | 121 ++++++++++ .../iOSPushNotifications.cs.meta | 0 Runtime/PushNotificationCoreInitialization.cs | 29 ++- Runtime/PushNotificationReceivedHandler.cs | 50 ----- .../PushNotificationReceivedHandler.cs.meta | 3 - Runtime/PushNotificationsContainer.cs | 67 ++++++ Runtime/PushNotificationsContainer.cs.meta | 3 + Runtime/PushNotificationsServiceInstance.cs | 146 +++++++----- ...icsPlatformWrapper.cs => SystemWrapper.cs} | 23 +- ...mWrapper.cs.meta => SystemWrapper.cs.meta} | 0 Runtime/Unity.Services.PushNotifications.api | 6 +- .../Unity.Services.PushNotifications.asmdef | 6 +- Runtime/iOS.meta | 8 - Runtime/iOS/iOSPushNotifications.cs | 128 ----------- Samples~/Example/PushNotificationExample.cs | 21 +- ValidationExceptions.json | 2 +- package.json | 17 +- 44 files changed, 753 insertions(+), 1231 deletions(-) delete mode 100644 Plugins/iOS/PushNotificationManager.h delete mode 100644 Plugins/iOS/PushNotificationManager.h.meta delete mode 100644 Plugins/iOS/PushNotificationManager.mm delete mode 100644 Plugins/iOS/PushNotificationManager.mm.meta delete mode 100644 Plugins/iOS/PushNotificationManagerWrapper.h delete mode 100644 Plugins/iOS/PushNotificationManagerWrapper.h.meta delete mode 100644 Plugins/iOS/PushNotificationManagerWrapper.mm delete mode 100644 Plugins/iOS/PushNotificationManagerWrapper.mm.meta delete mode 100644 Runtime/Analytics/EventsWrapper.cs create mode 100644 Runtime/Analytics/PushAnalytics.cs rename Runtime/Analytics/{PushNotificationAnalytics.cs.meta => PushAnalytics.cs.meta} (100%) delete mode 100644 Runtime/Analytics/PushNotificationAnalytics.cs delete mode 100644 Runtime/Android.meta delete mode 100644 Runtime/Android/AndroidPushNotifications.cs rename Plugins/iOS.meta => Runtime/Platforms.meta (77%) create mode 100644 Runtime/Platforms/AndroidPushNotifications.cs rename Runtime/{Android => Platforms}/AndroidPushNotifications.cs.meta (100%) create mode 100644 Runtime/Platforms/IPlatformLogic.cs rename Runtime/{Analytics/EventsWrapper.cs.meta => Platforms/IPlatformLogic.cs.meta} (83%) create mode 100644 Runtime/Platforms/iOSPushNotifications.cs rename Runtime/{iOS => Platforms}/iOSPushNotifications.cs.meta (100%) delete mode 100644 Runtime/PushNotificationReceivedHandler.cs delete mode 100644 Runtime/PushNotificationReceivedHandler.cs.meta create mode 100644 Runtime/PushNotificationsContainer.cs create mode 100644 Runtime/PushNotificationsContainer.cs.meta rename Runtime/{Analytics/PushNotificationsAnalyticsPlatformWrapper.cs => SystemWrapper.cs} (52%) rename Runtime/{Analytics/PushNotificationsAnalyticsPlatformWrapper.cs.meta => SystemWrapper.cs.meta} (100%) delete mode 100644 Runtime/iOS.meta delete mode 100644 Runtime/iOS/iOSPushNotifications.cs diff --git a/CHANGELOG.md b/CHANGELOG.md index dc73592..d059c68 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,27 @@ All notable changes to this package will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). +## [4.0.0-pre.1] - 2023-09-05 + +### Changed + +- You can now only subscribe to OnNotificationReceived before calling RegisterForPushNotificationsAsync + - Once RegisterForPushNotificationsAsync completes, OnNotificationReceived will be invoked if the app was launched from a remote notification +- Updated `com.unity.services.analytics` dependency to 5.0.0 +- Updated `com.unity.services.core` dependency to 1.10.1 +- Added `com.unity.mobile.notifications` version `2.2.0` as a dependency. + +### Fixed + +- Behaviour when the app is launched from a push notification is now consistent between iOS and Android (incoming push notification data is broadcast after RegisterForPushNotificationsAsync flow is complete) + +## [3.0.1-pre.2] - 2023-08-15 + +### Fixed + +- Bug fix for PushNotificationsService's OnNotificationReceived not being called on IOS +- Bug fix where RegisterForPushNotificationsAsync is stuck when the user disables notification settings. + ## [3.0.1-pre.1] - 2023-03-20 ### Fixed diff --git a/Editor/Unity.Services.PushNotifications.Editor.asmdef b/Editor/Unity.Services.PushNotifications.Editor.asmdef index f376cda..a5a8c10 100644 --- a/Editor/Unity.Services.PushNotifications.Editor.asmdef +++ b/Editor/Unity.Services.PushNotifications.Editor.asmdef @@ -4,7 +4,9 @@ "Unity.Services.PushNotifications", "Unity.Services.Core", "Unity.Services.Core.Internal", - "Unity.Services.Core.Editor" + "Unity.Services.Core.Editor", + "Unity.Notifications.iOS", + "Unity.Notifications.Android" ], "includePlatforms": [ "Editor" diff --git a/Plugins/Android/PushNotificationsAndroidLib-release.aar b/Plugins/Android/PushNotificationsAndroidLib-release.aar index e8d73b5e7e2ec2655d738266e61e751919775b91..affa22fc44a2dc378ea3f1009f0175685cb49355 100644 GIT binary patch delta 11037 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 Xff19Pg*XBuh?CcaO9rlp000007-OeF delta 10031 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 F000GBtM~u_ diff --git a/Plugins/Android/PushNotificationsAndroidLib-release.aar.meta b/Plugins/Android/PushNotificationsAndroidLib-release.aar.meta index 0162bca..986735a 100644 --- a/Plugins/Android/PushNotificationsAndroidLib-release.aar.meta +++ b/Plugins/Android/PushNotificationsAndroidLib-release.aar.meta @@ -1,3 +1,32 @@ fileFormatVersion: 2 guid: ef86ab48496543d195b88fd51a57d171 -timeCreated: 1675220299 \ No newline at end of file +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 1 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + Android: Android + second: + enabled: 1 + settings: {} + - first: + Any: + second: + enabled: 0 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + userData: + assetBundleName: + assetBundleVariant: diff --git a/Plugins/iOS/PushNotificationManager.h b/Plugins/iOS/PushNotificationManager.h deleted file mode 100644 index 10f3138..0000000 --- a/Plugins/iOS/PushNotificationManager.h +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef PushNotificationManager_h -#define PushNotificationManager_h - -#import "UnityAppController.h" -#import - -// Required for internal messaging constants. -#include "Classes/PluginBase/LifeCycleListener.h" -#include "Classes/PluginBase/AppDelegateListener.h" - -typedef void (REGISTRATION_CALLBACK)(char *token); -typedef void (NOTIFICATION_CALLBACK)(char *serialisedUserInfo); - -@interface PushNotificationManager : NSObject - -@property NSString *deviceToken; -@property (nonatomic) REGISTRATION_CALLBACK *registrationCallback; -@property (nonatomic) NOTIFICATION_CALLBACK *notificationCallback; - -+ (instancetype)sharedInstance; -- (void) registerForRemoteNotifications : (REGISTRATION_CALLBACK) callback; -- (char *) getLaunchedNotificationString; -- (void) resetLaunchedNotificationString; -- (void) flushNotificationBuffer; - -@end - -#endif - diff --git a/Plugins/iOS/PushNotificationManager.h.meta b/Plugins/iOS/PushNotificationManager.h.meta deleted file mode 100644 index 28eb743..0000000 --- a/Plugins/iOS/PushNotificationManager.h.meta +++ /dev/null @@ -1,80 +0,0 @@ -fileFormatVersion: 2 -guid: 46294242127bd47e493a651900fee6cb -PluginImporter: - externalObjects: {} - serializedVersion: 2 - iconMap: {} - executionOrder: {} - defineConstraints: [] - isPreloaded: 0 - isOverridable: 1 - isExplicitlyReferenced: 0 - validateReferences: 1 - platformData: - - first: - : Any - second: - enabled: 0 - settings: - Exclude Android: 1 - Exclude Editor: 1 - Exclude Linux64: 1 - Exclude OSXUniversal: 1 - Exclude Win: 1 - Exclude Win64: 1 - Exclude iOS: 0 - - first: - Android: Android - second: - enabled: 0 - settings: - CPU: ARMv7 - - first: - Any: - second: - enabled: 0 - settings: {} - - first: - Editor: Editor - second: - enabled: 0 - settings: - CPU: AnyCPU - DefaultValueInitialized: true - OS: AnyOS - - first: - Standalone: Linux64 - second: - enabled: 0 - settings: - CPU: None - - first: - Standalone: OSXUniversal - second: - enabled: 0 - settings: - CPU: None - - first: - Standalone: Win - second: - enabled: 0 - settings: - CPU: None - - first: - Standalone: Win64 - second: - enabled: 0 - settings: - CPU: None - - first: - iPhone: iOS - second: - enabled: 1 - settings: - AddToEmbeddedBinaries: false - CPU: AnyCPU - CompileFlags: - FrameworkDependencies: UserNotifications; - userData: - assetBundleName: - assetBundleVariant: diff --git a/Plugins/iOS/PushNotificationManager.mm b/Plugins/iOS/PushNotificationManager.mm deleted file mode 100644 index 3efac9f..0000000 --- a/Plugins/iOS/PushNotificationManager.mm +++ /dev/null @@ -1,212 +0,0 @@ -#import -#import -#import - -#import "PushNotificationManager.h" - -//MARK: Internal Class. Not publicly supported. Do not use directly. -@implementation PushNotificationManager : NSObject - -NSArray *bufferedNotifications; - -NSString *launchedNotificationString; - -+ (void)load { - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - [PushNotificationManager sharedInstance]; - - UNUserNotificationCenter* center = [UNUserNotificationCenter currentNotificationCenter]; - center.delegate = [PushNotificationManager sharedInstance]; - }); -} - -// MARK: Interface implementations - -+ (instancetype)sharedInstance -{ - static PushNotificationManager *sharedInstance = nil; - - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - sharedInstance = [[PushNotificationManager alloc] init]; - bufferedNotifications = [[NSArray alloc] init]; - launchedNotificationString = nil; - - NSNotificationCenter *nc = [NSNotificationCenter defaultCenter]; - - [nc addObserver:sharedInstance - selector:@selector(didRegisterForRemoteNotifications:) - name:kUnityDidRegisterForRemoteNotificationsWithDeviceToken - object:nil]; - - [nc addObserver:sharedInstance - selector:@selector(didFailToRegisterForRemoteNotifications:) - name:kUnityDidFailToRegisterForRemoteNotificationsWithError - object:nil]; - - [nc addObserver:sharedInstance - selector:@selector(didReceiveNotification:) - name:kUnityDidReceiveRemoteNotification - object:nil]; - - [nc addObserver:sharedInstance - selector:@selector(createLaunchedNotificationChecker:) - name:@"UIApplicationDidFinishLaunchingNotification" - object:nil]; - }); - - return sharedInstance; -} - -/// Called externally to register for push notifications. Initally requests notification permissions, -/// then registers to get a device token, which will be handled by one of the notification handlers. -- (void) registerForRemoteNotifications : (REGISTRATION_CALLBACK) callback -{ - // If we've already registered for a token previously, and have one ready, then just return it without - // requesting authorisation again. - if (_deviceToken != NULL && _deviceToken.length > 0) { - callback((char *)_deviceToken.UTF8String); - return; - } - - _registrationCallback = callback; - - // Register for the permissions to display notifications from the iOS system. Without this, we'd receive - // the pushes but wouldn't be able to display them to a user. - UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter]; - NSInteger authOptions = (UNAuthorizationOptionSound + UNAuthorizationOptionAlert + UNAuthorizationOptionBadge); - [center requestAuthorizationWithOptions:authOptions completionHandler:^(BOOL granted, NSError *error) { - if (granted) { - dispatch_async(dispatch_get_main_queue(), ^{ - [[UIApplication sharedApplication] registerForRemoteNotifications]; - }); - } - }]; -} - -// MARK: Delegate methods - -- (void) userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions))completionHandler -{ - NSDictionary *userInfo = notification.request.content.userInfo; - [self handleReceivedNotificationUserInfo:userInfo]; - completionHandler((UNAuthorizationOptionSound + UNAuthorizationOptionAlert + UNAuthorizationOptionBadge)); -} - -// MARK: Internal methods - -- (void) didRegisterForRemoteNotifications: (NSNotification *) notification -{ - if ([notification.userInfo isKindOfClass:[NSData class]]) - { - NSString *token = [[PushNotificationManager sharedInstance] getDeviceTokenFromNSData: (NSData*)notification.userInfo]; - [PushNotificationManager sharedInstance].deviceToken = token; - [PushNotificationManager sharedInstance].registrationCallback((char *)token.UTF8String); - } -} - -- (void) didFailToRegisterForRemoteNotifications: (NSNotification *) notification -{ - NSLog(@"Failed to register for push notifications"); -} - -- (void) didReceiveNotification: (NSNotification *) notification -{ - NSDictionary *userInfoDictionary = notification.userInfo; - [self handleReceivedNotificationUserInfo:userInfoDictionary]; -} - -- (void) handleReceivedNotificationUserInfo: (NSDictionary *)userInfoDictionary -{ - if ([PushNotificationManager sharedInstance].notificationCallback == nil) { - // Unity hasn't had time to register the callback yet, so let's store the notification data until we're ready for it. - bufferedNotifications = [bufferedNotifications arrayByAddingObject:userInfoDictionary]; - return; - } - - char *jsonString = [self serializeRemoteNotification:userInfoDictionary]; - - [PushNotificationManager sharedInstance].notificationCallback(jsonString); -} - -- (void) flushNotificationBuffer -{ - NSMutableArray *tempBuffer = [NSMutableArray arrayWithArray:bufferedNotifications]; - NSMutableArray *emptyBuffer = [NSMutableArray arrayWithArray:bufferedNotifications]; - - [emptyBuffer removeAllObjects]; - bufferedNotifications = [NSArray arrayWithArray:emptyBuffer]; - - for (NSDictionary *bufferedData in tempBuffer) { - [self handleReceivedNotificationUserInfo:bufferedData]; - } -} - -- (char *) serializeRemoteNotification: (NSDictionary *)notificationDictionary -{ - NSError *error = nil; - NSData *data = [NSJSONSerialization dataWithJSONObject:notificationDictionary options:kNilOptions error:&error]; - - if (error != nil) - { - NSLog(@"Failed to serialize notification user info to string. User info was: %@", notificationDictionary); - return nil; - } - - char *jsonString = (char *) [[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] UTF8String]; - - return jsonString; -} - -/// Checks if app was launched from notification and sends to notification handler -- (void)createLaunchedNotificationChecker:(NSNotification *)notification -{ - NSDictionary *launchOptions = [notification userInfo]; - NSDictionary *launchedNotification = [launchOptions objectForKey: @"UIApplicationLaunchOptionsRemoteNotificationKey"]; - - if (launchedNotification) - { - char *serializedString = [self serializeRemoteNotification:launchedNotification]; - - launchedNotificationString = [NSString stringWithFormat:@"%s", serializedString]; - } -} - -- (char *) getLaunchedNotificationString -{ - return [[PushNotificationManager sharedInstance] convertNSStringToCString: launchedNotificationString]; -} - -- (void) resetLaunchedNotificationString -{ - launchedNotificationString = nil; -} - -// MARK: Helper methods - -- (NSString *)getDeviceTokenFromNSData:(NSData *)deviceTokenData { - const char *data = (const char *)[deviceTokenData bytes]; - NSMutableString *token = [NSMutableString string]; - - for (NSUInteger i = 0; i < [deviceTokenData length]; i++) { - [token appendFormat:@"%02.2hhX", data[i]]; - } - - return [token copy]; -} - -- (char *) convertNSStringToCString: (NSString*) nsString -{ - if (nsString == nil) - return nil; - - const char* nsStringUtf8 = [nsString UTF8String]; - //create a null terminated C string on the heap so that our string's memory isn't wiped out right after method's return - char* cString = (char*)malloc(strlen(nsStringUtf8) + 1); - strcpy(cString, nsStringUtf8); - - return cString; -} - -@end diff --git a/Plugins/iOS/PushNotificationManager.mm.meta b/Plugins/iOS/PushNotificationManager.mm.meta deleted file mode 100644 index a9c5d72..0000000 --- a/Plugins/iOS/PushNotificationManager.mm.meta +++ /dev/null @@ -1,85 +0,0 @@ -fileFormatVersion: 2 -guid: da538eb90ba2d4ee5b13504644879380 -PluginImporter: - externalObjects: {} - serializedVersion: 2 - iconMap: {} - executionOrder: {} - defineConstraints: [] - isPreloaded: 0 - isOverridable: 1 - isExplicitlyReferenced: 0 - validateReferences: 1 - platformData: - - first: - : Any - second: - enabled: 0 - settings: - Exclude Android: 1 - Exclude Editor: 1 - Exclude Linux64: 1 - Exclude OSXUniversal: 1 - Exclude Win: 1 - Exclude Win64: 1 - Exclude iOS: 0 - - first: - Android: Android - second: - enabled: 0 - settings: - CPU: ARMv7 - - first: - Any: - second: - enabled: 0 - settings: {} - - first: - Editor: Editor - second: - enabled: 0 - settings: - CPU: AnyCPU - DefaultValueInitialized: true - OS: AnyOS - - first: - Standalone: Linux64 - second: - enabled: 0 - settings: - CPU: None - - first: - Standalone: OSXUniversal - second: - enabled: 0 - settings: - CPU: None - - first: - Standalone: Win - second: - enabled: 0 - settings: - CPU: x86 - - first: - Standalone: Win64 - second: - enabled: 0 - settings: - CPU: x86_64 - - first: - iPhone: iOS - second: - enabled: 1 - settings: - AddToEmbeddedBinaries: false - CPU: AnyCPU - CompileFlags: - FrameworkDependencies: UserNotifications; - - first: - tvOS: tvOS - second: - enabled: 1 - settings: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Plugins/iOS/PushNotificationManagerWrapper.h b/Plugins/iOS/PushNotificationManagerWrapper.h deleted file mode 100644 index 85fe376..0000000 --- a/Plugins/iOS/PushNotificationManagerWrapper.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef PushNotificationManagerWrapper_h -#define PushNotificationManagerWrapper_h - -#import "PushNotificationManager.h" - -extern "C" void NativeRegisterForPushNotifications(REGISTRATION_CALLBACK callback); -extern "C" void RegisterUnityCallbackForNotificationReceived(NOTIFICATION_CALLBACK callback); -extern "C" char * GetLaunchedNotificationString(); -extern "C" void ResetLaunchedNotificationString(); - -#endif diff --git a/Plugins/iOS/PushNotificationManagerWrapper.h.meta b/Plugins/iOS/PushNotificationManagerWrapper.h.meta deleted file mode 100644 index a389527..0000000 --- a/Plugins/iOS/PushNotificationManagerWrapper.h.meta +++ /dev/null @@ -1,80 +0,0 @@ -fileFormatVersion: 2 -guid: 8ff38dbd0933b433abe19d794a877c63 -PluginImporter: - externalObjects: {} - serializedVersion: 2 - iconMap: {} - executionOrder: {} - defineConstraints: [] - isPreloaded: 0 - isOverridable: 1 - isExplicitlyReferenced: 0 - validateReferences: 1 - platformData: - - first: - : Any - second: - enabled: 0 - settings: - Exclude Android: 1 - Exclude Editor: 1 - Exclude Linux64: 1 - Exclude OSXUniversal: 1 - Exclude Win: 1 - Exclude Win64: 1 - Exclude iOS: 0 - - first: - Android: Android - second: - enabled: 0 - settings: - CPU: ARMv7 - - first: - Any: - second: - enabled: 0 - settings: {} - - first: - Editor: Editor - second: - enabled: 0 - settings: - CPU: AnyCPU - DefaultValueInitialized: true - OS: AnyOS - - first: - Standalone: Linux64 - second: - enabled: 0 - settings: - CPU: None - - first: - Standalone: OSXUniversal - second: - enabled: 0 - settings: - CPU: None - - first: - Standalone: Win - second: - enabled: 0 - settings: - CPU: None - - first: - Standalone: Win64 - second: - enabled: 0 - settings: - CPU: None - - first: - iPhone: iOS - second: - enabled: 1 - settings: - AddToEmbeddedBinaries: false - CPU: AnyCPU - CompileFlags: - FrameworkDependencies: UserNotifications; - userData: - assetBundleName: - assetBundleVariant: diff --git a/Plugins/iOS/PushNotificationManagerWrapper.mm b/Plugins/iOS/PushNotificationManagerWrapper.mm deleted file mode 100644 index 48bd747..0000000 --- a/Plugins/iOS/PushNotificationManagerWrapper.mm +++ /dev/null @@ -1,22 +0,0 @@ -#import "PushNotificationManagerWrapper.h" - -extern "C" { - void NativeRegisterForPushNotifications(REGISTRATION_CALLBACK callback) { - [[PushNotificationManager sharedInstance] registerForRemoteNotifications:callback]; - } - - void RegisterUnityCallbackForNotificationReceived(NOTIFICATION_CALLBACK callback) { - [[PushNotificationManager sharedInstance] setNotificationCallback:callback]; - [[PushNotificationManager sharedInstance] flushNotificationBuffer]; - } - - char * GetLaunchedNotificationString() { - return [[PushNotificationManager sharedInstance] getLaunchedNotificationString]; - } - - void ResetLaunchedNotificationString() { - [[PushNotificationManager sharedInstance] resetLaunchedNotificationString]; - } -} - - diff --git a/Plugins/iOS/PushNotificationManagerWrapper.mm.meta b/Plugins/iOS/PushNotificationManagerWrapper.mm.meta deleted file mode 100644 index 64838ba..0000000 --- a/Plugins/iOS/PushNotificationManagerWrapper.mm.meta +++ /dev/null @@ -1,85 +0,0 @@ -fileFormatVersion: 2 -guid: ed9aa836168124bf1920a23f63d6935d -PluginImporter: - externalObjects: {} - serializedVersion: 2 - iconMap: {} - executionOrder: {} - defineConstraints: [] - isPreloaded: 0 - isOverridable: 1 - isExplicitlyReferenced: 0 - validateReferences: 1 - platformData: - - first: - : Any - second: - enabled: 0 - settings: - Exclude Android: 1 - Exclude Editor: 1 - Exclude Linux64: 1 - Exclude OSXUniversal: 1 - Exclude Win: 1 - Exclude Win64: 1 - Exclude iOS: 0 - - first: - Android: Android - second: - enabled: 0 - settings: - CPU: ARMv7 - - first: - Any: - second: - enabled: 0 - settings: {} - - first: - Editor: Editor - second: - enabled: 0 - settings: - CPU: AnyCPU - DefaultValueInitialized: true - OS: AnyOS - - first: - Standalone: Linux64 - second: - enabled: 0 - settings: - CPU: None - - first: - Standalone: OSXUniversal - second: - enabled: 0 - settings: - CPU: None - - first: - Standalone: Win - second: - enabled: 0 - settings: - CPU: x86 - - first: - Standalone: Win64 - second: - enabled: 0 - settings: - CPU: x86_64 - - first: - iPhone: iOS - second: - enabled: 1 - settings: - AddToEmbeddedBinaries: false - CPU: AnyCPU - CompileFlags: - FrameworkDependencies: UserNotifications; - - first: - tvOS: tvOS - second: - enabled: 1 - settings: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Runtime/Analytics/EventsWrapper.cs b/Runtime/Analytics/EventsWrapper.cs deleted file mode 100644 index b8c1ce5..0000000 --- a/Runtime/Analytics/EventsWrapper.cs +++ /dev/null @@ -1,30 +0,0 @@ -using System.Collections.Generic; -using Unity.Services.Analytics; -using Unity.Services.Analytics.Internal; - -namespace Unity.Services.PushNotifications -{ - interface IPushNotificationEventsWrapper - { - void RecordCustomEvent(string eventName, Dictionary parameters, int version); - } - - class EventsWrapper: IPushNotificationEventsWrapper - { - public void RecordCustomEvent(string eventName, Dictionary parameters, int version) - { - Event evt = new Event(eventName, version); - - foreach (KeyValuePair parameter in parameters) - { - evt.Parameters.Set(parameter.Key, parameter.Value); - } - - evt.Parameters.AddUserCountry(); - - - - AnalyticsService.Instance.RecordInternalEvent(evt); - } - } -} diff --git a/Runtime/Analytics/IPushNotificationsAnalytics.cs b/Runtime/Analytics/IPushNotificationsAnalytics.cs index 03ca6dd..ae1ebb3 100644 --- a/Runtime/Analytics/IPushNotificationsAnalytics.cs +++ b/Runtime/Analytics/IPushNotificationsAnalytics.cs @@ -1,12 +1,33 @@ using System; using System.Collections.Generic; -using UnityEngine; namespace Unity.Services.PushNotifications { + [Obsolete("This interface should not be used. It will be deleted in the future version. Notification events are recorded for you automatically.")] public interface IPushNotificationsAnalytics { void RecordPushTokenUpdated(string pushToken); void RecordNotificationOpened(Dictionary payload, bool didLaunch); } + + [Obsolete("Stub to help transition away from IPushNotificationsAnalytics. This should ensure deprecation warnings appear only for the correct (exposed) elements, not for any internal parts.")] + internal class PushNotificationsAnalyticsStub : IPushNotificationsAnalytics + { + readonly IPushAnalytics m_Actual; + + public PushNotificationsAnalyticsStub(IPushAnalytics actual) + { + m_Actual = actual; + } + + public void RecordPushTokenUpdated(string pushToken) + { + m_Actual.RecordPushTokenUpdated(pushToken); + } + + public void RecordNotificationOpened(Dictionary payload, bool didLaunch) + { + m_Actual.RecordNotificationOpened(payload, didLaunch); + } + } } diff --git a/Runtime/Analytics/PushAnalytics.cs b/Runtime/Analytics/PushAnalytics.cs new file mode 100644 index 0000000..34c57ce --- /dev/null +++ b/Runtime/Analytics/PushAnalytics.cs @@ -0,0 +1,89 @@ +using System; +using System.Collections.Generic; +using Unity.Services.Core.Analytics.Internal; +using UnityEngine; + +namespace Unity.Services.PushNotifications +{ + interface IPushAnalytics + { + void RecordPushTokenUpdated(string pushToken); + void RecordNotificationOpened(Dictionary payload, bool didLaunch); + } + + internal class PushAnalytics : IPushAnalytics + { + const string k_PackageName = "com.unity.services.push-notifications"; + + readonly IAnalyticsStandardEventComponent m_Analytics; + readonly ISystemWrapper m_Platform; + + internal PushAnalytics(IAnalyticsStandardEventComponent analytics, ISystemWrapper platform) + { + m_Analytics = analytics; + m_Platform = platform; + } + + public void RecordPushTokenUpdated(string pushToken) + { + var eventParams = new Dictionary(); + + switch (m_Platform.RuntimePlatform()) + { + case RuntimePlatform.Android: + eventParams.Add("androidRegistrationID", pushToken); + break; + case RuntimePlatform.IPhonePlayer: + case RuntimePlatform.tvOS: + eventParams.Add("pushNotificationToken", pushToken); + break; + } + + m_Analytics.Record("notificationServices", eventParams, 1, k_PackageName); + } + + public void RecordNotificationOpened(Dictionary payload, bool didLaunch) + { + var eventParams = new Dictionary(); + + bool insertCommunicationAttrs = false; + + if (payload.ContainsKey("_ddCampaign")) + { + eventParams.Add("campaignId", Convert.ToInt64(payload["_ddCampaign"])); + insertCommunicationAttrs = true; + } + + if (payload.ContainsKey("_ddCohort")) + { + eventParams.Add("cohortId", Convert.ToInt64(payload["_ddCohort"])); + insertCommunicationAttrs = true; + } + + if (insertCommunicationAttrs && + payload.ContainsKey("_ddCommunicationSender")) + { + eventParams.Add("communicationSender", payload["_ddCommunicationSender"]); + } + + if (didLaunch) + { + eventParams.Add("notificationLaunch", true); + } + + if (payload.ContainsKey("_ddId")) + { + eventParams.Add("notificationId", Convert.ToInt64(payload["_ddId"])); + } + + if (payload.ContainsKey("_ddName")) + { + eventParams.Add("notificationName", payload["_ddName"]); + } + + eventParams.Add("communicationState", "OPEN"); + + m_Analytics.Record("notificationOpened", eventParams, 1, k_PackageName); + } + } +} diff --git a/Runtime/Analytics/PushNotificationAnalytics.cs.meta b/Runtime/Analytics/PushAnalytics.cs.meta similarity index 100% rename from Runtime/Analytics/PushNotificationAnalytics.cs.meta rename to Runtime/Analytics/PushAnalytics.cs.meta diff --git a/Runtime/Analytics/PushNotificationAnalytics.cs b/Runtime/Analytics/PushNotificationAnalytics.cs deleted file mode 100644 index 635c890..0000000 --- a/Runtime/Analytics/PushNotificationAnalytics.cs +++ /dev/null @@ -1,106 +0,0 @@ -using System; -using System.Collections.Generic; -using UnityEngine; - -namespace Unity.Services.PushNotifications -{ - static class SdkVersion - { - // This value should always match what is in the package.json for this package - public static readonly string SDK_VERSION = "3.0.1-pre.1"; - } - - class PushNotificationAnalytics : IPushNotificationsAnalytics - { - IPushNotificationEventsWrapper m_EventsWrapper; - IPushNotificationAnalyticsPlatformWrapper m_AnalyticsPlatformWrapper; - - internal PushNotificationAnalytics(IPushNotificationEventsWrapper eventsWrapper, IPushNotificationAnalyticsPlatformWrapper analyticsPlatformWrapper) - { - m_EventsWrapper = eventsWrapper; - m_AnalyticsPlatformWrapper = analyticsPlatformWrapper; - } - - /// - /// This method should be called when the user's push notification token is updated. Most commonly this is - /// when first registering for notifications, but can also occur at other points during the app lifecycle. - /// If using one of this SDK's platform specific implementations this method will be called for you. - /// - /// The push token relating to this user's device. - /// - public void RecordPushTokenUpdated(string pushToken) - { - Dictionary eventData = new Dictionary - { - { "clientVersion", m_AnalyticsPlatformWrapper.ApplicationVersion() }, - { "sdkVersion", SdkVersion.SDK_VERSION }, - { "sdkMethod", "com.unity.services.pushNotifications.PushNotificationsAnalytics.RecordPushTokenUpdated" }, - { "platform", m_AnalyticsPlatformWrapper.AnalyticsPlatform() } - }; - - RuntimePlatform runtimePlatform = m_AnalyticsPlatformWrapper.RuntimePlatform(); - if (runtimePlatform == RuntimePlatform.Android) - { - eventData.Add("androidRegistrationID", pushToken); - } - else if (runtimePlatform == RuntimePlatform.IPhonePlayer || runtimePlatform == RuntimePlatform.tvOS) - { - eventData.Add("pushNotificationToken", pushToken); - } - - m_EventsWrapper.RecordCustomEvent("notificationServices", eventData, 1); - } - - /// - /// This method should be called when the user opens the app from a push notification. - /// If using one of this SDK's platform specific implementations this method will be called for you. - /// - /// The dictionary containing required the event data. - /// Was the app launched from opening the notification? - /// - public void RecordNotificationOpened(Dictionary payload, bool didLaunch) - { - Dictionary eventParams = new Dictionary - { - { "clientVersion", m_AnalyticsPlatformWrapper.ApplicationVersion() }, - { "sdkVersion", SdkVersion.SDK_VERSION }, - { "sdkMethod", "com.unity.services.pushNotifications.PushNotificationsAnalytics.RecordNotificationOpened" }, - { "platform", m_AnalyticsPlatformWrapper.AnalyticsPlatform() } - }; - - bool insertCommunicationAttrs = false; - - if (payload.ContainsKey("_ddCampaign")) - { - eventParams["campaignId"] = Convert.ToInt64(payload["_ddCampaign"]); - insertCommunicationAttrs = true; - } - if (payload.ContainsKey("_ddCohort")) - { - eventParams["cohortId"] = Convert.ToInt64(payload["_ddCohort"]); - insertCommunicationAttrs = true; - } - if (insertCommunicationAttrs && payload.ContainsKey("_ddCommunicationSender")) - { - eventParams["communicationSender"] = payload["_ddCommunicationSender"]; - eventParams["communicationState"] = "OPEN"; - } - - if (didLaunch) - { - eventParams["notificationLaunch"] = true; - } - if (payload.ContainsKey("_ddId")) - { - eventParams["notificationId"] = Convert.ToInt64(payload["_ddId"]); - } - if (payload.ContainsKey("_ddName")) - { - eventParams["notificationName"] = payload["_ddName"]; - } - eventParams["communicationState"] = "OPEN"; - - m_EventsWrapper.RecordCustomEvent("notificationOpened", eventParams, 1); - } - } -} diff --git a/Runtime/Android.meta b/Runtime/Android.meta deleted file mode 100644 index afe33c9..0000000 --- a/Runtime/Android.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: e6b00f86b74f34c6788b04515f4eb4b7 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Runtime/Android/AndroidPushNotifications.cs b/Runtime/Android/AndroidPushNotifications.cs deleted file mode 100644 index e462bff..0000000 --- a/Runtime/Android/AndroidPushNotifications.cs +++ /dev/null @@ -1,183 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Threading.Tasks; -using UnityEngine; -using UnityEngine.Android; - -namespace Unity.Services.PushNotifications -{ - class AndroidPushNotifications : AndroidJavaProxy - { - static object s_RegistrationLock = new object(); - static TaskCompletionSource s_DeviceRegistrationTcs; - static string s_DeviceToken; - - PushNotificationReceivedHandler m_NotificationReceivedHandler; - PushNotificationAnalytics m_NotificationAnalytics; - - AndroidJavaObject m_IntentExtras; - - const string k_AndroidNotificationPermissionName = "android.permission.POST_NOTIFICATIONS"; - const string k_PlayerPrefPermissionDenied = "NotificationPermissionRequested"; - const int k_TiramisuVersionNumber = 33; - - public AndroidPushNotifications(PushNotificationReceivedHandler notificationReceivedHandler, PushNotificationAnalytics analytics) - : base("com.unity.services.pushnotifications.android.UnityCallbackClass") - { - m_NotificationReceivedHandler = notificationReceivedHandler; - m_NotificationAnalytics = analytics; - - try - { - AndroidJavaObject intent = GetCurrentActivity().Call("getIntent"); - string intentNotificationData = intent.Call("getStringExtra", "notificationData"); - - if (intentNotificationData != null) - { - Debug.Log("App launched from notification, sending relevant events"); - OnNotificationReceived(intentNotificationData); - - // remove opened notificationData so it cannot be re-processed - intent.Call("removeExtra", "notificationData"); - } - } - catch (Exception e) - { - Debug.LogError($"Failed to check intent for notification data: {e.Message}"); - } - } - - internal event Action> InternalNotificationWasReceived; - - public Task RegisterForPushNotificationsAsync(string firebaseApiKey, string firebaseSenderId, string firebaseApplicationId, string firebaseProjectId) - { - lock (s_RegistrationLock) - { - if (!string.IsNullOrEmpty(s_DeviceToken)) - { - return Task.FromResult(s_DeviceToken); - } - - if (s_DeviceRegistrationTcs != null) - { - return s_DeviceRegistrationTcs.Task; - } - - s_DeviceRegistrationTcs = new TaskCompletionSource(); - - void InitializePushNotifications() - { - try - { - AndroidJavaObject applicationContext = GetCurrentActivity().Call("getApplicationContext"); - - AndroidJavaObject instance = GetPluginInstance(); - instance.Call("setCallbackClass", this); - instance.Call("initialize", applicationContext, - firebaseApiKey, firebaseApplicationId, firebaseSenderId, firebaseProjectId); - } - catch (Exception e) - { - s_DeviceRegistrationTcs.TrySetException(new Exception($"Failed to initialize Push Notification plugin instance and register the device for remote notifications")); - } - } - - bool isPermissionAuthorized = Permission.HasUserAuthorizedPermission(k_AndroidNotificationPermissionName); - AndroidJavaClass version = new AndroidJavaClass("android.os.Build$VERSION"); - int sdkVersion = version.GetStatic("SDK_INT"); - - if (sdkVersion < k_TiramisuVersionNumber || isPermissionAuthorized) - { - InitializePushNotifications(); - } - else - { - bool hasPermissionBeenDenied = Convert.ToBoolean(PlayerPrefs.GetInt(k_PlayerPrefPermissionDenied)); - - if (!hasPermissionBeenDenied) - { - var callbacks = new PermissionCallbacks(); - callbacks.PermissionGranted += _ => InitializePushNotifications(); - callbacks.PermissionDenied += _ => - { - PlayerPrefs.SetInt(k_PlayerPrefPermissionDenied, 1); - PlayerPrefs.Save(); - }; - - Permission.RequestUserPermission(k_AndroidNotificationPermissionName, callbacks); - } - } - - return s_DeviceRegistrationTcs.Task; - } - } - - AndroidJavaObject GetPluginInstance() - { - AndroidJavaClass notificationPluginObject = new AndroidJavaClass("com.unity.services.pushnotifications.android.UnityNotifications"); - AndroidJavaObject instance = notificationPluginObject.GetStatic("INSTANCE"); - if (instance == null) - { - Debug.LogError("Unity Push Notification Android plugin is missing, android push notifications will not work as expected."); - return null; - } - - return instance; - } - - AndroidJavaObject GetCurrentActivity() - { - AndroidJavaClass unityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer"); - return unityPlayer.GetStatic("currentActivity"); - } - - // Called from the Kotlin code - internal void OnTokenReceived(string token) - { - lock (s_RegistrationLock) - { - if (s_DeviceRegistrationTcs != null) - { - if (String.IsNullOrEmpty(token)) - { - s_DeviceRegistrationTcs.TrySetException(new Exception("Failed to register the device for remote notifications.")); - } - else - { - s_DeviceRegistrationTcs.TrySetResult(token); - } - // Reset registration flow ready for next time. - s_DeviceRegistrationTcs = null; - } - - if (!String.IsNullOrEmpty(token)) - { - s_DeviceToken = token; - - MainThreadHelper.RunOnMainThread(() => - { - m_NotificationAnalytics.RecordPushTokenUpdated(token); - }); - - Debug.Log($"Successfully registered for remote push notifications with token: {token}"); - } - } - } - - // Called from the Kotlin code - internal void OnNotificationReceived(string notificationDataAsJson) - { - if (string.IsNullOrEmpty(notificationDataAsJson)) - { - Debug.Log("Notification received with no data, ignoring"); - return; - } - - MainThreadHelper.RunOnMainThread(() => - { - Dictionary notificationData = m_NotificationReceivedHandler.HandleReceivedNotification(notificationDataAsJson); - InternalNotificationWasReceived?.Invoke(notificationData); - }); - } - } -} diff --git a/Runtime/AssemblyInternals.cs b/Runtime/AssemblyInternals.cs index 76ebef9..0b6e9aa 100644 --- a/Runtime/AssemblyInternals.cs +++ b/Runtime/AssemblyInternals.cs @@ -1,4 +1,6 @@ using System.Runtime.CompilerServices; [assembly: InternalsVisibleTo("Unity.Services.PushNotifications.Tests")] +[assembly: InternalsVisibleTo("Unity.Services.PushNotifications.EditorTests")] [assembly: InternalsVisibleTo("Unity.Services.PushNotifications.Editor")] +[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")] diff --git a/Runtime/IPushNotificationsService.cs b/Runtime/IPushNotificationsService.cs index 95a2378..dd40624 100644 --- a/Runtime/IPushNotificationsService.cs +++ b/Runtime/IPushNotificationsService.cs @@ -6,9 +6,26 @@ namespace Unity.Services.PushNotifications { public interface IPushNotificationsService { - public event Action> OnNotificationReceived; + /// + /// Subscribe to this event to be notified when a remote notification is used to launch or reopen the app. + /// + /// You must set up event subscriptions before calling RegisterForPushNotificationsAsync. + /// + /// If the application was started from a remote notification, this event will be invoked + /// once the RegisterForPushNotificationsAsync process has completed. + /// + public event Action> OnRemoteNotificationReceived; + + [Obsolete("Do not use this. It will be removed in a future version. Events are recorded for you automatically.")] public IPushNotificationsAnalytics Analytics { get; } - public Task RegisterForPushNotificationsAsync(); + /// + /// Registers for push notifications with the appropriate mechanism for the current platform. + /// + /// This method will automatically handle platform specific intricacies of getting a push notification token, and will + /// send the appropriate analytics events to Unity Analytics 2. + /// + /// (Asynchronously via a Task) The device token as a string. + public Task RegisterForPushNotificationsAsync(); } } diff --git a/Runtime/MainThreadHelper.cs b/Runtime/MainThreadHelper.cs index 88b1745..e3d94d0 100644 --- a/Runtime/MainThreadHelper.cs +++ b/Runtime/MainThreadHelper.cs @@ -6,27 +6,27 @@ namespace Unity.Services.PushNotifications { - static class MainThreadHelper + interface IMainThreadHelper + { + void RunOnMainThread(Action methodToRun); + } + + class MainThreadHelper : IMainThreadHelper { static SynchronizationContext s_UnitySynchronizationContext; static TaskScheduler s_TaskScheduler; static int s_MainThreadId; -#if UNITY_EDITOR - [InitializeOnLoadMethod] -#endif - [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)] - public static void Init() + public MainThreadHelper() { s_UnitySynchronizationContext = SynchronizationContext.Current; s_TaskScheduler = TaskScheduler.FromCurrentSynchronizationContext(); s_MainThreadId = Thread.CurrentThread.ManagedThreadId; } - internal static async void RunOnMainThread(Action methodToRun) + public void RunOnMainThread(Action methodToRun) { - await Task.Factory.StartNew(methodToRun, CancellationToken.None, TaskCreationOptions.None, - s_TaskScheduler); + Task.Factory.StartNew(methodToRun, CancellationToken.None, TaskCreationOptions.None, s_TaskScheduler); } } } diff --git a/Plugins/iOS.meta b/Runtime/Platforms.meta similarity index 77% rename from Plugins/iOS.meta rename to Runtime/Platforms.meta index 693352e..f245646 100644 --- a/Plugins/iOS.meta +++ b/Runtime/Platforms.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: cf662c0d28635416ea5a220d519b8de0 +guid: 0f0a0d24882a3ff4aa72b0b7dd497826 folderAsset: yes DefaultImporter: externalObjects: {} diff --git a/Runtime/Platforms/AndroidPushNotifications.cs b/Runtime/Platforms/AndroidPushNotifications.cs new file mode 100644 index 0000000..bf8fcf3 --- /dev/null +++ b/Runtime/Platforms/AndroidPushNotifications.cs @@ -0,0 +1,166 @@ +#if UNITY_ANDROID || UNITY_EDITOR +using System; +using System.Collections; +using System.Collections.Generic; +using System.Threading.Tasks; +using Newtonsoft.Json; +using Unity.Notifications.Android; +using UnityEngine; + +namespace Unity.Services.PushNotifications +{ + class AndroidPushNotifications : AndroidJavaProxy, IPushPlatform + { + TaskCompletionSource s_RegisterTcSource; + + IPushPlatformCallbacks m_PushNotificationsHandler; + readonly ICoroutineRunner m_Container; + + AndroidJavaObject s_CurrentActivity; + AndroidJavaObject s_CurrentContext; + AndroidJavaObject s_PushNotificationManager; + + public AndroidPushNotifications(ICoroutineRunner container) + : base("com.unity.services.pushnotifications.android.UnityPushNotificationsCallback") + { + m_Container = container; + } + + public void Initialize(IPushPlatformCallbacks callbacks) + { + m_PushNotificationsHandler = callbacks; + } + + AndroidJavaObject GetCurrentActivity() + { + AndroidJavaClass unityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer"); + return unityPlayer.GetStatic("currentActivity"); + } + + public void OnApplicationPause(bool isPaused) + { + // Android has no pause/unpause actions. + } + + /// + /// Registers for push notifications on Android. Returns the device token for the registered device. + /// This method checks if the user grants the notification permission, it will register for push notification and get the device token. + /// + /// The push notification token for this device + public Task RegisterForPushNotifications(PushNotificationSettings settings) + { + if (String.IsNullOrEmpty(settings.firebaseWebApiKey) || + String.IsNullOrEmpty(settings.firebaseAppID) || + String.IsNullOrEmpty(settings.firebaseProjectNumber) || + String.IsNullOrEmpty(settings.firebaseProjectID)) + { + throw new Exception("UGS Push Notifications is missing Android settings - make sure these are set in the editor Project Settings"); + } + + s_RegisterTcSource = new TaskCompletionSource(); + m_Container.StartCoroutine( + RequestAuthorization( + settings.firebaseWebApiKey, + settings.firebaseProjectNumber, + settings.firebaseAppID, + settings.firebaseProjectID)); + + return s_RegisterTcSource.Task; + } + + IEnumerator RequestAuthorization(string firebaseApiKey, string firebaseSenderId, string firebaseApplicationId, string firebaseProjectId) + { + var request = new PermissionRequest(); + while (request.Status == PermissionStatus.RequestPending) + { + yield return null; + } + + switch (request.Status) + { + case PermissionStatus.Allowed: + InitializePushNotifications(firebaseApiKey, firebaseSenderId, firebaseApplicationId, firebaseProjectId); + break; + case PermissionStatus.Denied: + case PermissionStatus.DeniedDontAskAgain: + s_RegisterTcSource.TrySetException(new Exception($"Authorization request was denied")); + break; + } + } + + void InitializePushNotifications(string firebaseApiKey, string firebaseSenderId, string firebaseApplicationId, string firebaseProjectId) + { + try + { + // Call Android Plugin code to initialise Push Notification with firebase + using (var unityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer")) + { + s_CurrentActivity = unityPlayer.GetStatic("currentActivity"); + } + s_CurrentContext = GetCurrentActivity().Call("getApplicationContext"); + + var unityPushNotificationManagerClass = new AndroidJavaClass("com.unity.services.pushnotifications.android.UnityPushNotifications"); + s_PushNotificationManager = unityPushNotificationManagerClass.CallStatic("getUnityPushNotificationImpl", s_CurrentContext); + s_PushNotificationManager.Call("initialize", s_CurrentActivity, this); + s_PushNotificationManager.Call("registerForPushNotifications", firebaseApiKey, firebaseApplicationId, firebaseSenderId, firebaseProjectId); + } + catch (Exception e) + { + s_RegisterTcSource.TrySetException(new Exception($"Failed to initialize Push Notification Plugin {e.Message}")); + } + } + + public Dictionary CheckForAppLaunchByNotification() + { + // This is to check if the notification is launched on cold boot and call OnRemoteNotificationReceived + try + { + AndroidJavaObject intent = GetCurrentActivity().Call("getIntent"); + string intentNotificationData = intent.Call("getStringExtra", "notificationData"); + if (intentNotificationData != null) + { + // remove opened notificationData so it cannot be re-processed + intent.Call("removeExtra", "notificationData"); + + return ParseNotification(intentNotificationData); + } + } + catch (Exception e) + { + Debug.LogError($"Push: GetIntent -> Failed to check intent for notification data: {e.Message}"); + } + + return null; + } + + // Implementing the UnityRemoteNotificationsCallback from the Plugin + // See: UnityPushNotificationsCallback.java + void OnTokenReceived(string token) + { + s_RegisterTcSource.TrySetResult(token); + } + + // Implementing the UnityRemoteNotificationsCallback from the Plugin + // See: UnityPushNotificationsCallback.java + void OnRemoteNotificationReceived(string notificationDataAsJson) + { + Dictionary notificationData = ParseNotification(notificationDataAsJson); + m_PushNotificationsHandler.RemoteNotificationReceived(notificationData); + } + + Dictionary ParseNotification(string notificationData) + { + try + { + return JsonConvert.DeserializeObject>(notificationData); + } + catch (Exception e) + { + Debug.Log($"Push: Failed handle notification: {e.Message}"); + } + + return null; + } + } +} +#endif diff --git a/Runtime/Android/AndroidPushNotifications.cs.meta b/Runtime/Platforms/AndroidPushNotifications.cs.meta similarity index 100% rename from Runtime/Android/AndroidPushNotifications.cs.meta rename to Runtime/Platforms/AndroidPushNotifications.cs.meta diff --git a/Runtime/Platforms/IPlatformLogic.cs b/Runtime/Platforms/IPlatformLogic.cs new file mode 100644 index 0000000..0dedacb --- /dev/null +++ b/Runtime/Platforms/IPlatformLogic.cs @@ -0,0 +1,44 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using UnityEngine; + +namespace Unity.Services.PushNotifications +{ + internal interface IPushPlatform + { + void Initialize(IPushPlatformCallbacks callbacks); + + Task RegisterForPushNotifications(PushNotificationSettings settings); + + Dictionary CheckForAppLaunchByNotification(); + + void OnApplicationPause(bool isPaused); + } + + internal class UnsupportedPlatformLogic : IPushPlatform + { + public void Initialize(IPushPlatformCallbacks callbacks) + { + } + + public Dictionary CheckForAppLaunchByNotification() + { + return null; + } + + public Task RegisterForPushNotifications(PushNotificationSettings settings) + { +#if UNITY_EDITOR + Debug.Log("Push notifications are not available in the Unity Editor."); +#else + Debug.Log("Push notifications are not available on this platform."); +#endif + return Task.FromResult(""); + } + + public void OnApplicationPause(bool isPaused) + { + } + } +} diff --git a/Runtime/Analytics/EventsWrapper.cs.meta b/Runtime/Platforms/IPlatformLogic.cs.meta similarity index 83% rename from Runtime/Analytics/EventsWrapper.cs.meta rename to Runtime/Platforms/IPlatformLogic.cs.meta index 103c2f6..3a25594 100644 --- a/Runtime/Analytics/EventsWrapper.cs.meta +++ b/Runtime/Platforms/IPlatformLogic.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 0673bcedb71414fd388cdf2c8440b377 +guid: 43a8f9104c5fbdb4e9e28011beefc9e6 MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Runtime/Platforms/iOSPushNotifications.cs b/Runtime/Platforms/iOSPushNotifications.cs new file mode 100644 index 0000000..b95eb20 --- /dev/null +++ b/Runtime/Platforms/iOSPushNotifications.cs @@ -0,0 +1,121 @@ +#if UNITY_IOS || UNITY_EDITOR +using System; +using System.Collections; +using System.Collections.Generic; +using System.Threading.Tasks; +using Newtonsoft.Json; +using Unity.Notifications.iOS; + +namespace Unity.Services.PushNotifications +{ + class IOSPushNotifications : IPushPlatform + { + TaskCompletionSource s_RegisterTcSource; + + IPushPlatformCallbacks m_PushNotificationsHandler; + readonly ICoroutineRunner m_Container; + + public IOSPushNotifications(ICoroutineRunner container) + { + m_Container = container; + } + + public void Initialize(IPushPlatformCallbacks callbacks) + { + m_PushNotificationsHandler = callbacks; + iOSNotificationCenter.OnRemoteNotificationReceived += OnRemoteNotificationReceived; + } + + /// + /// Registers for push notifications on iOS. Returns the device token for the registered device. + /// This method checks if the user grants the notification permission, it will register for push notification and get the device token. + /// + /// The push notification token for this device + public Task RegisterForPushNotifications(PushNotificationSettings settings) + { + // NOTE: Settings is only required by Android, but is taken to ensure a consistent interface + + s_RegisterTcSource = new TaskCompletionSource(); + m_Container.StartCoroutine(RequestAuthorization(AuthorizationOption.Alert | AuthorizationOption.Badge | AuthorizationOption.Sound)); + return s_RegisterTcSource.Task; + } + + IEnumerator RequestAuthorization(AuthorizationOption options) + { + using (AuthorizationRequest request = new AuthorizationRequest(options, true)) + { + while (!request.IsFinished) + { + yield return null; + } + + if (request.Granted) + { + s_RegisterTcSource.TrySetResult(request.DeviceToken); + } + else + { + s_RegisterTcSource.TrySetException(new Exception("Authorization request was denied")); + } + } + } + + public Dictionary CheckForAppLaunchByNotification() + { + // in case a killed app was launched by clicking a notification + iOSNotification notification = iOSNotificationCenter.GetLastRespondedNotification(); + if (notification != null && + notification.Trigger.Type == iOSNotificationTriggerType.Push) + { + return ParseNotification(notification); + } + else + { + return null; + } + } + + public void OnApplicationPause(bool isPaused) + { + if (isPaused == false) + { + iOSNotification notification = iOSNotificationCenter.GetLastRespondedNotification(); + if (notification != null && + notification.Trigger.Type == iOSNotificationTriggerType.Push) + { + OnRemoteNotificationReceived(notification); + } + } + } + + void OnRemoteNotificationReceived(iOSNotification notification) + { + Dictionary notificationData = ParseNotification(notification); + m_PushNotificationsHandler.RemoteNotificationReceived(notificationData); + } + + Dictionary ParseNotification(iOSNotification notification) + { + Dictionary notificationData = new Dictionary(); + notificationData["title"] = notification.Title; + notificationData["alert"] = notification.Body; + + if (notification.UserInfo.ContainsKey("_ddCampaign")) + { + notificationData["_ddCampaign"] = notification.UserInfo["_ddCampaign"]; + } + if (notification.UserInfo.ContainsKey("_ddCohort")) + { + notificationData["_ddCohort"] = notification.UserInfo["_ddCohort"]; + } + Dictionary aps = JsonConvert.DeserializeObject>(notification.UserInfo["aps"]);; + if (aps.ContainsKey("imageUrl")) + { + notificationData["imageUrl"] = aps["imageUrl"]; + } + + return notificationData; + } + } +} +#endif diff --git a/Runtime/iOS/iOSPushNotifications.cs.meta b/Runtime/Platforms/iOSPushNotifications.cs.meta similarity index 100% rename from Runtime/iOS/iOSPushNotifications.cs.meta rename to Runtime/Platforms/iOSPushNotifications.cs.meta diff --git a/Runtime/PushNotificationCoreInitialization.cs b/Runtime/PushNotificationCoreInitialization.cs index 157359d..69aba66 100644 --- a/Runtime/PushNotificationCoreInitialization.cs +++ b/Runtime/PushNotificationCoreInitialization.cs @@ -1,4 +1,5 @@ using System.Threading.Tasks; +using Unity.Services.Core.Analytics.Internal; using Unity.Services.Core.Internal; using UnityEngine; @@ -9,12 +10,36 @@ class PushNotificationCoreInitialization : IInitializablePackage [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)] static void Register() { - CoreRegistry.Instance.RegisterPackage(new PushNotificationCoreInitialization()); + CoreRegistry.Instance.RegisterPackage(new PushNotificationCoreInitialization()) + .DependsOn(); } public Task Initialize(CoreRegistry registry) { - PushNotificationsService.internalInstance = new PushNotificationsServiceInstance(); + var analyticsSdk = registry.GetServiceComponent(); + var platformWrapper = new SystemWrapper(); + + var containerObject = PushNotificationsContainer.CreateContainer(); + var mainThreadHelper = new MainThreadHelper(); + var analytics = new PushAnalytics(analyticsSdk, platformWrapper); + + IPushPlatform platformLogic; +#if UNITY_IOS && !UNITY_EDITOR + platformLogic = new IOSPushNotifications(containerObject); +#elif UNITY_ANDROID && !UNITY_EDITOR + platformLogic = new AndroidPushNotifications(containerObject); +#else + platformLogic = new UnsupportedPlatformLogic(); +#endif + + PushNotificationsService.internalInstance = new PushNotificationsServiceInstance( + analytics, + platformLogic, + platformWrapper, + mainThreadHelper); + + platformLogic.Initialize(PushNotificationsService.internalInstance); + containerObject.Initialize(PushNotificationsService.internalInstance); return Task.CompletedTask; } diff --git a/Runtime/PushNotificationReceivedHandler.cs b/Runtime/PushNotificationReceivedHandler.cs deleted file mode 100644 index cb5b572..0000000 --- a/Runtime/PushNotificationReceivedHandler.cs +++ /dev/null @@ -1,50 +0,0 @@ -using System; -using System.Collections.Generic; -using Newtonsoft.Json; -using UnityEngine; - -namespace Unity.Services.PushNotifications -{ - class PushNotificationReceivedHandler - { - readonly IPushNotificationAnalyticsPlatformWrapper m_PlatformWrapper; - readonly IPushNotificationsAnalytics m_NotificationAnalytics; - - bool m_IsCleanStart = true; - - internal PushNotificationReceivedHandler(IPushNotificationsAnalytics analytics, IPushNotificationAnalyticsPlatformWrapper platformWrapper) - { - m_NotificationAnalytics = analytics; - m_PlatformWrapper = platformWrapper; - } - - internal Dictionary HandleReceivedNotification(string jsonNotificationData) - { - try - { - Dictionary notificationData = JsonConvert.DeserializeObject>(jsonNotificationData); - if (notificationData != null) - { - // If the application is in the background, or we're opening for the first time, then we want to send the relevant analytics. - // (Note: This doesn't 100% guarantee that we're launching from an event, but it matches the previous deltaDNA behavior). - if (!m_PlatformWrapper.IsApplicationFocused() || m_IsCleanStart) - { - m_NotificationAnalytics.RecordNotificationOpened(notificationData, true); - m_IsCleanStart = false; - } - else - { - m_NotificationAnalytics.RecordNotificationOpened(notificationData, false); - } - } - - return notificationData; - } - catch (Exception e) - { - Debug.Log($"Failed to parse notification user info dictionary data: {e.Message}"); - return null; - } - } - } -} diff --git a/Runtime/PushNotificationReceivedHandler.cs.meta b/Runtime/PushNotificationReceivedHandler.cs.meta deleted file mode 100644 index aa08ca1..0000000 --- a/Runtime/PushNotificationReceivedHandler.cs.meta +++ /dev/null @@ -1,3 +0,0 @@ -fileFormatVersion: 2 -guid: 6c5362295dee40ca9b18c3eb8afef691 -timeCreated: 1627985420 \ No newline at end of file diff --git a/Runtime/PushNotificationsContainer.cs b/Runtime/PushNotificationsContainer.cs new file mode 100644 index 0000000..1864501 --- /dev/null +++ b/Runtime/PushNotificationsContainer.cs @@ -0,0 +1,67 @@ +using System; +using System.Collections; +using UnityEngine; + +namespace Unity.Services.PushNotifications +{ + interface ICoroutineRunner + { + Coroutine StartCoroutine(IEnumerator method); + } + + class PushNotificationsContainer : MonoBehaviour, ICoroutineRunner + { + static bool s_Created; + static GameObject s_Container; + + PushNotificationsServiceInstance m_Service; + + /// + /// For the test harness only. + /// + internal static PushNotificationsContainer Instance { get; private set; } + + + internal static PushNotificationsContainer CreateContainer() + { + if (!s_Created) + { +#if UNITY_PUSH_NOTIFICATION_DEVELOPMENT + Debug.Log("Created Analytics Container"); +#endif + + s_Container = new GameObject("PushNotificationsContainer"); + Instance = s_Container.AddComponent(); + + s_Container.hideFlags = HideFlags.DontSaveInBuild | HideFlags.NotEditable; +#if !UNITY_PUSH_NOTIFICATION_DEVELOPMENT + s_Container.hideFlags |= HideFlags.HideInInspector; +#endif + + DontDestroyOnLoad(s_Container); + s_Created = true; + } + + return Instance; + } + + public void Initialize(PushNotificationsServiceInstance service) + { + m_Service = service; + } + + void OnApplicationPause(bool paused) + { + m_Service.OnApplicationPause(paused); + } + + void OnDestroy() + { + // NOTE: we use OnDestroy rather than OnApplicationQuit in case the game developer should + // deliberately/accidentally destroy the container object. This should ensure graceful shutdown + // of the SDK regardless of 'how' it actually got turned off. + s_Container = null; + s_Created = false; + } + } +} diff --git a/Runtime/PushNotificationsContainer.cs.meta b/Runtime/PushNotificationsContainer.cs.meta new file mode 100644 index 0000000..b64158a --- /dev/null +++ b/Runtime/PushNotificationsContainer.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: a9b779ada67049c9b03b23aca86c57d1 +timeCreated: 1688650166 \ No newline at end of file diff --git a/Runtime/PushNotificationsServiceInstance.cs b/Runtime/PushNotificationsServiceInstance.cs index bcd2de0..b976c49 100644 --- a/Runtime/PushNotificationsServiceInstance.cs +++ b/Runtime/PushNotificationsServiceInstance.cs @@ -5,79 +5,113 @@ namespace Unity.Services.PushNotifications { - class PushNotificationsServiceInstance : IPushNotificationsService + internal interface IPushPlatformCallbacks { - PushNotificationsAnalyticsPlatformWrapper m_AnalyticsPlatformWrapper; - PushNotificationAnalytics m_PushNotificationAnalyticsImpl; - internal PushNotificationReceivedHandler notificationReceivedHandler; + void RemoteNotificationReceived(Dictionary notificationData); + } + + internal class PushNotificationsServiceInstance : IPushNotificationsService, IPushPlatformCallbacks + { + string m_DeviceToken; -#if UNITY_IOS && !UNITY_EDITOR - IOSPushNotifications m_IOSPushNotifications; -#elif UNITY_ANDROID && !UNITY_EDITOR - AndroidPushNotifications m_AndroidPushNotifications; -#endif + readonly IPushAnalytics m_Analytics; + readonly IPushPlatform m_PlatformLogic; + readonly ISystemWrapper m_PlatformWrapper; + readonly IMainThreadHelper m_MainThreadHelper; - internal PushNotificationsServiceInstance() + [Obsolete("Do not use this. It will be deleted in a future version. Notification events are recorded for you automatically.")] + public IPushNotificationsAnalytics Analytics { get { return new PushNotificationsAnalyticsStub(m_Analytics); } } + + internal PushNotificationsServiceInstance( + IPushAnalytics analytics, + IPushPlatform platformSpecificLogic, + ISystemWrapper platformWrapper, + IMainThreadHelper mainThreadHelper) { - m_AnalyticsPlatformWrapper = new PushNotificationsAnalyticsPlatformWrapper(); - m_PushNotificationAnalyticsImpl = new PushNotificationAnalytics(new EventsWrapper(), m_AnalyticsPlatformWrapper); - notificationReceivedHandler = new PushNotificationReceivedHandler(m_PushNotificationAnalyticsImpl, m_AnalyticsPlatformWrapper); - -#if UNITY_IOS && !UNITY_EDITOR - m_IOSPushNotifications = new IOSPushNotifications(notificationReceivedHandler, m_PushNotificationAnalyticsImpl); -#elif UNITY_ANDROID && !UNITY_EDITOR - m_AndroidPushNotifications = new AndroidPushNotifications(notificationReceivedHandler, m_PushNotificationAnalyticsImpl); -#endif + m_Analytics = analytics; + m_PlatformLogic = platformSpecificLogic; + m_PlatformWrapper = platformWrapper; + m_MainThreadHelper = mainThreadHelper; } - public event Action> OnNotificationReceived + event Action> m_NotificationReceivedEvent; + public event Action> OnRemoteNotificationReceived { -#if UNITY_IOS && !UNITY_EDITOR - add => IOSPushNotifications.InternalNotificationWasReceived += value; - remove => IOSPushNotifications.InternalNotificationWasReceived -= value; -#elif UNITY_ANDROID && !UNITY_EDITOR - add => m_AndroidPushNotifications.InternalNotificationWasReceived += value; - remove => m_AndroidPushNotifications.InternalNotificationWasReceived -= value; -#else add - { /* No action on unsupported platforms */ } - remove - { /* No action on unsupported platforms */ } -#endif + { + if (String.IsNullOrEmpty(m_DeviceToken)) + { + m_NotificationReceivedEvent += value; + } + else + { + throw new InvalidOperationException("You may not subscribe to OnRemoteNotificationReceived after calling RegisterForPushNotificationsAsync."); + } + } + remove => m_NotificationReceivedEvent -= value; + } + + public async Task RegisterForPushNotificationsAsync() + { + if (String.IsNullOrEmpty(m_DeviceToken)) + { + PushNotificationSettings settings = m_PlatformWrapper.GetSettings(); + + m_DeviceToken = await m_PlatformLogic.RegisterForPushNotifications(settings); + if (String.IsNullOrEmpty(m_DeviceToken)) + { + throw new Exception("Failed to register the device for remote notifications."); + } + else + { + // The underlying platform logic includes interop callbacks, so there's no guarantee we're back where we started. + // Therefore: force this bit onto the main thread so that we can use Unity APIs again. + m_MainThreadHelper.RunOnMainThread(CompleteRegistration); + } + } + + return m_DeviceToken; + } + + void CompleteRegistration() + { + Debug.Log($"DeviceToken = {m_DeviceToken}"); + + m_Analytics.RecordPushTokenUpdated(m_DeviceToken); + + Dictionary launchNotification = m_PlatformLogic.CheckForAppLaunchByNotification(); + if (launchNotification != null) + { + m_Analytics.RecordNotificationOpened(launchNotification, true); + m_NotificationReceivedEvent?.Invoke(launchNotification); + } } - public IPushNotificationsAnalytics Analytics => m_PushNotificationAnalyticsImpl; + internal void OnApplicationPause(bool isPaused) + { + m_PlatformLogic.OnApplicationPause(isPaused); + } - /// - /// Registers for push notifications with the appropriate mechanism for the current platform. - /// - /// This method will automatically handle platform specific intricacies of getting a push notification token, and will - /// send the appropriate analytics events to Unity Analytics 2. - /// - /// (Asynchronously via a Task) The device token as a string. - public Task RegisterForPushNotificationsAsync() + public void RemoteNotificationReceived(Dictionary notificationData) { - PushNotificationSettings settings = PushNotificationSettings.GetAssetInstance(); - return RegisterForPushNotificationsInternal(settings); + // Once again, this is invoked by underlying platform logic so there's no guarantee it's on the main thread. + // Therefore: enforce it. + m_MainThreadHelper.RunOnMainThread(() => + { + ProcessRemoteNotification(notificationData); + }); } - Task RegisterForPushNotificationsInternal(PushNotificationSettings settings) + void ProcessRemoteNotification(Dictionary notificationData) { -#if UNITY_IOS && !UNITY_EDITOR - return m_IOSPushNotifications.RegisterForPushNotificationsAsync(); -#elif UNITY_ANDROID && !UNITY_EDITOR - if (string.IsNullOrEmpty(settings.firebaseWebApiKey) || string.IsNullOrEmpty(settings.firebaseAppID) || string.IsNullOrEmpty(settings.firebaseProjectNumber) || string.IsNullOrEmpty(settings.firebaseProjectID)) + if (notificationData != null) { - throw new Exception("UGS Push Notifications is missing Android settings - make sure these are set in the editor Project Settings"); + // If the application is in the background then we want to send the relevant analytics. + // (Note: This doesn't 100% guarantee that we're launching from an event, but it matches the previous deltaDNA behavior). + m_Analytics.RecordNotificationOpened(notificationData, !m_PlatformWrapper.IsApplicationFocused()); } - return m_AndroidPushNotifications.RegisterForPushNotificationsAsync(settings.firebaseWebApiKey, settings.firebaseProjectNumber, settings.firebaseAppID, settings.firebaseProjectID); -#elif UNITY_EDITOR - Debug.Log("Push Notifications are not supported in the Editor Play mode. Returning an empty push token."); - return Task.FromResult(""); -#else - Debug.Log("Push notifications are not supported on this platform at this time. Returning an empty push token."); - return Task.FromResult(""); -#endif + + m_NotificationReceivedEvent?.Invoke(notificationData); } } } diff --git a/Runtime/Analytics/PushNotificationsAnalyticsPlatformWrapper.cs b/Runtime/SystemWrapper.cs similarity index 52% rename from Runtime/Analytics/PushNotificationsAnalyticsPlatformWrapper.cs rename to Runtime/SystemWrapper.cs index 8657491..eaf23c0 100644 --- a/Runtime/Analytics/PushNotificationsAnalyticsPlatformWrapper.cs +++ b/Runtime/SystemWrapper.cs @@ -1,21 +1,18 @@ -using System; -using Unity.Services.Analytics.Internal; using UnityEngine; namespace Unity.Services.PushNotifications { - interface IPushNotificationAnalyticsPlatformWrapper + interface ISystemWrapper { string ApplicationVersion(); RuntimePlatform RuntimePlatform(); bool IsApplicationFocused(); - string AnalyticsPlatform(); + + PushNotificationSettings GetSettings(); } - - class PushNotificationsAnalyticsPlatformWrapper: IPushNotificationAnalyticsPlatformWrapper + + class SystemWrapper : ISystemWrapper { - const string k_UnknownCountryCode = "ZZ"; - public string ApplicationVersion() { return Application.version; @@ -31,15 +28,9 @@ public bool IsApplicationFocused() return Application.isFocused; } - public string AnalyticsPlatform() + public PushNotificationSettings GetSettings() { -#if UNITY_IOS - return "IOS"; -#elif UNITY_ANDROID - return "ANDROID"; -#else - return "UNKNOWN"; -#endif + return PushNotificationSettings.GetAssetInstance(); } } } diff --git a/Runtime/Analytics/PushNotificationsAnalyticsPlatformWrapper.cs.meta b/Runtime/SystemWrapper.cs.meta similarity index 100% rename from Runtime/Analytics/PushNotificationsAnalyticsPlatformWrapper.cs.meta rename to Runtime/SystemWrapper.cs.meta diff --git a/Runtime/Unity.Services.PushNotifications.api b/Runtime/Unity.Services.PushNotifications.api index 9ffa63e..44246d8 100644 --- a/Runtime/Unity.Services.PushNotifications.api +++ b/Runtime/Unity.Services.PushNotifications.api @@ -3,7 +3,7 @@ // make sure the XML doc file is present and located next to the scraped dll namespace Unity.Services.PushNotifications { - public interface IPushNotificationsAnalytics + [System.Obsolete(@"This interface should not be used. It will be deleted in the future version. Notification events are recorded for you automatically.")] public interface IPushNotificationsAnalytics { public void RecordNotificationOpened(System.Collections.Generic.Dictionary payload, bool didLaunch); public void RecordPushTokenUpdated(string pushToken); @@ -11,8 +11,8 @@ namespace Unity.Services.PushNotifications public interface IPushNotificationsService { - public event System.Action> OnNotificationReceived; - public IPushNotificationsAnalytics Analytics { get; } + public event System.Action> OnRemoteNotificationReceived; + [System.Obsolete(@"Do not use this. It will be removed in a future version. Events are recorded for you automatically.")] public IPushNotificationsAnalytics Analytics { get; } public System.Threading.Tasks.Task RegisterForPushNotificationsAsync(); } diff --git a/Runtime/Unity.Services.PushNotifications.asmdef b/Runtime/Unity.Services.PushNotifications.asmdef index 4f51717..93c3ffc 100644 --- a/Runtime/Unity.Services.PushNotifications.asmdef +++ b/Runtime/Unity.Services.PushNotifications.asmdef @@ -4,7 +4,9 @@ "Unity.Services.Analytics", "Unity.Services.AnalyticsRuntime", "Unity.Services.Core", - "Unity.Services.Core.Internal" + "Unity.Services.Core.Internal", + "Unity.Notifications.iOS", + "Unity.Notifications.Android" ], "includePlatforms": [], "excludePlatforms": [], @@ -15,4 +17,4 @@ "defineConstraints": [], "versionDefines": [], "noEngineReferences": false -} \ No newline at end of file +} diff --git a/Runtime/iOS.meta b/Runtime/iOS.meta deleted file mode 100644 index 4e55f7f..0000000 --- a/Runtime/iOS.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 85c5045330d5a4e7c99b4fbc6e73ca06 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Runtime/iOS/iOSPushNotifications.cs b/Runtime/iOS/iOSPushNotifications.cs deleted file mode 100644 index 5f82e36..0000000 --- a/Runtime/iOS/iOSPushNotifications.cs +++ /dev/null @@ -1,128 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Runtime.InteropServices; -using System.Threading.Tasks; -using UnityEngine; - -namespace Unity.Services.PushNotifications -{ - class IOSPushNotifications - { - static object s_RegistrationLock = new object(); - static TaskCompletionSource s_DeviceRegistrationTcs; - static string s_DeviceToken; - - static PushNotificationReceivedHandler s_NotificationReceivedHandler; - static PushNotificationAnalytics s_NotificationAnalytics; - - internal static event Action> InternalNotificationWasReceived; - - delegate void NotificationRegistrationCallback(string deviceToken); - - delegate void NotificationReceivedCallback(string serialisedNotificationData); - -#if UNITY_IOS && !UNITY_EDITOR - [DllImport("__Internal")] - static extern void NativeRegisterForPushNotifications(NotificationRegistrationCallback callback); - - [DllImport("__Internal")] - static extern void RegisterUnityCallbackForNotificationReceived(NotificationReceivedCallback callback); - - [DllImport("__Internal")] - static internal extern string GetLaunchedNotificationString(); - - [DllImport("__Internal")] - static internal extern void ResetLaunchedNotificationString(); - - [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)] - internal static void PerformLaunchActions() - { - RegisterUnityCallbackForNotificationReceived(NotificationReceived); - } - -#endif - public IOSPushNotifications(PushNotificationReceivedHandler notificationReceivedHandler, PushNotificationAnalytics analytics) - { - s_NotificationReceivedHandler = notificationReceivedHandler; - s_NotificationAnalytics = analytics; - - #if UNITY_IOS && !UNITY_EDITOR - string launchedNotificationString = GetLaunchedNotificationString(); - - if (launchedNotificationString != null) - { - Debug.Log("App launched from notification, sending relevant events"); - NotificationReceived(launchedNotificationString); - - // remove launched notificationData so it cannot be re-processed - ResetLaunchedNotificationString(); - } - #endif - } - - /// - /// Registers for push notifications on iOS. Returns the device token for the registered device. - /// - /// The push notification token for this device - public Task RegisterForPushNotificationsAsync() - { - #if UNITY_IOS && !UNITY_EDITOR - lock (s_RegistrationLock) - { - if (!String.IsNullOrEmpty(s_DeviceToken)) - { - return Task.FromResult(s_DeviceToken); - } - - if (s_DeviceRegistrationTcs != null) - { - return s_DeviceRegistrationTcs.Task; - } - - s_DeviceRegistrationTcs = new TaskCompletionSource(); - - NativeRegisterForPushNotifications(NotificationRegistrationTokenReceived); - - return s_DeviceRegistrationTcs.Task; - } - #else - Debug.Log("iOS notification support is only available in iOS builds"); - return Task.FromResult(null); - #endif - } - - [AOT.MonoPInvokeCallback(typeof(NotificationRegistrationCallback))] - internal static void NotificationRegistrationTokenReceived(string token) - { - lock (s_RegistrationLock) - { - if (string.IsNullOrEmpty(token)) - { - s_DeviceRegistrationTcs.TrySetException(new Exception("Failed to register the device for remote notifications.")); - } - else - { - s_DeviceToken = token; - s_DeviceRegistrationTcs.TrySetResult(token); - s_NotificationAnalytics.RecordPushTokenUpdated(token); - Debug.Log($"Successfully registered for remote push notifications with token: {token}"); - } - - // Reset registration flow ready for next time. - s_DeviceRegistrationTcs = null; - } - } - - [AOT.MonoPInvokeCallback(typeof(NotificationReceivedCallback))] - internal static void NotificationReceived(string serialisedNotificationData) - { - if (string.IsNullOrEmpty(serialisedNotificationData)) - { - return; - } - - Dictionary userInfo = s_NotificationReceivedHandler.HandleReceivedNotification(serialisedNotificationData); - InternalNotificationWasReceived?.Invoke(userInfo); - } - } -} diff --git a/Samples~/Example/PushNotificationExample.cs b/Samples~/Example/PushNotificationExample.cs index 1ef5993..71abc7c 100644 --- a/Samples~/Example/PushNotificationExample.cs +++ b/Samples~/Example/PushNotificationExample.cs @@ -1,8 +1,8 @@ -using System; +using System.Collections.Generic; +using Unity.Services.Analytics; using Unity.Services.Core; using Unity.Services.PushNotifications; using UnityEngine; -using Unity.Services.Analytics; public class PushNotificationExample : MonoBehaviour { @@ -11,17 +11,24 @@ async void Start() { await UnityServices.InitializeAsync(); + PushNotificationsService.Instance.OnRemoteNotificationReceived += PushNotificationRecieved; + // Note: This is the minimum required to ensure the events with the push notification data are sent correctly through Analytics. - // In a real game you would need to handle privacy consent states here, see the Analytics documentation for more details. - await AnalyticsService.Instance.CheckForRequiredConsents(); + // In a real game you would need to handle privacy consent states here, see the Analytics documentation for more details: + // https://docs.unity.com/ugs/en-us/manual/analytics/manual/manage-data-privacy + AnalyticsService.Instance.StartDataCollection(); // Make sure to set the required settings in Project Settings before testing string token = await PushNotificationsService.Instance.RegisterForPushNotificationsAsync(); Debug.Log($"The push notification token is {token}"); + } - PushNotificationsService.Instance.OnNotificationReceived += notificationData => + void PushNotificationRecieved(Dictionary notificationData) + { + Debug.Log("Notification received!"); + foreach (KeyValuePair item in notificationData) { - Debug.Log("Data retrieved!"); - }; + Debug.Log($"Notification data item: {item.Key} - {item.Value}"); + } } } diff --git a/ValidationExceptions.json b/ValidationExceptions.json index 0962447..3d351eb 100644 --- a/ValidationExceptions.json +++ b/ValidationExceptions.json @@ -3,7 +3,7 @@ { "ValidationTest": "API Validation", "ExceptionMessage": "Breaking changes require a new major version.", - "PackageVersion": "3.0.1-pre.1" + "PackageVersion": "3.0.1-pre.2" } ], "WarningExceptions": [] diff --git a/package.json b/package.json index cfd9358..a958686 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "com.unity.services.push-notifications", "displayName": "Push Notifications", - "version": "3.0.1-pre.1", + "version": "4.0.0-pre.1", "unity": "2020.3", "_upm": { "gameService": { @@ -14,12 +14,13 @@ "Android", "iOS" ], - "changelog": "### Fixed\n\n- Android SDK Level 33 (Tiramisu) support now available.\n - Added necessary post notification permission to manifest.\n - Package will now ask for permission during initialization if required.\n- External Dependency Manager for Unity (EDM4U) and Mobile Dependency Resolver (MDR) support now available. When either is installed:\n - A new `PushSDKDependencies.xml` file is generated for them to use.\n - `InsertPushNotificationDependenciesIntoGradleScript` will not run to prevent duplication from gradle.\n- Fixed errors appearing in the Editor Play Mode due to platform specific classes instantiating." + "changelog": "### Changed\n\n- You can now only subscribe to OnNotificationReceived before calling RegisterForPushNotificationsAsync\n - Once RegisterForPushNotificationsAsync completes, OnNotificationReceived will be invoked if the app was launched from a remote notification\n- Updated `com.unity.services.analytics` dependency to 5.0.0\n- Updated `com.unity.services.core` dependency to 1.10.1\n- Added `com.unity.mobile.notifications` version `2.2.0` as a dependency.\n\n### Fixed\n\n- Behaviour when the app is launched from a push notification is now consistent between iOS and Android (incoming push notification data is broadcast after RegisterForPushNotificationsAsync flow is complete)" }, "description": "This package adds support for Push Notifications to your game. It allows sending rich push notifications with images, and provides analytics on the number of received push notifications.", "dependencies": { - "com.unity.services.analytics": "4.3.0", - "com.unity.services.core": "1.4.0" + "com.unity.services.analytics": "5.0.0", + "com.unity.services.core": "1.10.1", + "com.unity.mobile.notifications": "2.2.0" }, "samples": [ { @@ -29,15 +30,15 @@ } ], "relatedPackages": { - "com.unity.services.push-notifications.tests": "3.0.1-pre.1" + "com.unity.services.push-notifications.tests": "4.0.0-pre.1" }, "upmCi": { - "footprint": "927a49827610e91ab8c814bbc2e5b1574dd90449" + "footprint": "054068a89710c104e87a975345d09a133468fb0c" }, - "documentationUrl": "https://docs.unity3d.com/Packages/com.unity.services.push-notifications@3.0/manual/index.html", + "documentationUrl": "https://docs.unity3d.com/Packages/com.unity.services.push-notifications@4.0/manual/index.html", "repository": { "url": "https://github.cds.internal.unity3d.com/unity/operate-services-sdk.git", "type": "git", - "revision": "3805a41b5e29d7f30e70323b4bacd1a93335a8bb" + "revision": "90d4a9809f94049ed1b036b44dcdba044f530efd" } }