AndroidでMiAuth実装してみた
リポジトリ
AndroidでMiAuthを実装しました。
手っ取り早くソース寄こせって人はこちらから。 developmentブランチです。
あと、かなりクラスを行ったり来たりするので、コード表示しながら読んでいただければ幸いです。
Misskey Hub
解説では明示されていませんが、カスタムスキーマは現在受け付けておらず、httpsに統一しているそうです(しゅいろママが言ってた)。
トークン取得フロー
MiAuthは、次のようなイメージでアクセストークンを取得します。 OAuth2は未実装なので、詳細については言及しません。
さらに詳細を文字起こしにするとこんな感じ。
(一応MiAuth想定のフロー) 認証開始 -> ViewModel#startAuth -> AuthUseCase#startAuth -> ユーザによりアプリ連携が許可される -> Activity#onNewIntentでコールバックURLのキャッチ -> RegisterAppCallback#onRegistered で受信する -> Interactor#requestToken -> トークンが返ってくる(成功の場合) -> ViewModel で実装し Interactor に渡されている AuthResultCallback を叩いてトークンを ViewModel に渡す -> ViewModel から PreferenceUseCase 等を通じてトークンを保存する
インターフェース定義
AuthActivity
とAuthActivityViewModel
は認証フローの詳細を知らず、認証サーバとのやりとりはすべてAuthUseCase
を実装した各種インタラクタが実行します。
ViewModel はほとんどの場合、Activityからのイベントをインタラクタに通知するだけです。
また、MVVM を採用しているので、ViewModel は各種 UseCase を集約しています。
AuthUseCase
MiAuth以外にも対応できるようにsealed interface
で定義しました。
sealed interface
とすることで、AuthUseCase
を次のようにobject
句で実装しようとしてもエラーになります。
また、どんな認証フローでもstartAuth
を叩くことでフローを開始するように縛ります。
fun foo() { val XxxAuthInteractor = object : AuthUseCase { ... } } //-> This type is sealed, so it can be inherited by only its own nested classes or objects
AuthUseCase
は次のとおり定義します。
sealed interface AuthUseCase { fun startAuth(context: Context, ticket: AuthTicket, resultCallback: AuthResultCallback): RegisterAppCallback fun onDismiss() interface MiAuthUseCase: AuthUseCase interface OAuth2UseCase: AuthUseCase } //ユーザがアプリ連携を許可した際に必要なコールバック //フローにActivity#onNewIntentが絡むため、何かしらの形でインタラクタに通知する仕組みが必要 interface RegisterAppCallback { suspend fun onRegistered(callbackIntent: Intent) suspend fun onFailed(err: Exception) } //トークンをリクエストした際のサーバのレスポンス //取得に成功した場合、tokenが格納される sealed interface AuthResultCallback { fun onAuthFinish(ticket: AuthTicket, token: Token) fun onFailed(err: Exception) interface MiAuthResultCallback: AuthResultCallback interface OAuth2ResultCallback: AuthResultCallback }
AuthTicket
は各種パーミッションやホスト情報等をまとめた単なるデータクラスです。
こちらもsealed
で定義します。
MiAuthInteractor と OAuth2Interactor
AuthUseCase
を実装した具象クラス。
このように認証方式ごとにAuthUseCase
を実装したクラスを作ることで、startAuth
を叩くだけで異なる認証フローを起動できるようにしています(たぶん)。
また、RegisnterAppCallback
は Interector#startAuth
にて、AuthResultCallback
は ViewModel にて実装しています。
MiAuthInteractor github.com
AuthActivityViewModel github.com
雑なまとめ
- 一部甘い部分(クラス変数にしている部分とか)があるけどそこはスルーで。
- 別にMiAuthでトークン取得するテストなだけならここまでやる必要はない。。。