Spracherkennung für: .m vermutete Sprache: Abap {ABAP[55] Python[32] Lisp[29]} [Methode: maximale Elemente, drei Dimensionen]
#
import "AppGroup.h"
#
import "ThreemaFramework/ThreemaFramework-Swift.h"
#
define KEY_APP_GROUP_TYPE_APP @
"AppGroupTypeApp"
#
define KEY_APP_GROUP_TYPE_NOTIFICATION_EXTENSION @
"AppGroupTypeNotificationExtension"
#
define KEY_APP_GROUP_TYPE_SHARE_EXTENSION @
"AppGroupTypeShareExtension"
#
define KEY_DID_MIGRATION_CHECK @
"DefaultsKeyDidMigrationCheck"
#
define THREEMA_NOTIFICATION_EXTENSION_SUFFIX @
"NotificationExtension"
#
define THREEMA_SHARE_EXTENSION_SUFFIX @
"ShareExtension"
#
define THREEMA_APP_GROUP_NOTIFICATION_SUFFIX @
".SyncAppGroup"
#ifdef DEBUG
static const DDLogLevel ddLogLevel = DDLogLevelVerbose;
#
else
static const DDLogLevel ddLogLevel = DDLogLevelWarning;
#
endif
/*
Tooling to determine if extension or app is running.
E.g. when the share extension is triggered from within the app there is no other way to know that.
*/
static NSString
*appId;
static NSString
*groupId;
static CFStringRef appSyncNotificationKey;
static void observerCallback(void);
@
implementation AppGroup
+ (void)setAppId:(NSString
*)newAppId {
NSAssert(appId == nil || [appId isEqualToString:newAppId], @
"cannot change appId at runtime!");
appId = newAppId;
appSyncNotificationKey = CFBridgingRetain([NSString stringWithFormat:@
"%@%@", appId,
THREEMA_APP_GROUP_NOTIFICATION_SUFFIX]);
[self registerAppGroupSyncObserver];
}
+ (void)setGroupId:(NSString *)newGroupId {
NSAssert(groupId == nil || [groupId isEqualToString:newGroupId], @"cannot change groupId at runtime!");
groupId = newGroupId;
}
+ (NSString *)groupId {
NSAssert(groupId != nil, @"groupId not set");
return groupId;
}
+ (void)setActive:(BOOL)active forType:(AppGroupType)type {
NSAssert(appId != nil, @"appId not set, you need to set an id for the app or extension");
if (type == AppGroupTypeNone) {
return;
}
// Log AppGroupType, because of connection problem (Notification Extension steals connection from App and contrary)
DDLogWarn(@"Set AppGroupType %@ to active: %@", [AppGroup nameForType:type], active == YES ? @"YES" : @"NO");
NSUserDefaults *defaults = [self userDefaults];
[defaults setBool:active forKey:[self keyForType:type]];
[defaults synchronize];
}
+ (AppGroupType)getActiveType {
NSUserDefaults *defaults = [self userDefaults];
if ([defaults boolForKey:KEY_APP_GROUP_TYPE_NOTIFICATION_EXTENSION]) {
return AppGroupTypeNotificationExtension;
}
else if ([defaults boolForKey:KEY_APP_GROUP_TYPE_SHARE_EXTENSION]) {
return AppGroupTypeShareExtension;
}
else if ([defaults boolForKey:KEY_APP_GROUP_TYPE_APP]) {
return AppGroupTypeApp;
}
else {
return AppGroupTypeNone;
}
}
+ (AppGroupType)getCurrentType {
NSBundle *mainBundle = [NSBundle mainBundle];
if ([mainBundle.bundleIdentifier hasSuffix:THREEMA_NOTIFICATION_EXTENSION_SUFFIX]) {
return AppGroupTypeNotificationExtension;
}
if ([mainBundle.bundleIdentifier hasSuffix:THREEMA_SHARE_EXTENSION_SUFFIX]) {
return AppGroupTypeShareExtension;
} else {
return AppGroupTypeApp;
}
}
+ (NSString *)getCurrentTypeString {
NSBundle *mainBundle = [NSBundle mainBundle];
if ([mainBundle.bundleIdentifier hasSuffix:THREEMA_NOTIFICATION_EXTENSION_SUFFIX]) {
return @"NotificationExtension";
}
if ([mainBundle.bundleIdentifier hasSuffix:THREEMA_SHARE_EXTENSION_SUFFIX]) {
return @"AppGroupTypeShareExtension";
} else {
return @"AppGroupTypeApp";
}
}
+ (void)setMeActive {
if ([AppGroup getCurrentType] == AppGroupTypeApp) {
[AppGroup setActive:YES forType:AppGroupTypeApp];
[AppGroup setActive:NO forType:AppGroupTypeNotificationExtension];
[AppGroup setActive:NO forType:AppGroupTypeShareExtension];
}
else if ([AppGroup getCurrentType] == AppGroupTypeNotificationExtension) {
[AppGroup setActive:NO forType:AppGroupTypeApp];
[AppGroup setActive:YES forType:AppGroupTypeNotificationExtension];
[AppGroup setActive:NO forType:AppGroupTypeShareExtension];
}
else if ([AppGroup getCurrentType] == AppGroupTypeShareExtension) {
[AppGroup setActive:NO forType:AppGroupTypeApp];
[AppGroup setActive:NO forType:AppGroupTypeNotificationExtension];
[AppGroup setActive:YES forType:AppGroupTypeShareExtension];
}
else {
[AppGroup setActive:NO forType:AppGroupTypeApp];
[AppGroup setActive:NO forType:AppGroupTypeNotificationExtension];
[AppGroup setActive:NO forType:AppGroupTypeShareExtension];
}
}
+ (void)setMeInactive {
[AppGroup setActive:NO forType:[AppGroup getCurrentType]];
}
+ (BOOL)amIActive {
return [AppGroup getCurrentType] == [AppGroup getActiveType];
}
+ (BOOL)areOthersActive {
if ([AppGroup getActiveType] == AppGroupTypeNone || [AppGroup getActiveType] == [AppGroup getCurrentType]) {
return NO;
}
return YES;
}
+ (NSUserDefaults *)userDefaults {
static NSUserDefaults *userDefaults;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
userDefaults = [[NSUserDefaults alloc] initWithSuiteName: [self groupId]];
if ([userDefaults boolForKey:KEY_DID_MIGRATION_CHECK] == NO) {
[self migrateDefaults: userDefaults];
}
});
return userDefaults;
}
+ (void)migrateDefaults:(NSUserDefaults *)userDefaults {
NSUserDefaults *oldDefaults = [NSUserDefaults standardUserDefaults];
// Only the values the app actually stored: `dictionaryRepresentation` would also migrate the
// launch arguments set in the scheme (e.g. feature flags)
NSDictionary *oldValues = [oldDefaults persistentDomainForName:[[NSBundle mainBundle] bundleIdentifier]];
for (NSString *key in oldValues) {
[userDefaults setObject:oldValues[key] forKey:key];
}
[userDefaults setBool:YES forKey:KEY_DID_MIGRATION_CHECK];
[userDefaults synchronize];
}
+ (void)resetUserDefaults {
NSString *appDomain = [[NSBundle mainBundle] bundleIdentifier];
[[NSUserDefaults standardUserDefaults] removePersistentDomainForName:appDomain];
[[NSUserDefaults standardUserDefaults] removePersistentDomainForName:[AppGroup groupId]];
}
+ (NSString *)keyForType:(AppGroupType)type {
switch (type) {
case AppGroupTypeApp:
return KEY_APP_GROUP_TYPE_APP;
case AppGroupTypeNotificationExtension:
return KEY_APP_GROUP_TYPE_NOTIFICATION_EXTENSION;
case AppGroupTypeShareExtension:
return KEY_APP_GROUP_TYPE_SHARE_EXTENSION;
default:
DDLogError(@"unknown AppGroupType %d", type);
return KEY_APP_GROUP_TYPE_SHARE_EXTENSION;
}
}
+ (NSString *)nameForType:(AppGroupType)type {
switch (type) {
case AppGroupTypeApp: return @"App";
case AppGroupTypeShareExtension: return @"ShareExtension";
case AppGroupTypeNotificationExtension: return @"NotificationExtension";
case AppGroupTypeNone: return @"None";
default:
NSAssert(NO, @"Unknown App Group type");
return @"Unknown";
}
}
#pragma mark - inter app communication as seen in (https://developer.apple.com/videos/wwdc/2015/?id=224)
+ (void)registerAppGroupSyncObserver {
if ([AppGroup getCurrentType] != AppGroupTypeApp) {
// Otherwise notification gets consumed by extension
return;
}
CFNotificationCenterRef nc = CFNotificationCenterGetDarwinNotifyCenter();
CFNotificationCenterAddObserver(nc,
NULL,
(CFNotificationCallback)observerCallback,
appSyncNotificationKey,
NULL,
CFNotificationSuspensionBehaviorCoalesce);
}
+ (void)notifyAppGroupSyncNeeded {
if ([AppGroup getCurrentType] == AppGroupTypeApp) {
// Otherwise notification fires by app itself
return;
}
CFNotificationCenterRef nc = CFNotificationCenterGetDarwinNotifyCenter();
CFNotificationCenterPostNotification(nc,
appSyncNotificationKey,
nil,
nil,
TRUE);
}
@end
// The definition of this global C function should be outside of AppGroup implementation
static void observerCallback(void) {
[AppGroup refreshDirtyObjects];
};