はじめに
iOSにおいて、GoogleのOAuth認証は Google Sign-In for iOS というSDKを用いれば簡単に実現できます。
ただ、認証情報としてMobileSafariのキャッシュを用いている関係で状態管理が複雑なうえに、公式のドキュメントに書かれている情報は手順くらいで、「こういう時にこういう値が返る」などの情報がありません。
そこで本記事では、「こういう仕様にしたいんだけど、どうすれば良いんだろう」「外部ブラウザに引っ張られないで、一貫したUXにしたい」などという場合に考えられるケースと、その解決策を書いていきます。
主にセキュリティ面で、Googleが推奨している実装にはなっていない可能性があります。
また、サンプルコードはSwiftではなくObjective-Cで書いています。
ご了承ください。
ケース1: AppDelegate.m 以外の箇所にGIDSignInDelegateのメソッドが書きたい
諦めましょう。まずコンパイラに怒られます。
詳しくはこちらをご参照ください。
で、例えばViewControllerでサインイン後の処理がしたい場合は、下記のようにGIDSignInDelegateのメソッドからNotificationを飛ばすのが良いでしょう。
(@"MyNotification" などは定数化してあげましょう)
- (void)signIn:(GIDSignIn *)signIn didSignInForUser:(GIDGoogleUser *)user withError:(NSError *)error
{
// 取得したユーザーのプロフィールや認証情報など、通知を受け取る側に渡す値を生成する
NSDictionary * info = @{
@"email": user.profile.email,
@"error": error
};
// Notificationを飛ばす
NSNotification * n = [NSNotification notificationWithName:@"MyNotification" object:self userInfo:info];
[[NSNotificationCenter defaultCenter] postNotification:n];
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
// Notificationを登録する
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(foo:) name:@"MyNotification" object:nil];
}
- (void)viewWillDisappear:(BOOL)animated
{
// Notificationの登録を解除する
[[NSNotificationCenter defaultCenter removeObserver:self name:@"MyNotification" object:nil];
[super viewWillDisappear:animated];
}
- (void)foo:(NSNotification *)n
{
// サインインが実行された後、Notificationを受け取る処理
// n.userInfo で通知と一緒に渡された値を取り出すことができる
[n.userInfo objectForKey:@"email"];
}
ケース2: 余計な権限を要求してくる
Google Sign-Inは、デフォルトで「メールアドレスの表示」「ユーザーのプロフィール情報の表示」の2つの権限を要求してきます。
スコープの情報はこちらの公式ドキュメントのprofileとemailです。
GIDSignInインスタンスのプロパティshouldFetchBasicProfile
をNOに設定すると、これらの権限の要求がなくなります。
YouTube Data APIを使用するためYouTubeのチャンネルの情報しか使用しないなど、これらのスコープが必要ないケースが出てくると思います。
以下にGoogleアカウントに紐づいているYouTubeの情報しか権限を要求させないための実装を示します。
GIDSignIn * signIn = [GIDSignIn sharedInstance];
signIn.scopes = @[
@"https://www.googleapis.com/auth/youtube.upload",
@"https://www.googleapis.com/auth/youtube.readonly"
];
signIn.shouldFetchBasicProfile = NO;
[signIn signIn];
おわりに
・・・もっといろいろあった気がしますが、今思い出せるのはこれくらいです。
何かありましたら随時更新していきます。まだまだ検証したいところもありますね。