HMS Account Kit実装入門

# HMS Account Kitの概要

最近のアプリはだいたいサーバーと連携して動作します。そしてユーザー登録が必要だったり、会員登録しないとお得なサービスが使えなかったり、といったパターンが多いです。その新規登録にあたって、どのように本人確認を行うか、また、ユーザーに負担をかけずに新規登録をしてもらうか、というのは考えなければならない問題点です。

そこで登場するのがソーシャルログインというのもです。こういう画面を見たことありますか？
<img width="300" alt="Screenshot_20201001_150109_com.ss.android.ugc.trill.jpg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/704548/3f0fd870-ab38-171b-ceb9-8a33738026f4.jpeg">
第三者のプラットフォーム経由で新規登録・ログインを行うのがソーシャルログインです。HUAWEI Account KitはGoogleやLINE、Twitter、Facebookと同じものだと考えていただければと思います。

# HMS Account Kitの特徴
HMS Account Kitはほかのソーシャルログインの特徴だけではなく、下記の特徴も持っています。

* １９０ヵ国と地域以上をカバー
* ７０種類以上の言語をサポート
* ９億以上のユーザー

また、OAuth 2.0とOpen ID connectに準拠しているので、セキュリティ面も安心です。

# HMS Account Kitの実装
実装手順は下記に述べます。

## 前準備
(1) Huaweu Developerを登録します。

(2) AppGallery Connectでアプリのプロジェクトを登録します。
<img width="300" alt="スクリーンショット 2020-10-01 155726.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/704548/7ad86f57-75ef-2aa1-7f8a-89ba53ec0ae1.png">
<img width="300" alt="スクリーンショット 2020-10-01 155747.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/704548/910d9b63-0bf4-90fd-3aba-168b4eb26310.png">
<img width="300" alt="スクリーンショット 2020-10-01 155822.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/704548/890cd9ee-09ad-3e72-d9fb-7b1d95d48c45.png">
<img width="300" alt="スクリーンショット 2020-10-01 155911.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/704548/50d68b1d-4b5f-d185-2ecc-3b03c4175ad7.png">
<img width="300" alt="スクリーンショット 2020-10-01 155946.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/704548/25cf901a-7e9f-fbde-9eeb-63504bb9a821.png">

(3) keytoolで生成したSHA256をAppGallery Connectのアプリプロジェクトに登録します。
<img width="300" alt="スクリーンショット 2020-10-01 160111.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/704548/60cc348f-e029-8b02-8291-b16df40dd33d.png">

(4) Account Kitサービスを有効にします。 
<img width="300" alt="スクリーンショット 2020-10-01 160237.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/704548/d550b384-b3f0-095d-ac18-96344b2f8b1e.png">

(5) agconnect-services.jsonをダウンロードし、appフォルダに配置します。
<img width="300" alt="スクリーンショット 2020-10-01 161111.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/704548/f50eb1bb-6cbd-4575-0cb3-8f40b19c871d.png">
<img width="200" alt="スクリーンショット 2020-10-01 162011.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/704548/74e4218e-ea0d-fbbf-6cc3-134ff40d9c0f.png">

## HMS SDKを導入
(1) プロジェクトのbuild.gradleを開き、mavenとclasspathを追加します。
<img width="200" alt="スクリーンショット 2020-10-01 162820.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/704548/7ee345a1-2c6d-9857-deed-776060a09de4.png">

```gradle:build.gradle
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
    ext.kotlin_version = "1.3.72"
    repositories {
        google()
        jcenter()

        // こちらの行を追加
        maven {url 'http://developer.huawei.com/repo/'}
    }
    dependencies {
        classpath "com.android.tools.build:gradle:4.0.1"
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"

        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files

        // こちらの行を追加
        classpath 'com.huawei.agconnect:agcp:1.3.1.300'
    }
}

allprojects {
    repositories {
        google()
        jcenter()

        // こちらの行を追加
        maven { url 'http://developer.huawei.com/repo/' }
    }
}
```

(2) モジュールのbuild.gradleを開き、次のようにを追加します。
<img width="200" alt="スクリーンショット 2020-10-01 162842.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/704548/7cd74ac6-a36a-dbdd-30ea-fb24c14f0408.png">

```gradle:build.gradle
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'

// こちらの行をapply plugin: 'com.android.application'の後ろに追加してください。
apply plugin: 'com.huawei.agconnect'

android {
    // signingConfigsを追加
    signingConfigs {
        debug {
            storePassword 'My password'
            keyAlias 'My keyAlias'
            keyPassword 'My password'
            storeFile file('My keystore file.jks')
            v1SigningEnabled true
            v2SigningEnabled true
        }
        release {
            storePassword 'My password'
            keyAlias 'My keyAlias'
            keyPassword 'My password'
            storeFile file('My keystore file.jks')
            v1SigningEnabled true
            v2SigningEnabled true
        }
    }

    buildTypes {
        release {
            // signingConfigを追加
            signingConfig signingConfigs.release

            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }

        debug {
            // signingConfigを追加
            signingConfig signingConfigs.debug

            debuggable true
        }
    }

    dataBinding {
        enabled = true
    }
}

dependencies {
    implementation fileTree(dir: "libs", include: ["*.jar"])
    implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
    implementation 'androidx.core:core-ktx:1.3.1'
    implementation 'androidx.appcompat:appcompat:1.2.0'
    implementation 'androidx.constraintlayout:constraintlayout:2.0.1'
    implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
    implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'androidx.test.ext:junit:1.1.2'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
    implementation 'com.squareup.picasso:picasso:2.71828'

    // こちらの２行を追加
    implementation 'com.huawei.agconnect:agconnect-core:1.3.1.300'
    implementation 'com.huawei.hms:hwid:5.0.1.301'
}

// こちらの行を追加
apply plugin: 'com.huawei.agconnect'
```

