LoginSignup
6
8

More than 3 years have passed since last update.

[iOS13] ASWebAuthenticationSession用いたOAuth認証の変更点

Last updated at Posted at 2019-08-21

はじめに

OAuth認証やASWebAuthenticationSession、などについてはここではふれません。
ASWebAuthenticationSession用いたOAuth認証をiOS12で実装しており、これからiOS13に対応する方法の一例を書きたいと思います。

UIApplication.sharedApplication.keyWindow; が iOS13 で DEPRECATED になってしまったので、別の方法に書き換えました。

変更点

  • ASWebAuthenticationSessionstart を呼び出す前に、 presentationContextProvider を設定しなければいけない

In macOS, and for iOS apps with a deployment target of iOS 13 or later, after you call start, the session instance stores a strong reference to itself. To avoid deallocation during the authentication process, the session keeps the reference until after it calls the completion handler.

For iOS apps with a deployment target earlier than iOS 13, your app must keep a strong reference to the session to prevent the system from deallocating the session while waiting for authentication to complete.

参照元

これにより、以下の書き換えが必要になります。

iOS12.m
self.webAuthenticationSession = [[ASWebAuthenticationSession alloc] initWithURL:[NSURL URLWithString:url] callbackURLScheme:nil completionHandler:^(NSURL *callbackURL, NSError *error) {
    // SessionToken の取得など
    self.webAuthenticationSession = nil;
}];
[self.webAuthenticationSession start];

iOS13.m
self.webAuthenticationSession = [[ASWebAuthenticationSession alloc] initWithURL:[NSURL URLWithString:url] callbackURLScheme:nil completionHandler:^(NSURL *callbackURL, NSError *error) {
    // SessionToken の取得など
    self.webAuthenticationSession = nil;
}];
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 130000
if (@available(iOS 13.0, *)) {
    self.webAuthenticationSession.presentationContextProvider = uiViewController; // uiViewControllerについては後で記載
}
#endif
[self.webAuthenticationSession start];

以下のように presentationContextProviderASWebAuthenticationPresentationContextProviding Protocol を実装したインスタンスを設定すればいいだけです。

self.webAuthenticationSession.presentationContextProvider = uiViewController;

例えば

HogeLoginViewController.h
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>

#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 130000

API_AVAILABLE(ios(13.0), macos(10.15))
@interface HogeLoginViewController : UIViewController <ASWebAuthenticationPresentationContextProviding>

@end
#endif
HogeLoginViewController.m
#import "HogeLoginViewController.h"

#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 130000

@implementation HogeLoginViewController {

}

...

- (ASPresentationAnchor)presentationAnchorForWebAuthenticationSession:(ASWebAuthenticationSession *)session {
    return view.window;
}
...

@end

#endif

問題点

これだと、認証システム基盤を作成するには、問題があります。
APIの引数にUI要素のものを渡し他場合、以下のような問題が出てくるからです。

  • Androidと共通基盤の場合、引数が異なる
  • 引数にUI要素なものを渡さないといけない?
  • Unityなどで利用する場合、どうするの?

解決策は簡単で、 UIViewController を使わないだけです。

解決策

HogeBridgeAPI.h
#import <Foundation/Foundation.h>

#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 130000

API_AVAILABLE(ios(13.0), macos(10.15))
@interface HogeBridgeAPI : NSObject <ASWebAuthenticationPresentationContextProviding>

@end
#endif
HogeBridgeAPI.m
#import "HogeBridgeAPI.h"

#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 130000

@implementation HogeBridgeAPI {

}

- (ASPresentationAnchor)presentationAnchorForWebAuthenticationSession:(ASWebAuthenticationSession *)session {
    for (UIScene *uiScene in UIApplication.sharedApplication.connectedScenes) {
        if (uiScene.activationState != UISceneActivationStateForegroundActive) {
            continue;
        }
        if ([uiScene isKindOfClass:UIWindowScene.class]) {
            UIWindowScene *uiWindowScene = (UIWindowScene *)uiScene;
            for (UIWindow *uiWindow in uiWindowScene.windows) {
                if(uiWindow.isKeyWindow){
                    return uiWindow;
                }
            }
        }
    }
    return nil;
}

@end
#endif

HogeBridgeAPIなるものを作成します。

for (UIScene *uiScene in UIApplication.sharedApplication.connectedScenes) {
    if (uiScene.activationState != UISceneActivationStateForegroundActive) {
        continue;
    }
    if ([uiScene isKindOfClass:UIWindowScene.class]) {
        UIWindowScene *uiWindowScene = (UIWindowScene *)uiScene;
        for (UIWindow *uiWindow in uiWindowScene.windows) {
            if(uiWindow.isKeyWindow){
                return uiWindow;
            }
        }
    }
}

presentationAnchorForWebAuthenticationSession の戻り値は、上記とすることで UIViewController を使わくても大丈夫です。

あとは、 コンストラクタなどで HogeBridgeAPI を生成

self.webAuthenticationSession.presentationContextProvider = self.bridgeAPI;

などしてあげれば解決します。

6
8
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
8