Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Threema/ThreemaFramework/Business/   (Social Medium ©)  Datei vom 26.9.2026 mit Größe 8 kB image not shown  

Quelle  AppGroup.m  Sprache: unbekannt

 
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];
};

[Dauer der Verarbeitung: 0.15 Sekunden]