端末のアカウントでスプレッドシートにアクセスする

# こんななんでもないことで丸2日潰れた。いやー大変だった・・。

GoogleスプレッドをAPI経由で操作する方法は、ぐぐればゴマンと記事がひっかかるが、どれもこれもほとんど setUserCredentials でユーザ名、パスワードを設定してアクセスしている。探せばOAuth認証を用いたコードもあるが、今回はAndroid端末に設定してるアカウントでユーザ、パスを入力せずともアクセスできるにはどうしたらいいか、が知りたかった。
でもこれがなかなか見つからない。見つかっても、実は動かないという記事ばっかりだった。GoogleAPIはよくバージョンアップで動かなくなるので、記事が古いという理由もあるかもしれないが・・。

そこで試行錯誤の末、ようやくできるようになったので、重要な点だけ先にまとめておく。

  • AccountManager.getAuthToken の authTokenTypeは"wise"
  • ACCOUNT_MANAGER、GET_ACCOUNTS、INTERNET、USE_CREDENTIALS のPermissionを追加
  • AccountManagerFuture.getString(AccountManager.KEY_AUTHTOKEN) で取得したトークンをSpreadsheetService.setUserTokenにセット

最後は特に重要で、setAuthSubToken では上手く動かない。setHeader("Authorization", "Bearer " + token) てのもダメだった。

コード片も載せておく(エラー処理とかは全くないのでそのままコピペすると酷いことなる

final AccountManager am = AccountManager.get(getApplication());
Account[] accounts = am.getAccountsByType("com.google");

for(Account account : accounts)
{
    String tokenType = "wise";
    AccountManagerFuture<Bundle> amf = am.getAuthToken(
        account,
        tokenType,
        null,
        MainActivity.this,
        null,
        null
    );

    Bundle bundle = amf.getResult();
    if( bundle.containsKey(AccountManager.KEY_INTENT) )
    {   // 認証が必要な場合(認証していいかどうか画面が表示される)
        Intent intent = bundle.getParcelable(AccountManager.KEY_INTENT);
        int flags = intent.getFlags();
        flags &= ~Intent.FLAG_ACTIVITY_NEW_TASK;
        intent.setFlags(flags);
        startActivityForResult(intent, 0);
    }
    else
    {   // 認証用トークン取得
        String token = bundle.getString(AccountManager.KEY_AUTHTOKEN);

        String applicationName = "パッケージ名-アプリ名-バージョン"; // ex: "jp.example-Test-1"
        SpreadsheetService service = new SpreadsheetService(applicationName);
        service.setUserToken(token);
        /*
        try {
            // こっちはID/PWの認証
            service.setUserCredentials(username, password);
        } catch (AuthenticationException e1) {
            e1.printStackTrace();
        }
        */

        // 指定したKEYのスプレッドシート取得
        String sheetKey = "xxx";
        URL entryUrl = new URL("http://spreadsheets.google.com/feeds/spreadsheets/" + sheetKey);
        spreadsheetEntry = service.getEntry(entryUrl, SpreadsheetEntry.class);
        :
        : あとはやりたいように・・
        :
    }
}


非常に参考になった記事を以下にリストアップしておく(ただ、私の環境では上手く動かなかったor想定の動作をするプログラムじゃなかった)