Question

In my app, I have implemented a private method in my AppDelegate to override the default openURL: method in order to open links inside my app within UIWebView. But now I need the default functionalities in place too.

Here's what I did:

@implementation UIApplication (Private)

- (BOOL)customOpenURL:(NSURL*)url
{ 
    AppDelegate *MyWatcher = (AppDelegate *)[[UIApplication sharedApplication] delegate];

    if (MyWatcher.currentViewController) {
        [MyWatcher.currentViewController handleURL:url];
        return YES;
    }
    return NO;
}

@end

- (void)applicationDidBecomeActive:(UIApplication *)application {  
    Method customOpenUrl = class_getInstanceMethod([UIApplication class], @selector(customOpenURL:));
    Method openUrl = class_getInstanceMethod([UIApplication class], @selector(openURL:));

   method_exchangeImplementations(openUrl, customOpenUrl);  
}

I also implemented handleURL: in my class where the custom open URL handling was needed. However, this is hindering my other class in which I just want to do a simple open of an iTunes link in iTunes. So what I don't know how to achieve is how to use the original openURL: in place of customOpenURL:.

Was it helpful?

Solution

You can just subclass UIApplication and override openURL: directly. Be sure to change the principle class in your Info.plist to use your UIApplication subclass.

Example:

@interface ECApplication : UIApplication

@end

@implementation ECApplication

- (BOOL)openURL:(NSURL*)url
{

    AppDelegate *MyWatcher = (AppDelegate *)[[UIApplication sharedApplication] delegate];

    if (MyWatcher.currentViewController) {
        [MyWatcher.currentViewController handleURL:url];
        return YES;
    }
    return NO;
}

@end

Then, in your Info.plist file, look for the Principle Class key, and change the value to ECApplication (or whatever you name your subclass).

OTHER TIPS

You can set the original implementation to some other method and then just call it:

@implementation UIApplication (Private)
- (BOOL)originalOpenURL:(NSURL*)url 
{
     return NO;
}

- (BOOL)customOpenURL:(NSURL*)url
{
     if (/* some condition */)
     {
        // your code
     }
     else
     {
        return [self originalOpenURL: url];
     }
}

@end

- (void)applicationDidBecomeActive:(UIApplication *)application {  
     Method customOpenUrl = class_getInstanceMethod([UIApplication class], @selector(customOpenURL:));
     Method openUrl = class_getInstanceMethod([UIApplication class], @selector(openURL:));
     Method originalOpenUrl = class_getInstanceMethod([UIApplication class], @selector(originalOpenURL:));

     method_exchangeImplementations(openUrl, originalOpenUrl); 
     method_exchangeImplementations(openUrl, customOpenUrl);  
}

Note: This is just a solution giving direct answer to your question. The clearer approach to this problem is the one suggested by @edc1591. You can access original openURL: with [super openURL:url].

The approach pointed out by Krizz works on the first app launch only, if you happen to open an URL that redirects you to another App (i.e.: Facebook app), it messes with the implementations when your app is resumed. Adding a flag to make sure the method_exchangeImplementations is called only on the first app launch seems to work.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top