Files
UnrealEngineUWP/Engine/Source/Runtime/IOS/IOSLocalNotification/Private/IOSLocalNotification.cpp
thomas ross c9f763bea5 Adding background http protype system. Enables downloading files while app is suspended on iOS. Other platforms need to be added over time if desired. For now other platforms just wrap basic HTTPRequests under the hood.
#rb none
#tests iOS / Android
[CODEREVIEW] Andrew.Grant,Daniel.Lamb,Justin.Marcus
[FYI] Pete.Sauerbrei

#ROBOMERGE-OWNER: robert.manuszewski
#ROBOMERGE-AUTHOR: thomas.ross
#ROBOMERGE-SOURCE: CL 4898958 via CL 4898963 via CL 4898965 via CL 4905881 via CL 4906509
#ROBOMERGE-BOT: CORE (Main -> Dev-Core)

[CL 5015742 by thomas ross in Dev-Core branch]
2019-02-16 01:05:14 -05:00

319 lines
11 KiB
C++

// Copyright 1998-2019 Epic Games, Inc. All Rights Reserved.
/*=============================================================================
IOSLocalNotification.cpp: Unreal IOSLocalNotification service interface object.
=============================================================================*/
/*------------------------------------------------------------------------------------
Includes
------------------------------------------------------------------------------------*/
#include "IOSLocalNotification.h"
#include "IOS/IOSApplication.h"
#include "IOS/IOSAppDelegate.h"
#include "Modules/ModuleManager.h"
#include "Logging/LogMacros.h"
#if __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_10_0
#import <UserNotifications/UserNotifications.h>
#endif
DEFINE_LOG_CATEGORY(LogIOSLocalNotification);
class FIOSLocalNotificationModule : public ILocalNotificationModule
{
public:
/** Creates a new instance of the audio device implemented by the module. */
virtual ILocalNotificationService* GetLocalNotificationService() override
{
static ILocalNotificationService* oneTrueLocalNotificationService = nullptr;
if(oneTrueLocalNotificationService == nullptr)
{
oneTrueLocalNotificationService = new FIOSLocalNotificationService;
}
return oneTrueLocalNotificationService;
}
#if !PLATFORM_TVOS
#if __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_10_0
static UNMutableNotificationContent* CreateNotificationContent(const FText& Title, const FText& Body, const FText& Action, const FString& ActivationEvent, uint32 BadgeNumber)
{
UNMutableNotificationContent* Content = [UNMutableNotificationContent new];
if(Content != nil)
{
if(!Title.IsEmpty())
{
NSString* NotificationTitle = [NSString stringWithFString:Title.ToString()];
if(NotificationTitle != nil)
{
Content.title = NotificationTitle;
}
}
if(!Body.IsEmpty())
{
NSString* NotificationBody = [NSString stringWithFString:Body.ToString()];
if(NotificationBody != nil)
{
Content.body = NotificationBody;
}
}
NSNumber* BadgeNSNumber = [NSNumber numberWithInt:BadgeNumber];
Content.badge = BadgeNSNumber;
Content.sound = [UNNotificationSound defaultSound];
if(!ActivationEvent.IsEmpty())
{
NSString* ActivationEventString = [NSString stringWithFString:ActivationEvent];
NSString* LocalString = [NSString stringWithFString:FString(TEXT("Local"))];
if (ActivationEventString != nil && LocalString != nil)
{
NSDictionary* Dict = [NSDictionary dictionaryWithObjectsAndKeys: ActivationEventString, @"ActivationEvent", LocalString, @"NotificationType", nil];
if (Dict != nil)
{
Content.userInfo = Dict;
}
}
}
}
return Content;
}
static UNCalendarNotificationTrigger* CreateCalendarNotificationTrigger(const FDateTime& FireDateTime)
{
NSCalendar *calendar = [NSCalendar autoupdatingCurrentCalendar];
NSDateComponents *dateComps = [[NSDateComponents alloc] init];
[dateComps setDay : FireDateTime.GetDay()];
[dateComps setMonth : FireDateTime.GetMonth()];
[dateComps setYear : FireDateTime.GetYear()];
[dateComps setHour : FireDateTime.GetHour()];
[dateComps setMinute : FireDateTime.GetMinute()];
[dateComps setSecond : FireDateTime.GetSecond()];
UNCalendarNotificationTrigger *trigger = [UNCalendarNotificationTrigger triggerWithDateMatchingComponents:dateComps repeats:NO];
return trigger;
}
#else
static UILocalNotification* CreateLocalNotification(const FDateTime& FireDateTime, bool bLocalTime, const FString& ActivationEvent)
{
UIApplication* application = [UIApplication sharedApplication];
NSCalendar *calendar = [NSCalendar autoupdatingCurrentCalendar];
NSDateComponents *dateComps = [[NSDateComponents alloc] init];
[dateComps setDay : FireDateTime.GetDay()];
[dateComps setMonth : FireDateTime.GetMonth()];
[dateComps setYear : FireDateTime.GetYear()];
[dateComps setHour : FireDateTime.GetHour()];
[dateComps setMinute : FireDateTime.GetMinute()];
[dateComps setSecond : FireDateTime.GetSecond()];
NSDate *itemDate = [calendar dateFromComponents : dateComps];
UILocalNotification *localNotif = [[UILocalNotification alloc] init];
if (localNotif != nil)
{
localNotif.fireDate = itemDate;
if (bLocalTime)
{
localNotif.timeZone = [NSTimeZone defaultTimeZone];
}
else
{
localNotif.timeZone = nil;
}
NSString* activateEventNSString = [NSString stringWithFString:ActivationEvent];
if (activateEventNSString != nil)
{
NSDictionary* infoDict = [NSDictionary dictionaryWithObject:activateEventNSString forKey:@"ActivationEvent"];
if (infoDict != nil)
{
localNotif.userInfo = infoDict;
}
}
}
return localNotif;
}
#endif
#endif
};
IMPLEMENT_MODULE(FIOSLocalNotificationModule, IOSLocalNotification);
/*------------------------------------------------------------------------------------
FIOSLocalNotification
------------------------------------------------------------------------------------*/
FIOSLocalNotificationService::FIOSLocalNotificationService()
{
AppLaunchedWithNotification = false;
LaunchNotificationFireDate = 0;
}
void FIOSLocalNotificationService::ClearAllLocalNotifications()
{
#if !PLATFORM_TVOS
#if __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_10_0
UNUserNotificationCenter *Center = [UNUserNotificationCenter currentNotificationCenter];
[Center removeAllPendingNotificationRequests];
#else
UIApplication* application = [UIApplication sharedApplication];
[application cancelAllLocalNotifications];
#endif
#endif
}
static uint32 NotificationNumber = 0;
void FIOSLocalNotificationService::ScheduleLocalNotificationAtTime(const FDateTime& FireDateTime, bool LocalTime, const FText& Title, const FText& Body, const FText& Action, const FString& ActivationEvent)
{
#if !PLATFORM_TVOS
#if __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_10_0
//Create local copies of these for the block to capture
FDateTime FireDateTimeCopy = FireDateTime;
FText TitleCopy = Title;
FText BodyCopy = Body;
FText ActionCopy = Action;
FString ActivationEventCopy = ActivationEvent;
//have to schedule notification on main thread queue
dispatch_async(dispatch_get_main_queue(), ^{
UNMutableNotificationContent* Content = FIOSLocalNotificationModule::CreateNotificationContent(TitleCopy, BodyCopy, ActionCopy, ActivationEventCopy, 1);
UNCalendarNotificationTrigger* Trigger = FIOSLocalNotificationModule::CreateCalendarNotificationTrigger(FireDateTimeCopy);
UNUserNotificationCenter *Center = [UNUserNotificationCenter currentNotificationCenter];
FString NotId = TitleCopy.ToString() + FString::FromInt(NotificationNumber);
NSString* NotificationIdentifier = [NSString stringWithFString : NotId];
UNNotificationRequest *Request = [UNNotificationRequest requestWithIdentifier:NotificationIdentifier content:Content trigger:Trigger];
[Center addNotificationRequest : Request withCompletionHandler : ^ (NSError * _Nullable error) {
if (error != nil) {
UE_LOG(LogIOSLocalNotification, Warning, TEXT("Error scheduling notification: %s"), *NotId);
}
}];
});
#else
//Create local copies of these for the block to capture
FDateTime FireDateTimeCopy = FireDateTime;
FText TitleCopy = Title;
FText BodyCopy = Body;
FText ActionCopy = Action;
FString ActivationEventCopy = ActivationEvent;
//have to schedule notification on main thread queue
dispatch_async(dispatch_get_main_queue(), ^{
UILocalNotification *localNotif = FIOSLocalNotificationModule::CreateLocalNotification(FireDateTimeCopy, LocalTime, ActivationEventCopy);
if (localNotif == nil)
return;
NSString* alertBody = [NSString stringWithFString : BodyCopy.ToString()];
if (alertBody != nil)
{
localNotif.alertBody = alertBody;
}
NSString* alertAction = [NSString stringWithFString : ActionCopy.ToString()];
if (alertAction != nil)
{
localNotif.alertAction = alertAction;
}
if ([IOSAppDelegate GetDelegate].OSVersion >= 8.2f)
{
NSString* alertTitle = [NSString stringWithFString : TitleCopy.ToString()];
if (alertTitle != nil)
{
localNotif.alertTitle = alertTitle;
}
}
localNotif.soundName = UILocalNotificationDefaultSoundName;
localNotif.applicationIconBadgeNumber = 1;
[[UIApplication sharedApplication] scheduleLocalNotification:localNotif];
});
#endif
#endif
}
void FIOSLocalNotificationService::ScheduleLocalNotificationBadgeAtTime(const FDateTime& FireDateTime, bool LocalTime, const FString& ActivationEvent)
{
#if !PLATFORM_TVOS
#if __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_10_0
UNMutableNotificationContent* Content = FIOSLocalNotificationModule::CreateNotificationContent(FText(), FText(), FText(), ActivationEvent, 1);
UNCalendarNotificationTrigger* Trigger = FIOSLocalNotificationModule::CreateCalendarNotificationTrigger(FireDateTime);
UNUserNotificationCenter *Center = [UNUserNotificationCenter currentNotificationCenter];
FString NotId = FString(TEXT("Badge")) + FString::FromInt(NotificationNumber);
NSString* NotificationIdentifier = [NSString stringWithFString:NotId];
UNNotificationRequest *Request = [UNNotificationRequest requestWithIdentifier:NotificationIdentifier content:Content trigger:Trigger];
[Center addNotificationRequest:Request withCompletionHandler:^(NSError * _Nullable error) {
if (error != nil) {
UE_LOG(LogIOSLocalNotification, Warning, TEXT("Error scheduling notification: %s"), *NotId);
}
}];
#else
UILocalNotification *localNotif = FIOSLocalNotificationModule::CreateLocalNotification(FireDateTime, LocalTime, ActivationEvent);
if (localNotif == nil)
return;
// As per Apple documentation, a nil 'alertBody' results in 'no alert'
// https://developer.apple.com/reference/uikit/uilocalnotification/1616646-alertbody?language=objc
localNotif.alertBody = nil;
localNotif.applicationIconBadgeNumber = 1;
[[UIApplication sharedApplication] scheduleLocalNotification:localNotif];
#endif
#endif
}
void FIOSLocalNotificationService::CancelLocalNotification(const FString& ActivationEvent)
{
// TODO
}
void FIOSLocalNotificationService::GetLaunchNotification(bool& NotificationLaunchedApp, FString& ActivationEvent, int32& FireDate)
{
NotificationLaunchedApp = AppLaunchedWithNotification;
ActivationEvent = LaunchNotificationActivationEvent;
FireDate = LaunchNotificationFireDate;
}
void FIOSLocalNotificationService::SetLaunchNotification(FString const& ActivationEvent, int32 FireDate)
{
AppLaunchedWithNotification = true;
LaunchNotificationActivationEvent = ActivationEvent;
LaunchNotificationFireDate = FireDate;
}
static FIOSLocalNotificationService::FAllowedNotifications NotificationsAllowedDelegate;
void FIOSLocalNotificationService::CheckAllowedNotifications(const FAllowedNotifications& AllowedNotificationsDelegate)
{
#if __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_10_0
NotificationsAllowedDelegate = AllowedNotificationsDelegate;
UNUserNotificationCenter *Center = [UNUserNotificationCenter currentNotificationCenter];
[Center getNotificationSettingsWithCompletionHandler:^(UNNotificationSettings * _Nonnull settings) {
bool NotificationsAllowed = settings.authorizationStatus == UNAuthorizationStatusAuthorized;
NotificationsAllowedDelegate.ExecuteIfBound(NotificationsAllowed);
}];
#else
checkf(false, TEXT("For min iOS version < 10 use FIOSPlatformMisc::IsAllowedRemoteNotifications()."));
#endif
}