(3) proguard-rules.proを開き、次のようにを追加します。
<img width="200" alt="スクリーンショット 2020-10-01 162901.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/704548/01ff236e-58c6-0000-165a-99daa78f64e8.png">

```java:proguard-rules.pro
-ignorewarnings
-keepattributes *Annotation*
-keepattributes Exceptions
-keepattributes InnerClasses
-keepattributes Signature
-keepattributes SourceFile,LineNumberTable
-keep class com.hianalytics.android.**{*;}
-keep class com.huawei.updatesdk.**{*;}
-keep class com.huawei.hms.**{*;}
```

## HUAWEI IDによるログインの実装

こちらはオフィシャルサイトに掲載されているシーケンス図です。
<img width="600" alt="accountKitClientIdToken.png" src="https://communityfile-drcn.op.hicloud.com/FileServer/getFile/cmtyPub/011/111/111/0000000000011111111.20200930110613.25711348362617540438467123463280:50510930061339:2800:832A2EC1031A06ACC7FC02FC440F151702F438E7C5D5B5B609A3AEADE8F6A552.png">

各ステップに対応しているコード実装は下記に示します。

### ステップ１
ユーザーが”HUAWEI IDでログイン”ボタンを押すというプロセスです。

ここで気を付けなければならないのは、ファーウェイはこのログインボタンのデザインに対して規定を設けているところです。いろいろ細かいデザイン規定があるので、オフィシャルページをご参照ください。
[HUAWEI ID Sign-In Icon Specifications](https://developer.huawei.com/consumer/jp/doc/HMSCore-Guides-V5/dev-specifications-0000001050048916-V5)

### ステップ２～８
”HUAWEI IDでログイン”ボタンが押されたときの処理です。

```kotlin:MyActivity.kt
private var authManager: HuaweiIdAuthService? = null

private fun signInIdToken() {
	val param = HuaweiIdAuthParamsHelper(HuaweiIdAuthParams.DEFAULT_AUTH_REQUEST_PARAM)
		.setIdToken()
		.createParams()
	authManager = HuaweiIdAuthManager.getService(activity, param)
	authManager?.let {
		startActivityForResult(it.signInIntent, REQUEST_CODE_SIGN_IN_ID_TOKEN)
	}
}
```

### ステップ９～１４
HMS Account Kitの内部の認証済み確認処理とユーザーが明示的に認証を承認するプロセスです。こちらはコード実装不要です。

### ステップ１５～１６
IDトークンとユーザーのアカウント情報はここで返ってきます。

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

	when (requestCode) {
		REQUEST_CODE_SIGN_IN_ID_TOKEN -> {
			val authHuaweiIdTask = HuaweiIdAuthManager.parseAuthResultFromIntent(data)
			if (authHuaweiIdTask.isSuccessful) {
				// Idトークン= authHuaweiIdTask.result.idToken
				// ユーザー名 = authHuaweiIdTask.result.displayName
				// ユーザーのアバター画像のURL = authHuaweiIdTask.result.avatarUri
				// ユーザーのメールアドレス = authHuaweiIdTask.result.email
			}
		}
	}
}
```

### ステップ１７
シーケンス図ではこのステップはIDトークンの有効性をチェックするためのプロセスと書かれていますが、ステップ１５～１６ではIDトークンに含まれているユーザー情報も一緒に送られてくるので、このステップを飛ばしてもよいでしょう。

### IDトークンの有効性検証
下記のAPIでIDトークンを検証できます。

API（開発者）：https://oauth-login.cloud.huawei.com/oauth2/v3/tokeninfo
API（運営側）：https://oauth-login-at.cloud.huawei.com/oauth2/v3/tokeninfo
メソッド：POST
リクエストのパラメータ：id_token = IDトークン

レスポンスはJSONとなります。

詳細はこちらをご参照ください。
[Verifying the Validity of an ID Token](https://developer.huawei.com/consumer/jp/doc/HMSCore-References-V5/account-verify-id-token_hms_reference-0000001050050577-V5)

Postmanのスクリーンショットだとこんな感じです。
![スクリーンショット 2020-10-01 192850.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/704548/af745045-e958-f606-f333-d4c37861d6ac.png)

### IDトークンの有効性検証とは？
実はIDトークンをJWTで解凍すれば、ユーザー情報が見られます。たとえば、ネットの[JWT解凍ツール](http://calebb.net/)で解凍したら、次のようになります。
![スクリーンショット 2020-10-01 224632.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/704548/7f8b0a06-2ecb-efbf-7c55-ad85699f0f0a.png)

IDトークンの有効性の検証とは、kidやiss、aud、expが正しいかどうかを確認することです。

# 最後の一言
実装ではそこまでソースコードを書く必要がないので、すごく簡単だと思います。みなさんもぜひ使ってみてください。

# 参考
* オフィシャルのデモ：[https://github.com/HMS-Core/huawei-account-demo](https://github.com/HMS-Core/huawei-account-demo)