はじめに
OAuth認証やASWebAuthenticationSession、などについてはここではふれません。
ASWebAuthenticationSession用いたOAuth認証をiOS12で実装しており、これからiOS13に対応する方法の一例を書きたいと思います。
※ UIApplication.sharedApplication.keyWindow;
が iOS13 で DEPRECATED になってしまったので、別の方法に書き換えました。
変更点
-
ASWebAuthenticationSession
のstart
を呼び出す前に、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.
これにより、以下の書き換えが必要になります。
self.webAuthenticationSession = [[ASWebAuthenticationSession alloc] initWithURL:[NSURL URLWithString:url] callbackURLScheme:nil completionHandler:^(NSURL *callbackURL, NSError *error) {
// SessionToken の取得など
self.webAuthenticationSession = nil;
}];
[self.webAuthenticationSession start];
↓
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];
以下のように presentationContextProvider
に ASWebAuthenticationPresentationContextProviding
Protocol を実装したインスタンスを設定すればいいだけです。
self.webAuthenticationSession.presentationContextProvider = uiViewController;
例えば
# 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
# 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
を使わないだけです。
解決策
# 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
# 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;
などしてあげれば解決します。