How to dynamically change the openURL implementation in my app?

倖福魔咒の 提交于 2019-12-08 01:37:06

问题


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:.


回答1:


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).




回答2:


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].




回答3:


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.



来源:https://stackoverflow.com/questions/10157543/how-to-dynamically-change-the-openurl-implementation-in-my-app

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!