Android

Google Drive REST API v3 for Android完全ガイド

簡単にGoogle DriveにアクセスできたGoogle Drive Android APIがdeprecatedとなり、2019年12月6日には接続が出来なくなります

代わりにGoogle Drive REST APIへの変更が案内されています。

 

(https://developers.google.com/drive/android/deprecation)

 

この記事では、現在最新のGoogle Drive REST API v3 をAndroidに実装する手順を丁寧に解説していきます。

 

1. 開発コーンソールでGoogle Drive APIを有効化

Google開発コンソールにログインをして、Google Drive APIを有効化します。
まだプロジェクトが1つも無い場合は、作成してください。
https://console.developers.google.com



 

2. OAuthクライアントIDの作成

Google Driveにアクセスするためのアカウントを作成します。

左側のメニューから「認証情報」を選択し、「認証情報を作成」>「OAuthクライアントID」を選択。

アプリケーションの種類は「Android」、名前は任意、最後のパッケージ名は、AndroidManifest.xmlに記述しているパッケージ名を入れます。

「署名証明書フィンガープリント」は、デバッグ環境用に発行する場合は
~/.android/debug.keystore
のフィンガープリントを発行し、リリースのタイミングで、リリース用keystoreのフィンガープリントに差し替えてください。

ただ、この画面に書いてあるコマンドをそのまま打つと文字化けしたフィンガープリントが表示されるので、次のコマンドを打つようにします。

最後の -v を忘れるとSHA-256のフィンガープリントだけ表示される(必要なのはSHA-1)ので、忘れないように。

keytool -list -keystore [keystoreへのパス] -v

 

3. OAuth同意画面の作成

OAuthへの同意画面が無いと、ログインが100回に制限されるので作成します。


諸々入力しつつ、スクロールをしていって「スコープを追加」をクリック。

「../auth/drive」を探して、チェックを入れて、保存。

最後に一番下までスクロールして「ホームページ」と「プライバシーポリシー」のURLを記入して(必須)、「確認のため送信」をクリックすると、Googleの審査に入ります。

以上で、開発コンソールでの作業は完了です。

Googleの審査が終わるまでは、アプリが作ったファイルにしかアクセスできないのでご注意。

 

4. Androidの実装

depencencies

まず、Moduleレベルのbuild.gradleに関連ライブラリを記入します。

android {

 ....

    packagingOptions {
        exclude 'META-INF/DEPENDENCIES'
        exclude 'META-INF/LICENSE'
        exclude 'META-INF/LICENSE.txt'
        exclude 'META-INF/license.txt'
        exclude 'META-INF/NOTICE'
        exclude 'META-INF/NOTICE.txt'
        exclude 'META-INF/notice.txt'
        exclude 'META-INF/ASL2.0'
    }
}
    
dependencies {

    ....

    implementation 'com.google.android.gms:play-services-auth:17.0.0'
    implementation 'com.google.http-client:google-http-client-gson:1.26.0'
    implementation('com.google.api-client:google-api-client-android:1.26.0') {
        exclude group: 'org.apache.httpcomponents'
    }
    implementation('com.google.apis:google-api-services-drive:v3-rev173-1.25.0') {
        exclude group: 'org.apache.httpcomponents'
    }
}

 

ログイン

ログアウト用にGoogleSignInClient変数、Google Drive操作用にDrive変数を定義しておきます。

var googleSignInClient: GoogleSignInClient? = null
var driveService: Drive? = null

 

ログイン処理はこんな感じです。

val googleSignInOptions = GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
  .requestScopes(Scope(DriveScopes.DRIVE_FILE))
  .build()
        
googleSignInClient = GoogleSignIn.getClient(this, googleSignInOptions)
googleSignInClient?.apply {
  startActivityForResult(this.signInIntent, REQUEST_CODE_SIGNIN)
}

 

この処理が呼ばれると、Googleが用意してくれたログイン画面が表示されます。

ログイン処理が終わると、onActivityResultに返ってくるのでそこでハンドリングします。

ログインに失敗する場合は、前の方で説明した「2. OAuthクライアントIDの作成」のフィンガープリントを今の環境に合わせて生成しているか(本番? or テスト?)再確認すると良いかもしれません。

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
  super.onActivityResult(requestCode, resultCode, data)

  if (requestCode == REQUEST_CODE_SIGNIN) {
    if (resultCode == RESULT_OK && data != null) {
      handleSignInResult(data)
    } else {
    	// ログイン失敗 or キャンセル
    }
  }
}

 

ログインに成功したら、Google Driveにアクセスするために、driveService: Driveを生成します。

