グーグルのAPIを使うときに欠かせないGoogle OAuthの作り方と使い方:Androidで動く携帯Javaアプリ作成入門(59)(3/3 ページ)
Gmail、Google Maps、YouTube、Google DriveなどをAPIとして活用する際に必要となるGoogle OAuthの作り方と、Androidアプリを例にした使い方を解説する。
アプリの実装
アプリのコードを説明します。
フィールド
まずはフィールドです。
private static final int REQUEST_ACCOUNT_CHOOSER = 1; private static final int REQUEST_AUTHORIZATION_FROM_DRIVE = 2; private static final int REQUEST_AUTHORIZATION_FROM_PLUS = 3; private GoogleAccountCredential mCredential; private Drive mDrive; private Plus mPlus;
主要なフィールドは上記6つです。うち3つはActivityを呼び出すリクエストコードです。認証画面を呼び出すリクエストコードが2つあるのは、認証画面でOKをタップされた際に、再度同一機能を呼び出すためです。詳細は後述します。
GoogleAccountCredentialはアカウント情報を保持します。DriveおよびPlusはサービスのAPIです。
気を付けなければならないのは、DriveもPlusもcom.google.android.gms.driveやcom.google.android.gms.plusではなくcom.google.api.services.driveとcom.google.api.services.plusをimportするということです。
onCreate()メソッド
続いてonCreate()メソッドです。
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initializeLogging(); showAccountChooser(); }
initializeLogging()は、ログ出力を画面に表示するViewの初期化を行うメソッドです。このログの画面出力はGoogleの他のサンプルから実装を流用し、改良を加えたものです。
showAccountChooser()はアカウントの選択ダイアログを表示するメソッド呼び出しです。
onPrepareOptionsMenu()メソッドとonOptionsItemSelected()メソッド
次にonPrepareOptionsMenu()メソッドとonOptionsItemSelected()メソッドです。
@Override public boolean onPrepareOptionsMenu(Menu menu) { boolean isSelectedAccount = mCredential != null && mCredential.getSelectedAccountName() != null; menu.getItem(0).setEnabled(!isSelectedAccount); menu.getItem(1).setEnabled(isSelectedAccount); menu.getItem(2).setEnabled(isSelectedAccount); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { int id = item.getItemId(); switch (id) { case R.id.action_oauth: Log.i(TAG, "--- Authentication ---"); showAccountChooser(); return true; case R.id.action_drive: Log.i(TAG, "--- List Drive files ---"); listDriveFiles(); return true; case R.id.action_plus: Log.i(TAG, "--- Show Plus user ---"); showPlusUser(); return true; } return super.onOptionsItemSelected(item); }
メニューは「OAuth」「Drive」「Plus」があります。「OAuth」はアカウント選択が行われていないなら有効に、「Drive」「Plus」はアカウント選択が行われていれば有効にします。
それぞれのメニューが選択された際に、showAccountChooser()メソッド、listDriveFiles()メソッド、showPlusUser()メソッドを呼び出します。
showAccountChooser()メソッド
次はshowAccountChooser()メソッドです。
@NonNull private GoogleAccountCredential makeCredential() { Collection<String> scopes = Arrays.asList( DriveScopes.DRIVE_READONLY, PlusScopes.USERINFO_PROFILE); return GoogleAccountCredential.usingOAuth2(getApplicationContext(), scopes); } private void showAccountChooser() { if (mCredential == null) { mCredential = makeCredential(); } startActivityForResult(mCredential.newChooseAccountIntent(), REQUEST_ACCOUNT_CHOOSER); }
makeCredential()メソッドでGoogleAccountCredentialを生成しています。生成する際にサービスのスコープを設定します。今回はDriveでは読み込み専用、Plusではプロフィール情報参照を設定しました。
生成したインスタンスを用いてアカウントの選択ダイアログを表示します。startActivityForResult()メソッドで呼び出し、結果を取得する必要があります。
onActivityResult()メソッド
次にonActivityResult()メソッドです。
@Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); switch (requestCode) { case REQUEST_ACCOUNT_CHOOSER: if (resultCode == RESULT_OK && data != null) { String accountName = data.getStringExtra(AccountManager.KEY_ACCOUNT_NAME); Log.i(TAG, "Account Name:" + accountName); if (accountName != null) { mCredential.setSelectedAccountName(accountName); } } break; case REQUEST_AUTHORIZATION_FROM_DRIVE: case REQUEST_AUTHORIZATION_FROM_PLUS: if (resultCode == RESULT_OK) { if (requestCode == REQUEST_AUTHORIZATION_FROM_DRIVE) { listDriveFiles(); } else if (requestCode == REQUEST_AUTHORIZATION_FROM_PLUS) { showPlusUser(); } } break; } }
REQUEST_ACCOUNT_CHOOSERはアカウントの選択ダイアログから戻ってきたケースです。アカウントの選択ダイアログでアカウントが選択されたら、Intentから選択されたアカウント名を取得し、GoogleAccountCredential#setSelectedAccountName()メソッドで設定します。
REQUEST_AUTHORIZATION_FROM_DRIVEとREQUEST_AUTHORIZATION_FROM_PLUSは認証画面から戻ってきたケースです。認証画面はサービスAPIを呼び出した際に例外経由で表示するため、ユーザーが認証画面でOKをタップした場合、再度同一のサービスAPIを呼び出すのがユーザーフレンドリーな動作です。ここでは2パターンしかないので簡単に実装していますが、実際には呼び出し条件などをフィールドに保持しておく必要があるでしょう。
サービスの呼び出し用メソッド
次はサービスの呼び出し用メソッドです。
private void listDriveFiles() { if (mDrive == null) { mDrive = buildDrive(); } new ListDriveFilesTask().execute(); } private void showPlusUser() { if (mPlus == null) { mPlus = buildPlus(); } new ShowPlusUserTask().execute(); } @NonNull private Drive buildDrive() { HttpTransport transport = AndroidHttp.newCompatibleTransport(); GsonFactory factory = new GsonFactory(); return new Drive.Builder(transport, factory, mCredential).build(); } @NonNull private Plus buildPlus() { HttpTransport transport = AndroidHttp.newCompatibleTransport(); GsonFactory factory = new GsonFactory(); return new Plus.Builder(transport, factory, mCredential).build(); }
DriveもPlusも同じパターンです。Builderでインスタンスを作る際に、HttpTransport、GsonFactory、GoogleAccountCredentialのインスタンスを渡します。実際のAPI呼び出しはAsyncTaskで非同期に行います。
AsyncTaskのDrive APIを利用する実装
次はAsyncTaskのDrive APIを利用する実装の抜粋です。
@Override protected Void doInBackground(Void... unused) { mList = new ArrayList<>(); try { Drive.Files.List request = mDrive.files().list(); request.setQ("mimeType = 'application/vnd.google-apps.document'"); do { FileList files = request.execute(); mList.addAll(files.getItems()); request.setPageToken(files.getNextPageToken()); } while (request.getPageToken() != null && request.getPageToken().length() > 0); } catch (UserRecoverableAuthIOException e) { mIntent = e.getIntent(); } catch (IOException e) { Log.e(TAG, e.getMessage(), e); } return null; }
DriveのファイルリストはDrive.Files.List#setQ()メソッドでクエリを設定して取得します。今回は"mimeType = 'application/vnd.google-apps.document'"というクエリでGoogle Docsファイルをリストアップしています。サポートするMIME/Typeは「Supported MIME Types | Drive REST API | Google Developers」を、クエリの文法は「Search for Files | Drive REST API | Google Developers」を参照してください。
全てのファイルをリストアップするために、ページトークンという情報を持ち回りながらループさせています。この繰り返しと終了判定はパターンとして覚えてください。
重要なのはUserRecoverableAuthIOExceptionが発生した際の動作です。
この例外は、ユーザーが認証していない場合に発生、つまり初回は必ず発生する例外です。つまり、例外の情報は重要ではなく、この例外から取得可能なIntentが重要になります。ここではフィールドに保存して、後で利用するようにしています。
AsyncTaskのonPostExecute()メソッド
@Override protected void onPostExecute(Void unused) { if (mIntent != null) { startActivityForResult(mIntent, REQUEST_AUTHORIZATION_FROM_DRIVE); } else { for (File file : mList) { Log.d(TAG, file.getTitle() + " " + file.getOwnerNames() + ""); } } }
AsyncTaskのonPostExecute()メソッドでは、もしUserRecoverableAuthIOExceptionが発生してIntentが保存されているならば、そのIntentを用いて認証画面を表示し、そうでなければファイル情報を出力するようにしています。ファイル情報としてここではタイトルとオーナー名を取得しています。
AsyncTaskでGoogle+ APIを利用する実装
最後にAsyncTaskでGoogle+ APIを利用する実装の抜粋です。
@Override protected Void doInBackground(Void... unused) { try { mPerson = mPlus.people().get("me").execute(); } catch (UserRecoverableAuthIOException e) { mIntent = e.getIntent(); } catch (IOException e) { Log.e(TAG, e.getMessage(), e); } return null; }
自身のプロフィール情報を取得するにはPlus.People#get()メソッドに”me”を渡し、得られたPlus.People.Get#execute()メソッドを呼び出します。Driveと同様、初回実行時であればUserRecoverableAuthIOExceptionが発生するのでIntentを保存しておきます。
@Override protected void onPostExecute(Void unused) { if (mIntent != null) { startActivityForResult(mIntent, REQUEST_AUTHORIZATION_FROM_PLUS); } else { Log.d(TAG, "Display Name:" + mPerson.getDisplayName()); Log.d(TAG, "Birthday:" + mPerson.getBirthday()); Log.d(TAG, "Gender:" + mPerson.getGender()); Log.d(TAG, "toString():" + mPerson.toString()); } }
onPostExecute()メソッドでは認証の必要があれば認証画面を表示し、なければプロフィール情報を取得しています。ここでは表示名、誕生日、性別、toString()によるPersonのJSON表現です。
無料で利用できるリクエスト数制限に注意
今回はGoogle DriveとGoogle+で提供されるGoogle APIを、Google OAuthで認証した後アプリから利用しました。今回見たサービスはどちらもサービスAPI以外はほぼ同様の使い方ができたことが確認できたと思います。ぜひ、他のサービスの利用もチャレンジしてみてください。
なお、Google APIは無料で利用できるリクエスト数に制限があります。Google Driveなら1日当たり10億リクエスト、ユーザーごとでは1秒当たり10リクエスト、Google+なら1日当たり1万リクエスト、ユーザーごとでは1秒当たり5リクエストです。この制限はGoogle Developer Consoleから調べられるので、利用したいサービスの制限を調べて、アプリの設計に反映するようにしてください。
Copyright © ITmedia, Inc. All Rights Reserved.
関連記事
「OAuth」の基本動作を知る
いまWebの世界では、さまざまなWebサービスが提供するプラットフォームと、サードパーティが提供するアプリケーションがAPIを中心に結び付き、一種の「APIエコノミー」を形成しています。この連載では、そこで重要な役割を果たす「デジタル・アイデンティティ」について理解を深めていきます。(編集部)RFCとなった「OAuth 2.0」――その要点は?
いまWebの世界では、さまざまなWebサービスが提供するプラットフォームと、サー ドパーティが提供するアプリケーションがAPIを中心に結び付き、一種の「APIエコノミー」を形成しています。この連載では、そこで重要な役割を果たす「デジタル・アイデンティティ」について理解を深めていきます。OAuthを悪用したアカウント乗っ取りに注意喚起、IPA
JavaでTwitterをOAuth認証して使えるTwitter4Jとは
数年前に比べケータイ向けサービス構築を支援するフレームワークやノウハウがたまってきて、そして無料または、格安でサービスを公開できる仕組み(クラウドやVPSなど)も普及している今こそ、ケータイ向けサービス開発を始めるチャンスではないでしょうかOAuthでバーコード情報をTwitterに投稿するiPhoneアプリ作成
iPad/iPhone VS Androidに戸惑っているWebデザイナ/開発者のために、Web技術でネイティブアプリを作れるオープンソースの開発ツールを紹介し、その利点や使い方を連載で解説します- OAuth 2.0を使うソーシャルなAndroidアプリの作り方
OAuth 2.0のソーシャルなWeb APIを使った、Androidで動く簡単なネイティブ・アプリケーションの作り方を解説します - OAuth 2.0でWebサービスの利用方法はどう変わるか
OAuthの現状と1.0の問題点、2.0での特徴などを解説し、2.0の例としてFacebookのAPIの利用例を紹介します