0

Environment

  • xcode 6.4
  • Objective-C
  • iOS Application

Use-case

  • The product is a SDK integrated in 3rd party apps
  • No Access to the source-code of the application using the SDK
  • Modules in the SDK should retrieve the URL Used to start the application ( if any )

Problem at hand

Having the above mentioned use-case in mind, how can I retrieve the URL used to start the app ( if any ), OR, to intercept the 'openUrl' method implemented by the Applications AppDelegate ?

NadavRub
  • 2,520
  • 27
  • 63

2 Answers2

1

You can create your own class that implements the UIApplicationDelegate protocol. In your SDK's start-up code (which the user will have to call early in something like application:willFinishLaunchingWithOptions:), instantiate it, and replace the main UIApplication object's delegate with your custom object.

Your custom object is now the application delegate instead of theirs.

Prior to setting the UIApplication object's delegate, set your class's delegate to the current UIApplication delegate so that you can forward any messages back to their application delegate object.

No swizzling required.

Marcus Adams
  • 53,009
  • 9
  • 91
  • 143
  • This sounds horrible to me for some reason, but it'd work. +1 – mattsven Aug 11 '15 at 19:13
  • I was trying something similar ( swizzeling the setDelegate method and injecting my delegate instade of the apps ), however, for some apps it work and with other apps it simply make it crash – NadavRub Aug 12 '15 at 05:41
1

This is actually quite simple, having the SDK linked as a DyLib and the main object initialized in a "attribute((constructor))" section, the following is what needed:

IMP g_originalSetDelegate           = nil;
IMP g_originalOpenUrl               = nil;

BOOL swizzle_openUrl(id self, SEL _cmd, UIApplication* application, NSURL* url, NSString* sourceApplication, id annotation) {
    // TBD: Do your magic
    return ((BOOL(*)(id,SEL,UIApplication*,NSURL*,NSString*,id))g_originalOpenUrl)(self, _cmd, application, url, sourceApplication, annotation);
}

void swizzle_setDelegate(id self, SEL _cmd, id delegate) {
    ((void(*)(id,SEL,id))g_originalSetDelegate)(self, _cmd, delegate);// Call the original method

    auto method  = class_getInstanceMethod([delegate class], @selector(application:openURL:sourceApplication:annotation:));
    g_originalOpenUrl  = method_getImplementation(method);
    method_setImplementation(method, (IMP)swizzle_openUrl);
}

-(id)init {
    auto method  = class_getInstanceMethod([UIApplication class], @selector(setDelegate:));
    g_originalSetDelegate = method_getImplementation(method);
    method_setImplementation(method, (IMP)swizzle_setDelegate);

    ...
}
NadavRub
  • 2,520
  • 27
  • 63