fun handleSignInResult(intent: Intent) {
  GoogleSignIn.getSignedInAccountFromIntent(intent)
  .addOnSuccessListener {
    // ログイン成功
    val credential = GoogleAccountCredential.usingOAuth2(
      this, Collections.singleton(DriveScopes.DRIVE_FILE)
    )
    credential.setSelectedAccount(it.account)
    
    driveService = Drive.Builder(
    AndroidHttp.newCompatibleTransport(),
      GsonFactory(),
      credential
    ).setApplicationName("Drive API").build()
  }
  
  .addOnFailureListener {
    // ログイン失敗
  }
}

以上で、下準備は完了です。

 

ログアウト

ログアウトは、ログインの処理で生成したgoogleSignInClientのメソッドを呼ぶだけです。

googleSignInClient?.apply {
  this.signOut()
  .addOnSuccessListener {
  	// ログアウト成功
  }
  .addOnFailureListener {
  	// ログアウト失敗
  }
}

 

検索

検索は、独特のqueryを投げて行います。

Tasks.call<FileList>(
  Executors.newSingleThreadExecutor(),
  Callable<FileList>{
    driveService!!.files().list()
      .setSpaces("drive")
      .setFields("nextPageToken, files(id, name, modifiedTime)")
      .execute()
  })
  .addOnSuccessListener {
    // アクセス成功
    // it.files :List<File> にファイル情報が来る
  }
  .addOnFailureListener {
    // アクセス失敗
  }

 

検索条件を入れて絞り込みたい場合はsetQメソッドを使います。

driveService!!.files().list()
  .setQ("name contains 'hoge1' and name contains 'hoge2'")
  ...

 

その他、指定できるオプションはこちらの公式ドキュメントが参考になります。
https://developers.google.com/drive/api/v3/search-files

 

ファイルの取得

Google Driveから実際のファイルを取得する場合は、前述の「検索」で取得した「id (ファイルID)」を指定して取得します。

例はバイナリーファイルの場合なので、テキストファイルを取得したい場合は、BufferdInputStreamを、BufferdReaderに置き換えて処理をさせましょう。

Tasks.call(Executors.newSingleThreadExecutor(), Callable<Void>{
  // queryで取得したファイルidで、ファイルを指定する
  val metadata = driveService!!.files().get( 取得したファイルid ).execute()
  val name = metadata.getName()

  driveService!!.files().get(fileId).executeMediaAsInputStream().use({ `is` ->
    BufferedInputStream(
      BufferedInputStream(`is`)

    ).use { inputStream ->
      // GoogleDriveから取得したファイルを読み込む
      var outputStream = FileOutputStream(File( 出力先パス ))
      
      var readBuff = ByteArray(4096)
      var readLen = -1
      while (true) {
       val readLen = inputStream.read(readBuff)
       if (readLen == -1) {
         break
       }

       outputStream.write(readBuff, 0, readLen)
      }
      outputStream.close()
      null
    }
  })
})
.addOnSuccessListener {
  // 処理の終了
} 
.addOnFailureListener {
  // エラー
}

 

ファイルの保存 / 更新

ファイルIDを指定して保存/更新をします。

ファイル名が同じでも、ファイルIDが違う場合は、新規保存されるので気をつけてください。

新しくファイルIDを生成したい場合は、後述の「ファイルIDの作成」を見てください。

Tasks.call(Executors.newSingleThreadExecutor(), Callable<Void>{
  val metadata = com.google.api.services.drive.model.File().setName( ファイル名 )
  val contentStream = ByteArrayContent( コンテントタイプ: String, アップロードデータ: ByteArray)
  driveService!!.files().update( ファイルID , metadata, contentStream).execute()

  null
})
.addOnSuccessListener {
  // 成功
}
.addOnFailureListener {
 // 失敗
}

 

ファイルIDの作成

新規にファイルを作成したい場合は、次の方法でファイルIDを生成します。

その後は、上記の「ファイルの保存 / 更新」を参照してください。

Tasks.call(Executors.newSingleThreadExecutor(), Callable<String>{
  val metadata = com.google.api.services.drive.model.File()
    .setParents(listOf("root"))
    .setMimeType( コンテントタイプ )
    .setName( ファイル名 )

  val googleFile = driveService!!.files().create(metadata).execute()
  ?: throw IOException("Null result when requesting file creation.")

  googleFile.getId()
})
.addOnSuccessListener {
  // it: String としてファイルIDを取得できる。
  val fileID = it
}
.addOnFailureListener {
  // 失敗
}

 

以上で、Googleアカウントのログインから、Google Driveの操作まで一通りが行えるはずです!

twitterでも毎日開発情報をつぶやいていますので、フォロー宜しくおねがいします。