Can you swizzle application:didReceiveRemoteNotification:

2k views Asked by At

I'm currently working on a product that needs to swizzle the AppDelegate's application:didReceiveRemoteNotification: (I don't want to call my new method in the appDelegate itself).

The thing is: the swizzling simply doesn't work. I've already swizzled methods several times before with success, and this time, the replacing implementation is simply not called. I was wondering if that was because of some specificity of the appDelegate's methods, since these are called by the system, and not the application.

1

There are 1 answers

2
Saumitra R. Bhave On

I am going to assume most of the things which are missing in your question, Its a great idea to always post the questions with code samples whenever possible.

  1. You need to make sure that you are swizzling your methods on the specific implementation of UIApplicationDelegate and NOT the UIApplicationDelegate itself. For Eg

    @interface AppDelegate : UIResponder <UIApplicationDelegate>
    @end
    

    In this case you need to swizzle the AppDelegate Class.

  2. Also, if you are trying to write a static library/framework you may not know the name of this class at all. In such cases simplest/safest way is to ask for App's AppDelegate name and use that to retrieve a specific class instance via NSClassFromString() or you can just brute force to find the class you need (because you usually have a Single AppDelegate class).

        unsigned int numberOfClasses = 0;
        Class *classes = objc_copyClassList(&numberOfClasses);
        Class appDelegateClass = nil;
        for (unsigned int i = 0; i < numberOfClasses; ++i) {
            if (class_conformsToProtocol(classes[i], @protocol(UIApplicationDelegate))) {
                appDelegateClass = classes[i];
            }
    }
    

EDIT

There are a few shortcomings of the above approach,

  1. It iterates over all the classes accessible by your application code, looping through all of these classes is not a performant solution.

  2. Many famous SDKs will swizzle or dynamically extend your AppDelegate, because a lot of interesting things can be intercepted at this single place. This also means that your application may have more than one implementation of UIApplicationDelegate protocol and the code above may just pick any implementation of it, causing some serious issues.

As, Chris suggested in comments below, its much safer and performant to just use [[UIApplication sharedApplication].delegate class]. which should give you the exact AppDelegate implementation known to iOS application at the moment of calling this line of code.