連載
» 2015年09月15日 05時00分 公開

グーグルのAPIを使うときに欠かせないGoogle OAuthの作り方と使い方Androidで動く携帯Javaアプリ作成入門(59)(3/3 ページ)

[緒方聡,株式会社ゆめみ]
前のページへ 1|2|3       

アプリの実装

 アプリのコードを説明します。

フィールド

 まずはフィールドです。

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から調べられるので、利用したいサービスの制限を調べて、アプリの設計に反映するようにしてください。

前のページへ 1|2|3       

Copyright © ITmedia, Inc. All Rights Reserved.

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。