Skip to content
This repository has been archived by the owner on Sep 4, 2020. It is now read-only.

Commit

Permalink
[ios] better swizzling
Browse files Browse the repository at this point in the history
This still isn't the "right way" linked in #427, but seems to be safe
and void of side effects due to the namespacing of all the methods.

It has been tested to work side by side with another plugin that also
swizzles AppDelegate's applicationDidBecomeActive.

1. wrapped swizzling in dispatch_once
2. first attempts class_addMethod / class_replaceMethod but if that
fails falls back to method_exchangeImplementations.
3. swizzled_init => pushPluginSwizzledInit (if other plugins attempt to
swizzle init and use the same name, there seems to be a collision)
4. added an observer for UIApplicationDidBecomeActiveNotification
instead of overriding applicationDidBecomeActive
5. applicationDidBecomeActive => pushPluginOnApplicationDidBecomeActive
(and it becomes a notification observer instead)

See http://nshipster.com/method-swizzling/ and "Avoid collisions" under
"Considerations".

This will need testng by someone that understands the plugin better than
I do, but it should not be changing the core functionality at all. The
pushPluginOnApplicationDidBecomeActive method *is* called when the
application becomes active, etc.

Goes a long way toward fixing #427 without regressing #447, etc.
  • Loading branch information
devgeeks committed Mar 1, 2016
1 parent 64d68bf commit ee58346
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 11 deletions.
2 changes: 1 addition & 1 deletion src/ios/AppDelegate+notification.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken;
- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error;
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:( void (^)(UIBackgroundFetchResult))completionHandler;
- (void)applicationDidBecomeActive:(UIApplication *)application;
- (void)pushPluginOnApplicationDidBecomeActive:(UIApplication *)application;
- (void)application:(UIApplication *)application handleActionWithIdentifier:(NSString *)identifier forRemoteNotification:(NSDictionary *)userInfo completionHandler:(void(^)())completionHandler;
- (id) getCommandInstance:(NSString*)className;

Expand Down
48 changes: 38 additions & 10 deletions src/ios/AppDelegate+notification.m
Original file line number Diff line number Diff line change
Expand Up @@ -23,21 +23,47 @@ - (id) getCommandInstance:(NSString*)className
// Instead we will use method swizzling. we set this up in the load call.
+ (void)load
{
Method original, swizzled;

original = class_getInstanceMethod(self, @selector(init));
swizzled = class_getInstanceMethod(self, @selector(swizzled_init));
method_exchangeImplementations(original, swizzled);
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
Class class = [self class];

SEL originalSelector = @selector(init);
SEL swizzledSelector = @selector(pushPluginSwizzledInit);

Method original = class_getInstanceMethod(class, originalSelector);
Method swizzled = class_getInstanceMethod(class, swizzledSelector);

BOOL didAddMethod =
class_addMethod(class,
originalSelector,
method_getImplementation(swizzled),
method_getTypeEncoding(swizzled));

if (didAddMethod) {
class_replaceMethod(class,
swizzledSelector,
method_getImplementation(original),
method_getTypeEncoding(original));
} else {
method_exchangeImplementations(original, swizzled);
}
});
}

- (AppDelegate *)swizzled_init
- (AppDelegate *)pushPluginSwizzledInit
{
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(createNotificationChecker:)
name:@"UIApplicationDidFinishLaunchingNotification" object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(createNotificationChecker:)
name:UIApplicationDidFinishLaunchingNotification
object:nil];
[[NSNotificationCenter defaultCenter]addObserver:self
selector:@selector(pushPluginOnApplicationDidBecomeActive:)
name:UIApplicationDidBecomeActiveNotification
object:nil];

// This actually calls the original init method over in AppDelegate. Equivilent to calling super
// on an overrided method, this is not recursive, although it appears that way. neat huh?
return [self swizzled_init];
return [self pushPluginSwizzledInit];
}

// This code will be called immediately after application:didFinishLaunchingWithOptions:. We need
Expand Down Expand Up @@ -127,10 +153,12 @@ - (BOOL)userHasRemoteNotificationsEnabled {
}
}

- (void)applicationDidBecomeActive:(UIApplication *)application {
- (void)pushPluginOnApplicationDidBecomeActive:(NSNotification *)notification {

NSLog(@"active");

UIApplication *application = notification.object;

PushPlugin *pushHandler = [self getCommandInstance:@"PushNotification"];
if (pushHandler.clearBadge) {
NSLog(@"PushPlugin clearing badge");
Expand Down

0 comments on commit ee58346

Please sign in to comment.