Android kotlinでGmail APIに接続して受信箱のメッセージを取得する方法
1 やりたいこと
AndroidのアプリでGmailの受信箱にあるメッセージを取りたい。
2 過去の記事と実装方針(読み飛ばしてもOKです)
過去の記事ではOAuth2.0を使って認証するときにclient idとclient secretを使った方法が多かった【参考記事(Qiita, @hsn))】。Androidのアプリはclient idのみで動かせるそうなので、それを使いたい(実際はclient idを入力するところすら無い)。
そこで、AndroidアプリでGoogleスプレッドシートを使う記事【参考記事(寝室コンピューティング, karintomania)】を参考に認証のコードを書いて、Gmail APIに応用。この記事では今では非推奨のstartActivityForResultが使われているので、この部分を【参考記事(Composeとその他のライブラリ, Android)】を参考にして推奨形式に書き直す。
3 前準備(Google Cloud Platformですること)
Google Developer Consoleで検索してアクセスしてもGCPに飛ぶと思う。
そこで、「APIとサービス」を選択し「認証情報」を選択する。そのページの「認証情報を作成」から「OAuthクライアントID」を選択する。指示に従って空欄を埋めていく。ここで、アプリケーションの種類は必ずAndroidを選択すること。
また、OAuthの同意画面も設定する。ScopeはGmailで目的に合わせたScopeを設定する。
4 動いたコード
以下に動いたコードを示します。
実装のアーキテクチャは『Jetpack ComposeによるAndroid MVVMアーキテクチャ入門 (OnDeck Books(NextPublishing)) 』(奥澤 俊樹 著)を参考にしました。
まずは認証をするViewについて。
@Composable
fun AuthGmailView(mainViewModel: MainViewModel,context: Context, activity: Activity) {
val uiState: MainViewModel.UiState by mainViewModel.uiState
lateinit var mGoogleSignInClient: GoogleSignInClient
lateinit var credential: GoogleAccountCredential
val scopeGmail: String = "目的に合わせたscopeを入れてください。"
val gso = GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN).requestScopes(
Scope(scopeGmail)
).requestEmail().build()
mGoogleSignInClient = GoogleSignIn.getClient(activity, gso)
credential = GoogleAccountCredential.usingOAuth2(activity, Collections.singleton(scopeGmail))
val signInIntent: Intent = mGoogleSignInClient.signInIntent
val test = rememberLauncherForActivityResult(contract = ActivityResultContracts.StartActivityForResult(), onResult = {
if (it.resultCode == Activity.RESULT_OK) {
val task = GoogleSignIn.getSignedInAccountFromIntent(it.data)
try {
val account = task.getResult(ApiException::class.java)
Log.i("Sign in", "Name : " + account?.displayName.toString()) //Debug用
Log.i("Sign in", "Email : " + account?.email) //Debug用
mainViewModel.initialLoad(context = context) //Gmailの中身を探すModelを呼んでいます。
} catch (e: ApiException) {
Log.w("Sign in fail", "signInResult: failed code = " + e.statusCode)
mainViewModel.resultAuth() //失敗したと表示
}
} else {
mainViewModel.resultAuth() //失敗したと表示
}
})
SideEffect {
test.launch(signInIntent) //サインインの画面を出す。
}
}
そして、メッセージを呼んでくるところ。ここではスニペットを表示している。
val scopeGmail: String = "目的に合わせたscopeを入れてください。"
override suspend fun getInboxEmails(context: Context): MessagesGmail {
val account = GoogleSignIn.getLastSignedInAccount(context)
val credential: GoogleAccountCredential =
GoogleAccountCredential.usingOAuth2(context, Collections.singleton(scopeGmail))
credential?.setSelectedAccount(account?.account)
withContext(Dispatchers.Default) {
val mailService = Gmail.Builder(
AndroidHttp.newCompatibleTransport(),
JacksonFactory.getDefaultInstance(), credential
).setApplicationName("Test")
.build()
val messages = mailService.users().messages().list("me").execute()
Log.i("size of messages", messages.messages.size.toString()) //Debug用に何個Messageあるかを表示
var listMessage: MutableList<Message> = mutableListOf()
var a = 0;
for (message in messages.messages) {
val mdata = mailService.users().messages().get("me", message.id).execute()
listMessage.add(a++, mdata)
}
Log.d("Mutable list", listMessage[0].snippet)
val messagesGmail = MessagesGmail(messsages = listMessage)
return@withContext messagesGmail
}
ここで
for (message in messages.messages) {
val mdata = mailService.users().messages().get("me", message.id).execute()
listMessage.add(a++, mdata)
}
これをしないと、Messageが読めないので注意。
あとは、Gmail APIのリファレンス(messages)をもとに、listMessageから欲しい情報を取得すれば良い。
おまけ
ログアウトしたいときは、以下のような関数を適当に作って呼ぶ。
fun logout() {
val scopeGmail: String = "目的に合わせたscopeを入れてください。"
lateinit var mGoogleSignInClient: GoogleSignInClient
val gso = GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN).requestScopes(
Scope(scopeGmail)
).requestEmail().build()
mGoogleSignInClient = GoogleSignIn.getClient(this, gso)
mGoogleSignInClient.signOut()
}
さいごに
Androidアプリ開発初心者なので、良くないコードの書き方とか、不具合あればコメントいただけると幸いです。質問なども答えられる範囲でお返ししますので、ぜひコメントください。
もしも、コメントに書けない事や質問などありましたら、akira.kashihara[at]hotmail.comまでメールをお願いします。
参考記事
ここは必ず見ておいたほうがいい記事
- Gmail APIのSample Code(Python) <- Threadに関するSample Codeなので注意!
- Gmail APIのリファレンス
以下の記事は、調べたときにヒントになった記事
Discussion