iOS 7 で自身のカスタムスキームを呼び出した時にアプリケーションイベントが異なる

# 問題
iOS 7 では、自身のカスタムスキームを呼び出した時、
`UIApplicationWillResignActiveNotification` / ` UIApplicationDidBecomeActiveNotification` が呼び出されない・通知されない。

ルーティングを実装して遷移するために呼び出したり、WebView で認証させてる場合に実装によっては影響することがあるのではなかろうかと思ってます。

## 自身を呼び出す (iOS 7)
```
-[AppDelegate application:openURL:sourceApplication:annotation:] [Line 28] url: openurl://, app: (null), state: 0, annotation: (null)
```

## 自身を呼び出す (iOS 8 later)
```
-[AppDelegate applicationWillResignActive:] [Line 36] 
-[AppDelegate application:openURL:sourceApplication:annotation:] [Line 28] url: openurl://, app: example.OpenURLTest, state: 1, annotation: (null)
-[AppDelegate applicationDidBecomeActive:] [Line 52] 
```

## 他アプリケーションが呼び出す (iOS 7)
```
-[AppDelegate applicationWillEnterForeground:] [Line 47]
-[AppDelegate application:openURL:sourceApplication:annotation:] [Line 28] url: openurl://, app: com.apple.mobilesafari, state: 1, annotation: (null)
-[AppDelegate applicationDidBecomeActive:] [Line 52] 
```

## 他アプリケーションが呼び出す (iOS 8 later)
```
-[AppDelegate applicationWillEnterForeground:] [Line 47]
-[AppDelegate application:openURL:sourceApplication:annotation:] [Line 28] url: openurl://, app: com.apple.mobilesafari, state: 1, annotation: (null)
-[AppDelegate applicationDidBecomeActive:] [Line 52] 

```



# 対応
Method Swizzling で、iOS 8 以降と同じ処理になるよう `UIApplicationWillResignActiveNotification` / ` UIApplicationDidBecomeActiveNotification` を補完してみました。

```objc:AppDelegate.m
+ (void)initialize
{
    [super initialize];

    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        if (NSOrderedAscending == [[UIDevice currentDevice].systemVersion compare:@"8.0"
                                                                          options:NSNumericSearch]) {
            Method fromMethod = class_getInstanceMethod([self class],
                                                        @selector(application:openURL:sourceApplication:annotation:));
            Method toMethod = class_getInstanceMethod([self class],
                                                      @selector(iOS7_application:openURL:sourceApplication:annotation:));
            method_exchangeImplementations(fromMethod, toMethod);
        }
    });
}

/**
 iOS 7 では自身のスキームを呼び出した際に UIApplicationWillResignActiveNotification / UIApplicationDidBecomeActiveNotification が呼び出されないため補完する
 */
- (BOOL)iOS7_application:(UIApplication *)application
                 openURL:(NSURL *)url
       sourceApplication:(NSString *)sourceApplication
              annotation:(id)annotation
{
    BOOL result = NO;
    BOOL oneself = NO;
    NSString *bundleIdentifier = sourceApplication;
    
    // 自身のスキーム呼び出し時、sourceApplication が nil になっている
    if (!sourceApplication || 0 == [sourceApplication length]) {
        oneself = YES;
        bundleIdentifier = [NSBundle mainBundle].bundleIdentifier;
    }
    
    // UIApplicationWillResignActiveNotification
    if(oneself) {
        // perform delegate
        if([self respondsToSelector:@selector(applicationWillResignActive:)]) {
            [self applicationWillResignActive:application];
        }
        
        // post notification
        [[NSNotificationCenter defaultCenter] postNotificationName:UIApplicationWillResignActiveNotification
                                                            object:nil];
    }
    
    // perform original
    result = [self iOS7_application:application
                            openURL:url
                  sourceApplication:bundleIdentifier
                         annotation:annotation];
    
    // UIApplicationDidBecomeActiveNotification
    if (oneself) {
        // perform delegate
        if([self respondsToSelector:@selector(applicationDidBecomeActive:)]) {
            [self applicationDidBecomeActive:application];
        }
        
        // post notification
        [[NSNotificationCenter defaultCenter] postNotificationName:UIApplicationDidBecomeActiveNotification
                                                            object:nil];
    }
    
    return result;
}
```


# 課題
## application.applicationState が iOS 8 以降とは異なる

| iOS バージョン | applicationState | 
|:-----------|:------------|
| iOS 7       |        UIApplicationStateActive | 
| iOS 8 later     |      UIApplicationStateInactive |  

自身を呼び出した時なので気にしなくていいはず…。