コンテンツ開発事業部、Unityエンジニアの平井です。
普段はゲームアプリのクライアント側をUnityで開発しております。
今回は直近のプロジェクトでGoogle Calendar API
を使用した時の話を書こうかと思います。
この記事を書こうと思った経緯
新規開発のゲームアプリにてGoogleカレンダーとの連携を行い、
アプリ側で用意したカレンダーデータとユーザーのカレンダーデータをアプリ内で確認したい、という要件でした。
会社内でもGoogleカレンダーの連携の実装をした人がいなかったので、まず実装方法の調査から行いました。
が、Unityで使用している記事が見つからなかったので、自分で書いてやろうと思った次第です。
ネイティブアプリで実装している記事は見つかったので、プラグインを活用して実装を行うことにしました。
Unityとプラグインの繋ぎ込み、外部ブラウザ側の設定でハマったところを中心に解説出来ればと思います。
今後Unity上でGoogleカレンダー連携を実装する人の参考になれれば幸いです。
前提
アプリ側で用意したカレンダーデータとユーザーのカレンダーデータの結合はサーバー側にお願いしました。
今回アプリ側で必要な処理としては、
1.OAuth認証でGoogleアカウントにサインインする
2.アカウントの認証情報をサーバーに送る
の2点になります。
Google Cloud Platformの設定
1. Google Cloud Platform
にて新しいプロジェクトを作成する
Google Calendar API
を使用するにはGoogle Cloud Platformのプロジェクトが必要になります。
※GoogleAPIs
、GoogleDeveloperConsole
等色んな名前がありますが、基本的には同じサービスを指しているようです。
2. ライブラリからGoogle Calendar API
を有効にする
今回はGoogle Calendar API
のみですが、他のAPIも使用する場合同じように有効にする必要があります。
3. 認証情報からOAuth2.0クライアントID
を作成する
Android、iOS、ウェブアプリケーション用のものをそれぞれ作成します。
開発(デバッグ)と本番(リリース)でPackageNameやBundleIDが変わってくると思うので、それぞれクライアントIDを作成する必要があります。
※今回のプロジェクトではそもそも開発と本番でプロジェクト自体を分けたので、それぞれ一つしか用意していません。
Androidの注意点として、keystore
のフィンガープリントが必要になります。
また、デバッグ用のkeystore
はバイナリをビルドするPCのkeystore
を参照するようにして下さい。
バイナリで使われているkeystore
と指定したkeystore
が違うとOAuth認証時にエラーが出ます。
4. OAuth同意画面の設定
UserTypeは外部で作成します。
アプリケーション名、アプリのロゴ、サポートメール、[アプリケーション ホームページ] リンク、[アプリケーション プライバシー ポリシー] リンクの設定をします
(開発用であればなくても問題ないですが、本番用では記述されていないと承認を受けることが出来ません)
■スコープ
GoogleAPIのスコープ
にカレンダー用スコープを追加します。
下記のページにカレンダーで使用するスコープの一覧があります。
https://developers.google.com/calendar/auth?hl=ja
今回は読み取りと書き込み両方を行うつもりでしたので、https://www.googleapis.com/auth/calendar
を指定しました。
後述しますが、OAuth認証の同意画面はGoogleからの承認を受ける必要がありその際に定義したスコープの正当性を確認しているようです。
承認が受けられない可能性がありますので、正しいスコープを選択した方が良いかと思います。
(読み取りしか行わないのならcalendar.readonly
にする等)
■承認済みドメイン
リンクで指定しているURIはこちらに記述したドメインでないと設定できません。
また、Webクライアントのコールバック設定などでURIを指定している場合もこちらにドメインを記述しておかないと設定できません。
プラグインとの繋ぎ込み
今回プラグイン側にお願いしたのはOAuth認証の処理と認証完了後に発行されるAuthCode
をUnity側に返す処理です。
プラグイン側での注意点をかいつまんで説明していきます。
■導入準備
Androidはgradleに下記を追加しました
implementation 'com.android.support:design:28.0.0' implementation 'com.android.support:support-v4:28.0.0' implementation 'com.google.android.gms:play-services-auth:16.0.0' implementation('com.google.api-client:google-api-client-android:1.22.0') { exclude group: 'org.apache.httpcomponents' } implementation('com.google.apis:google-api-services-calendar:v3-rev214-1.22.0') { exclude group: 'org.apache.httpcomponents' }
iOSは下記フレームワークを追加しています
GoogleSignIn.bundle GoogleSignIn.framework GoogleSignInDependencies.framework
1. サインインの処理の初期化の際にスコープの設定とクライアントIDの設定を行う
■Android kotlin
val gso = GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN) .requestScopes(Scope(SCOPES[0])) .requestIdToken(clientId) .requestEmail() .requestServerAuthCode(clientId, true) .build()
■iOS Objective-C
- (void)init:(NSString*_Nonnull)clientID server:(NSString*_Nonnull)serverClientID { [GIDSignIn sharedInstance].clientID = clientID; [GIDSignIn sharedInstance].serverClientID = serverClientID; [GIDSignIn sharedInstance].scopes = @[@"https://www.googleapis.com/auth/calendar"]; [GIDSignIn sharedInstance].shouldFetchBasicProfile = NO; }
■スコープ
OAuth同意画面の設定で選択したスコープと同じものを設定するようにしましょう。
■クライアントID
AndroidではウェブアプリケーションのクライアントIDを、
iOSでは.clientID
にiOSのクライアントID、.serverClientID
にウェブアプリケーションのクライアントIDを、それぞれ渡す必要があります。
注意点として、AndroidではAndroidのクライアントIDではなく、ウェブアプリケーションのクライアントIDでないとサインイン時にエラーが発生します。
2. サインイン完了後、AuthCode
を取得する
当初はアクセストークンとリフレッシュトークンをサーバーに渡そうと思っていましたが、
両OSともリフレッシュトークンを取得するAPIが用意されていませんでしたので、
serverAuthCode
を渡してサーバー側でトークンを発行する形にしました。
なお、serverAuthCode
自体は数分で有効期限が切れるようなので、取得後すぐに送らないと発行できない可能性があります。
■Android kotlin
val authcode = GoogleSignInAccount?.getServerAuthCode()!!
■iOS Objective-C
NSDictionary *dict = @{@"serverAuthCode": (GIDGoogleUser *).serverAuthCode};
3. iOSで処理するためのコールバックを設定する
info.plistの「URL Types」に以下2点を追加してください。
CFBundleURLSchemes [REVERSED_CLIENT_ID]
CFBundleURLSchemes [BUNDLE_ID]
※REVERSED_CLIENT_IDはGoogle Cloud Platform > 認証情報
のiOSクライアント内「iOSのURLスキーム」で設定されているものです。
正しく設定出来ていればinfo.plistが下の画像のようになります。
実機確認
ここまで行えれば開発用では動作の確認が行えます。
Androidは前述したようにビルドするPCには気を付けましょう。
クライアントIDを作成する時に指定したKeyStore
を持つPCでビルドしないとAPI実行時にエラー(エラーコード:12500)が返ってきます。
本番用の設定
これ以降の設定はStoreで公開する時に必要な設定になります。
Storeでの公開を行わない場合は無視して下さい。
1. 本番用のOAuth2.0クライアントID
を作成する
BundleIDやPackageNameが開発と同じ場合は不要です。
Androidは本番用のkeystore
のフィンガープリントを用意して下さい。
クライアントIDが作成出来たらpluginに渡すクライアントIDを本番用に変更します。
2.OAuth同意画面の承認
OAuth同意画面の承認を受けていない場合、iOSでのサインイン時に下記画面が出ます。
この画面を表示させないために承認は受けましょう。
開発で各項目を入力していなかった場合、承認が受けられないので設定して下さい。
問題なければ画面下の方の「確認のため送信」ボタンを押すと送信画面が出ます。
スコープの理由と連絡先メールアドレスを記載してさらに送信を押すと申請が行えます。
(例で書いてあるのと同じような感じで書けば問題ないかと思います)
この承認は完了するまで1週間程掛かる可能性があります。
また、何度かメールで質問が来たり、実際に連携している様子を動画で送る必要もありますので、事前に受けておきましょう。
※一度送信後、内容を変更した場合は、再度送信する必要があります。
※送信後は保存ボタンが押せなくなるため、一時保存を行う場合も再度送信しないと保存できません。
3. Firebase
とGoogle Play Console
のリンク
リリースバイナリの場合、リンクを行っていないと「ApiException: 10」が出ます。
Google Cloud Platform
プロジェクトとリンクしているFirebase
プロジェクトが作られていない場合は作成しましょう。
設定 > 全般 > マイアプリ
にアプリが設定されていない場合は追加して下さい。
設定 > 統合 > GooglePlay
にてリンクするGoogle Play Console
とリンクを行います。
※Google Play Console
のオーナーアカウントでないとリンクは設定できません
画像のようにステータスがリンク済みになっていればリンクされています。
まとめ
自分がはまったところを中心に解説させて頂きました。
GoogleAPIは公式ドキュメントはありますが、実装の記事が少ないので手探りの状態で開発してました。
必要な箇所をまとめられたかと思うので、参考にして頂ければ幸いです。