Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(ios): reviving PR #12411 for ios background tasks #14142

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions iphone/Classes/TiAppiOSProxy.m
Original file line number Diff line number Diff line change
Expand Up @@ -161,9 +161,20 @@ - (void)_listenerRemoved:(NSString *)type count:(int)count
if ((count == 1) && [type isEqual:@"backgroundfetch"]) {
[[NSNotificationCenter defaultCenter] removeObserver:self name:kTiBackgroundFetchNotification object:nil];
}
if ((count == 1) && [type isEqual:@"backgroundprocess"]) {
[[NSNotificationCenter defaultCenter] removeObserver:self name:kTiBackgroundProcessNotification object:nil];
}
if ((count == 1) && [type isEqual:@"sessioneventscompleted"]) {
[[NSNotificationCenter defaultCenter] removeObserver:self name:kTiURLSessionEventsCompleted object:nil];
}
if ((count == 1) && [type isEqual:@"backgroundprocess"]) {
NSArray *backgroundModes = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"UIBackgroundModes"];
if ([backgroundModes containsObject:@"processing"]) {
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didReceiveBackgroundProcessNotification:) name:kTiBackgroundProcessNotification object:nil];
} else {
DebugLog(@"[ERROR] Cannot add backgroundprocess eventListener. Please add `processing` to UIBackgroundModes inside info.plist ");
}
}
if ((count == 1) && [type isEqual:@"silentpush"]) {
[[NSNotificationCenter defaultCenter] removeObserver:self name:kTiSilentPushNotification object:nil];
}
Expand Down Expand Up @@ -407,6 +418,20 @@ - (TiAppiOSBackgroundServiceProxy *)registerBackgroundService:(id)args
return proxy;
}

- (void)registerBackgroundTask:(id)args
{
ENSURE_SINGLE_ARG(args, NSDictionary);
ENSURE_STRING(args[@"identifier"]);
ENSURE_STRING(args[@"type"]);

if ([TiUtils isIOSVersionLower:@"13.0"]) {
DebugLog(@"This API is not supported fo iOS < 13.0");
return;
}

[[TiApp app] addBackgroundTask:args];
}

- (void)registerUserNotificationSettings:(id)args
{
ENSURE_SINGLE_ARG(args, NSDictionary);
Expand Down Expand Up @@ -889,6 +914,11 @@ - (void)didReceiveBackgroundFetchNotification:(NSNotification *)note
[self fireEvent:@"backgroundfetch" withObject:[note userInfo]];
}

- (void)didReceiveBackgroundProcessNotification:(NSNotification *)note
{
[self fireEvent:@"backgroundprocess" withObject:[note userInfo]];
}

- (void)didReceiveSilentPushNotification:(NSNotification *)note
{
[self fireEvent:@"silentpush" withObject:[note userInfo]];
Expand Down Expand Up @@ -975,6 +1005,9 @@ - (void)endBackgroundHandler:(id)handlerIdentifier

if ([handlerIdentifier rangeOfString:@"Session"].location != NSNotFound) {
[[TiApp app] performCompletionHandlerForBackgroundTransferWithKey:handlerIdentifier];
} else if ([handlerIdentifier hasPrefix:@"BgTask-"]) {
// handlerId = @"BgTask-" + BgTask.identifier. So remove @"BgTask-" to get actual BgTask identifier.
[[TiApp app] backgroundTaskCompletedForIdentifier:[handlerIdentifier substringFromIndex:7]];
} else {
[[TiApp app] performCompletionHandlerWithKey:handlerIdentifier andResult:UIBackgroundFetchResultNoData removeAfterExecution:NO];
}
Expand Down Expand Up @@ -1338,6 +1371,9 @@ - (NSString *)applicationOpenSettingsURL
MAKE_SYSTEM_PROP(USER_NOTIFICATION_ALERT_STYLE_ALERT, UNAlertStyleAlert);
MAKE_SYSTEM_PROP(USER_NOTIFICATION_ALERT_STYLE_BANNER, UNAlertStyleBanner);

MAKE_SYSTEM_STR(BACKGROUND_TASK_TYPE_REFRESH, @"refresh");
MAKE_SYSTEM_STR(BACKGROUND_TASK_TYPE_PROCESS, @"process");

@end

#endif
2 changes: 1 addition & 1 deletion iphone/TitaniumKit/TitaniumKit.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
archiveVersion = 1;
classes = {
};
objectVersion = 52;
objectVersion = 54;
objects = {

/* Begin PBXAggregateTarget section */
Expand Down
10 changes: 9 additions & 1 deletion iphone/TitaniumKit/TitaniumKit/Sources/API/TiApp.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#import "KrollBridge.h"
#import "TiHost.h"
#import "TiRootViewController.h"
#import <BackgroundTasks/BackgroundTasks.h>
#import <JavaScriptCore/JavaScriptCore.h>

extern BOOL applicationInMemoryPanic; // TODO: Remove in SDK 9.0+
Expand Down Expand Up @@ -56,8 +57,12 @@ TI_INLINE void waitForMemoryPanicCleared() // WARNING: This must never be run on

NSString *sessionId;

UIBackgroundTaskIdentifier bgTask;
UIBackgroundTaskIdentifier bgTaskIdentifier;
NSMutableArray *backgroundServices;

NSMutableArray *backgroundTasks;
NSMutableArray *registeredBackgroundTasks;

NSMutableArray *runningServices;
NSDictionary *localNotification;
UIApplicationShortcutItem *launchedShortcutItem;
Expand Down Expand Up @@ -294,6 +299,9 @@ TI_INLINE void waitForMemoryPanicCleared() // WARNING: This must never be run on
*/
- (void)tryToPostBackgroundModeNotification:(NSMutableDictionary *)userInfo withNotificationName:(NSString *)notificationName;

- (void)addBackgroundTask:(NSDictionary *)bgTask;
- (void)backgroundTaskCompletedForIdentifier:(NSString *)identifier;

- (void)registerBackgroundService:(TiProxy *)proxy;
- (void)unregisterBackgroundService:(TiProxy *)proxy;
- (void)stopBackgroundService:(TiProxy *)proxy;
Expand Down
131 changes: 124 additions & 7 deletions iphone/TitaniumKit/TitaniumKit/Sources/API/TiApp.m
Original file line number Diff line number Diff line change
Expand Up @@ -433,6 +433,10 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(
// Create application support directory if not exists
[self createDefaultDirectories];

if ([TiUtils isIOSVersionOrGreater:@"13.0"]) {
[self registerBackgroundTasks];
}

return YES;
}

Expand Down Expand Up @@ -1083,20 +1087,26 @@ - (void)applicationDidEnterBackground:(UIApplication *)application

[[NSNotificationCenter defaultCenter] postNotificationName:kTiPausedNotification object:self];

if ([TiUtils isIOSVersionOrGreater:@"13.0"]) {
for (NSDictionary *backgroundTask in backgroundTasks) {
[self submitBackgroundTask:backgroundTask];
}
}

if (backgroundServices == nil) {
return;
}

UIApplication *app = [UIApplication sharedApplication];
TiApp *tiapp = self;
bgTask = [app beginBackgroundTaskWithExpirationHandler:^{
bgTaskIdentifier = [app beginBackgroundTaskWithExpirationHandler:^{
// Synchronize the cleanup call on the main thread in case
// the task actually finishes at around the same time.
TiThreadPerformOnMainThread(
^{
if (bgTask != UIBackgroundTaskInvalid) {
[app endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
if (bgTaskIdentifier != UIBackgroundTaskInvalid) {
[app endBackgroundTask:bgTaskIdentifier];
bgTaskIdentifier = UIBackgroundTaskInvalid;
}
},
NO);
Expand Down Expand Up @@ -1202,6 +1212,8 @@ - (void)dealloc
RELEASE_TO_NIL(queuedBootEvents);
RELEASE_TO_NIL(_queuedApplicationSelectors);
RELEASE_TO_NIL(_applicationDelegates);
RELEASE_TO_NIL(backgroundTasks);
RELEASE_TO_NIL(registeredBackgroundTasks);

[super dealloc];
}
Expand Down Expand Up @@ -1237,6 +1249,111 @@ - (KrollBridge *)krollBridge

#pragma mark Background Tasks

- (void)registerBackgroundTasks
{
NSArray *identifiers = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"BGTaskSchedulerPermittedIdentifiers"];

for (NSString *identifier in identifiers) {
if (registeredBackgroundTasks == nil) {
registeredBackgroundTasks = [[NSMutableArray alloc] init];
}
[[BGTaskScheduler sharedScheduler] registerForTaskWithIdentifier:identifier
usingQueue:nil
launchHandler:^(__kindof BGTask *_Nonnull task) {
[registeredBackgroundTasks addObject:task];
[self handleBGTask:task];
}];
}
}

- (void)handleBGTask:(BGTask *)task
{
NSString *notificationName = kTiBackgroundProcessNotification;
if ([task isKindOfClass:[BGAppRefreshTask class]]) {
// Fo refresh task submit it again
[self submitTaskForIdentifier:task.identifier];
notificationName = kTiBackgroundFetchNotification;
}
NSString *key = [NSString stringWithFormat:@"BgTask-%@", task.identifier];

[self tryToPostBackgroundModeNotification:[NSMutableDictionary dictionaryWithObjectsAndKeys:key, @"handlerId", nil]
withNotificationName:notificationName];

task.expirationHandler = ^{
if ([task isKindOfClass:[BGProcessingTask class]]) {
// Fo processing task, if it is not completed in time then only submit it again.
[self submitTaskForIdentifier:task.identifier];
}
[task setTaskCompletedWithSuccess:false];
[registeredBackgroundTasks removeObject:task];
};
}

- (void)submitTaskForIdentifier:(NSString *)identifier
{
NSDictionary *backgroundTask = [self backgroundTaskForIdentifier:identifier];
if (backgroundTask) {
[self submitBackgroundTask:backgroundTask];
}
}

- (void)submitBackgroundTask:(NSDictionary *)bgTask
{
BGTaskRequest *taskRequest;
if ([bgTask[@"type"] isEqualToString:@"process"]) {
taskRequest = [[[BGProcessingTaskRequest alloc] initWithIdentifier:bgTask[@"identifier"]] autorelease];
((BGProcessingTaskRequest *)taskRequest).requiresNetworkConnectivity = [TiUtils boolValue:bgTask[@"networkConnect"] def:NO];
((BGProcessingTaskRequest *)taskRequest).requiresExternalPower = [TiUtils boolValue:bgTask[@"powerConnect"] def:NO];
} else {
taskRequest = [[[BGAppRefreshTaskRequest alloc] initWithIdentifier:bgTask[@"identifier"]] autorelease];
}
taskRequest.earliestBeginDate = bgTask[@"beginDate"];

[BGTaskScheduler.sharedScheduler submitTaskRequest:taskRequest error:nil];
}

- (void)backgroundTaskCompletedForIdentifier:(NSString *)identifier
{
for (BGTask *task in registeredBackgroundTasks) {
if ([task.identifier isEqualToString:identifier]) {
[task setTaskCompletedWithSuccess:YES];
[registeredBackgroundTasks removeObject:task];
break;
}
}
}

- (NSDictionary *_Nullable)backgroundTaskForIdentifier:(NSString *)identifier
{
NSDictionary *bgTask = nil;
for (NSDictionary *backgroundTask in backgroundTasks) {
if (backgroundTask[@"identifier"] == identifier) {
bgTask = backgroundTask;
break;
}
}
return bgTask;
}

- (void)addBackgroundTask:(NSDictionary *)backgroundTask
{
if (backgroundTasks == nil) {
backgroundTasks = [[NSMutableArray alloc] init];
}
NSArray *identifiers = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"BGTaskSchedulerPermittedIdentifiers"];
NSDictionary *oldTask = [self backgroundTaskForIdentifier:backgroundTask[@"identifier"]];
if ([identifiers containsObject:backgroundTask[@"identifier"]]) {
if (oldTask) {
[backgroundTasks removeObject:oldTask];
}
[backgroundTasks addObject:backgroundTask];
} else {
DebugLog(@"The identifier, %@, is not added in tiapp.xml. Add it against key BGTaskSchedulerPermittedIdentifiers", backgroundTask[@"identifier"]);
}
}

#pragma mark Background Services

- (void)beginBackgrounding
{
if (runningServices == nil) {
Expand Down Expand Up @@ -1383,9 +1500,9 @@ - (void)checkBackgroundServices
// the expiration handler is fired at the same time.
TiThreadPerformOnMainThread(
^{
if (bgTask != UIBackgroundTaskInvalid) {
[[UIApplication sharedApplication] endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
if (bgTaskIdentifier != UIBackgroundTaskInvalid) {
[[UIApplication sharedApplication] endBackgroundTask:bgTaskIdentifier];
bgTaskIdentifier = UIBackgroundTaskInvalid;
}
},
NO);
Expand Down
1 change: 1 addition & 0 deletions iphone/TitaniumKit/TitaniumKit/Sources/API/TiBase.h
Original file line number Diff line number Diff line change
Expand Up @@ -591,6 +591,7 @@ extern NSString *const kTiRemoteDeviceUUIDNotification;
extern NSString *const kTiGestureShakeNotification;
extern NSString *const kTiRemoteControlNotification;
extern NSString *const kTiBackgroundFetchNotification;
extern NSString *const kTiBackgroundProcessNotification;
extern NSString *const kTiSilentPushNotification;
extern NSString *const kTiBackgroundTransfer;
extern NSString *const kTiCurrentLocale;
Expand Down
1 change: 1 addition & 0 deletions iphone/TitaniumKit/TitaniumKit/Sources/API/TiBase.m
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ void TiLogMessage(NSString *str, ...)
NSString *const kTiGestureShakeNotification = @"TiGestureShake";
NSString *const kTiRemoteControlNotification = @"TiRemoteControl";
NSString *const kTiBackgroundFetchNotification = @"TiBackgroundFetch";
NSString *const kTiBackgroundProcessNotification = @"TiBackgroundProcess";
NSString *const kTiSilentPushNotification = @"TiSilentPush";
NSString *const kTiBackgroundTransfer = @"TiBackgroundTransfer";
NSString *const kTiCurrentLocale = @"kTiCurrentLocale";
Expand Down
26 changes: 25 additions & 1 deletion iphone/iphone/Assets.xcassets/AppIcon.appiconset/Contents.json
Original file line number Diff line number Diff line change
Expand Up @@ -103,10 +103,34 @@
"idiom" : "ios-marketing",
"filename" : "appicon-1024.png",
"scale" : "1x"
},
AbdullahFaqeir marked this conversation as resolved.
Show resolved Hide resolved
{
"appearances" : [
{
"appearance" : "luminosity",
"value" : "dark"
}
],
"filename" : "DefaultIcon-Dark.png",
"idiom" : "universal",
"platform" : "ios",
"size" : "1024x1024"
},
{
"appearances" : [
{
"appearance" : "luminosity",
"value" : "tinted"
}
],
"filename" : "DefaultIcon-Tinted.png",
"idiom" : "universal",
"platform" : "ios",
"size" : "1024x1024"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
}
2 changes: 2 additions & 0 deletions iphone/iphone/Titanium.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -2391,6 +2391,7 @@
DEVELOPMENT_TEAM = "";
ENABLE_BITCODE = NO;
"ENABLE_HARDENED_RUNTIME[sdk=macosx*]" = YES;
EXCLUDED_ARCHS = "";
GCC_DYNAMIC_NO_PIC = NO;
GCC_ENABLE_CPP_RTTI = NO;
GCC_OPTIMIZATION_LEVEL = 0;
Expand Down Expand Up @@ -2454,6 +2455,7 @@
ENABLE_BITCODE = NO;
"ENABLE_HARDENED_RUNTIME[sdk=macosx*]" = YES;
ENABLE_NS_ASSERTIONS = NO;
EXCLUDED_ARCHS = "";
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = Titanium_Prefix.pch;
GCC_PREPROCESSOR_DEFINITIONS = (
Expand Down
Loading
Loading