简介

HMS Core华为帐号注册用户量已达到10亿+,通过华为帐号可以一键登录应用,通过与华为帐号绑定,可以为应用快速引入新用户和登录。华为帐号开放遵循OAuth2.0以及OpenID Connect标准规范。
您需要:

您将建立什么

在这个codelab中,您将使用已经创建好的Demo Project实现对华为帐号开放服务的API调用,通过Demo Project您可以体验到:

您将会学到什么

硬件要求

软件要求

需要的知识点

Android基础开发能力

集成HUAWEI HMS Core能力,需要完成以下准备工作:

具体操作,请按照《HUAWEI HMS Core集成准备》中详细说明来完成。
  1. 华为开发者联盟AppGallery Connect中选择"我的项目",在项目列表中选择创建的应用,在"项目设置"页面中选择"API管理"。
  2. 打开"华为帐号"服务开关。

至此,已经为创建的应用开通了"帐号"服务。

获取配置文件

  1. 打开AppGallery Connect应用管理中之前创建的应用,并选择"项目设置 > 常规",点击"默认数据处理位置"的设置按钮。
  2. 下载应用中的"agconnect-services.json"。
  3. 将 "agconnect-services.json"文件移至Android Studio开发工程应用模块的根目录。

配置HMS Core SDK依赖

  1. 打开应用级的build.gradle文件。
  2. 在"dependencies"中添加如下编译依赖,其中{version}替换为HMS Core SDK的版本号,例如:5.3.0.305。
    dependencies { implementation 'com.huawei.hms:hwid:{version}' }
  3. 点击Sync Now同步工程。

配置HMS Core SDK的Maven仓地址

  1. 打开Android Studio项目级"build.gradle"文件。
  2. 添加HUAWEI agcp插件以及Maven代码库。
    • 在"buildscript > repositories"中配置HMS Core SDK的Maven仓地址。
    • 在"allprojects > repositories"中配置HMS Core SDK的Maven仓地址。
    • 如果App中添加了"agconnect-services.json"文件则需要在"buildscript > dependencies"中增加agcp配置。
      buildscript { repositories { google() jcenter() // 配置HMS Core SDK的Maven仓地址。 maven {url 'https://developer.huawei.com/repo/'} } dependencies { ... // 增加agcp配置。 classpath 'com.huawei.agconnect:agcp:1.4.2.300' } } allprojects { repositories { google() jcenter() // 配置HMS Core SDK的Maven仓地址。 maven {url 'https://developer.huawei.com/repo/'} } }

配置混淆脚本

  1. 打开Android Studio工程的混淆配置文proguard-rules.pro
  2. 加入混淆配置。
    -ignorewarnings -keepattributes *Annotation* -keepattributes Exceptions -keepattributes InnerClasses -keepattributes Signature -keepattributes SourceFile,LineNumberTable -keep class com.huawei.hianalytics.**{*;} -keep class com.huawei.updatesdk.**{*;} -keep class com.huawei.hms.**{*;}
  3. 如果您使用了AndResGuard,需要在混淆配置文件中加入AndResGuard允许清单。
    "R.string.hms*", "R.string.connect_server_fail_prompt_toast", "R.string.getting_message_fail_prompt_toast", "R.string.no_available_network_prompt_toast", "R.string.third_app_*", "R.string.upsdk_*", "R.layout.hms*", "R.layout.upsdk_*", "R.drawable.upsdk*", "R.color.upsdk*", "R.dimen.upsdk*", "R.style.upsdk*", "R.string.agc*"

添加权限

Account SDK需要获取网络状态权限和获取Wi-Fi状态权限。需要在Manifest文件中添加下面权限:

<!--check network permissions--> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <!--check wifi state--> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />

帐号的交互接口主要涉及登录、静默登录、退出帐号、取消授权。本次codelab中您可以在您的Android Studio工程中创建一个布局页面,参照下图进行UI设计。

ID Token模式登录帐号

ID Token模式整体流程

  1. 用户点击帐号授权登录图标,请求使用帐号授权登录。
  2. 帐号拉起用户登录授权界面,界面上会根据登录请求中携带的授权域(scopes)信息,显示告知用户需要授权的内容。
  3. 用户手动允许授权后,帐号返回ID Token信息。
  4. 应用选择使用本地方式验证或帐号服务器方式验证ID Token。

ID Token模式代码示例

  1. 展示华为登录方式图标。
    应用在登录页面展示帐号登录方式的图标,华为登录方式图标规范请参见华为帐号登录图标使用规范
  2. 调用AccountAuthParamsHelper的setIdToken方法请求授权。
    Java
    AccountAuthParams authParams = new AccountAuthParamsHelper(AccountAuthParams.DEFAULT_AUTH_REQUEST_PARAM).setIdToken().createParams();

    Kotlin

    val authParams : AccountAuthParams = AccountAuthParamsHelper(AccountAuthParams.DEFAULT_AUTH_REQUEST_PARAM).setIdToken().createParams()
  3. 调用AccountAuthManager的 getService方法初始化AccountAuthService对象。
    Java
    AccountAuthService service = AccountAuthManager.getService(MainActivity.this, authParams);

    Kotlin

    val service : AccountAuthService = AccountAuthManager.getService(this@MainActivity, authParams)
  4. 调用AccountAuthService的getSignInIntent方法并拉起帐号登录授权页面。
    Java
    startActivityForResult(service.getSignInIntent(), 8888);

    Kotlin

    startActivityForResult(service.signInIntent, 8888)
  5. 登录授权完成后处理登录结果。
    Java
    @Override protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { //授权登录结果处理,从AuthAccount中获取ID Token super.onActivityResult(requestCode, resultCode, data); if (requestCode == 8888) { Task<AuthAccount> authAccountTask = AccountAuthManager.parseAuthResultFromIntent(data); if (authAccountTask.isSuccessful()) { //登录成功,获取用户的帐号信息和ID Token AuthAccount authAccount = authAccountTask.getResult(); Log.i(TAG, "idToken:" + authAccount.getIdToken()); } else { //登录失败,不需要做处理,打点日志方便定位 Log.e(TAG, "sign in failed : " +((ApiException) authAccountTask.getException()).getStatusCode()); } } }

    Kotlin

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { //授权登录结果处理,从AuthAccount中获取ID Token super.onActivityResult(requestCode, resultCode, data) if (requestCode == 8888) { val authAccountTask = AccountAuthManager.parseAuthResultFromIntent(data) if (authAccountTask.isSuccessful) { //登录成功,获取用户的帐号信息和ID Token val authAccount = authAccountTask.result Log.i(TAG, "idToken:" + authAccount.idToken) } else { //登录失败,不需要做处理,打点日志方便定位 Log.e(TAG, "sign in failed : " + (authAccountTask.exception as ApiException).statusCode) } } }

Authorization Code模式登录帐号

帐号还支持使用Authorization Code授权登录。适用于拥有server端的应用授权。

Authorization Code模式整体流程

  1. 用户点击帐号授权登录图标,请求使用帐号授权登录。
  2. 帐号拉起用户授权界面,界面上会根据登录请求中携带的授权域(scopes)信息, 显示告知用户需要授权的内容。
  3. 用户手动允许授权后,帐号返回Authorization Code信息。
  4. 第三方应用获取Authorization Code后,通过服务端接口获取Access Token、Refresh Token、Id Token信息。
  5. Access Token或ID Token过期后,使用Refresh Token获取新的Access Token、ID Token信息。

Authorization Code模式代码示例

  1. 展示华为登录方式图标。
    应用在登录页面展示帐号登录方式的图标,华为登录方式图标规范请参见华为帐号登录图标使用规范
  2. 调用AccountAuthParamsHelper的 setAuthorizationCode方法请求授权。
    Java
    AccountAuthParams authParams = new AccountAuthParamsHelper(AccountAuthParams.DEFAULT_AUTH_REQUEST_PARAM).setAuthorizationCode().createParams();

    Kotlin

    val authParams : AccountAuthParams = AccountAuthParamsHelper(AccountAuthParams.DEFAULT_AUTH_REQUEST_PARAM).setAuthorizationCode().createParams()
  3. 调用AccountAuthManager的 getService方法初始化AccountAuthService对象。
    Java
    AccountAuthService service = AccountAuthManager.getService(MainActivity.this, authParams);

    Kotlin

    val service : AccountAuthService = AccountAuthManager.getService(this@MainActivity, authParams)
  4. 调用AccountAuthService的getSignInIntent方法并拉起帐号登录授权页面。
    Java
    startActivityForResult(service.getSignInIntent(), 8888);

    Kotlin

    startActivityForResult(service.signInIntent, 8888)
  5. 登录授权完成后处理登录结果。
    Java
    @Override protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { //授权登录结果处理,从AuthAccount中获取Authorization Code super.onActivityResult(requestCode, resultCode, data); if (requestCode == 8888) { Task<AuthAccount> authAccountTask = AccountAuthManager.parseAuthResultFromIntent(data); if (authAccountTask.isSuccessful()) { //登录成功,获取用户的帐号信息和Authorization Code AuthAccount authAccount = authAccountTask.getResult(); Log.i(TAG, "serverAuthCode:" + authAccount.getAuthorizationCode()); } else { //登录失败 Log.e(TAG, "sign in failed:" + ((ApiException) authAccountTask.getException()).getStatusCode()); } } }

    Kotlin

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { //授权登录结果处理,从AuthAccount中获取Authorization Code super.onActivityResult(requestCode, resultCode, data) if (requestCode == 8888) { val authAccountTask = AccountAuthManager.parseAuthResultFromIntent(data) if (authAccountTask.isSuccessful) { //登录成功,获取用户的帐号信息和Authorization Code val authAccount = authAccountTask.result Log.i(TAG, "serverAuthCode:" + authAccount.authorizationCode) } else { //登录失败 Log.e(TAG, "sign in failed:" + (authAccountTask.exception as ApiException).statusCode) } } }
  6. 应用客户端将获取到的code上报给应用服务端,再由其调用/oauth2/v3/token接口向帐号服务器请求获取ID Token、Access Token、Refresh Token。
  7. 请求样例

    POST /oauth2/v3/token HTTP/1.1 Host: oauth-login.cloud.huawei.com Content-Type: application/x-www-form-urlencoded grant_type=authorization_code& code=CF3L7XyCVZi52XMdsUzD7Z6ap0/N2qExcNe0AMqTselTtNd1B4DUwTsQ/23FPZasC8yI29v+N2s2jMT/T2MXiuc+178I/sYuWVoTyqwBaDqVW82KCMqaxbeWBguH4hEENxmDSUIE61Qg5R1F074PiS+qJYnbLI2IBqatS37px8pn5qnuq5oX+UX8XN3/w8HLt4GpakW5Dk1v7hGs& client_id={app_id}& client_secret={app_secret}& redirect_uri=https%3A%2F%2F/www.example.com/%2Fredirect_uri

    返回样例

    HTTP/1.1 200 OK Content-Type: application/json;charset=UTF-8 Cache-Control: no-store Pragma: no-cache { "access_token": "CFyJ21sNODl16eV9y2vu3CwQk9DBr32BkOcxxgAd7MZUR5th1giyTk5\/kA+QDAyxou+\/5U2zzBRcf3qgLkkFdtbbC+mM3zFV7xj7CCEMHc5Tw92al0Y=", "refresh_token": "CF13G0sRaGybtYt7SIyeUILNORtTFwMgz4ao5C7j7vtgLPt6ogmXKjdI8RS\/YlyS71z4DyP6kEMnOrRlmNK0KhdOUNWd+qVLLRsEEHkqRIKpuAkPvL8=", "expires_in": 3600, "id_token": "eyJraWQiOiI3YTNlYjRkNTJmMDdhODM0NDU4MmRhOGQ3MWE1MGQ5MDlmNWM0YmRiZTFkNDQ3MjQ2MDNhZTA2NGM0ZTlkZGYyIiwidHlwIjoiSldUIiwiYWxnIjoiUlMyNTYifQ.eyJhdF9oYXNoIjoiM0hPdFZYOEdMcG1GSDBWRVlSc1BjdyIsImF1ZCI6IjEwMDczNTE2NyIsInN1YiI6Ik1ERTlYaWFoc3MwaWFFNXU2c09PaEY5Mlhvell0Rkt4bUdtbWlhNGtTaEJ3dklLR2ciLCJhenAiOiIxMDA3MzUxNjciLCJpc3MiOiJodHRwczovL2FjY291bnRzLmh1YXdlaS5jb20iLCJuYW1lIjoi6Jab5oyv5Y2OIiwiZXhwIjoxNTczMDQ2NDI4LCJnaXZlbl9uYW1lIjoi6Jab5oyv5Y2OIiwiZGlzcGxheV9uYW1lIjoi5rKh5pyJ562U5qGIIiwiaWF0IjoxNTczMDQyODI4LCJwaWN0dXJlIjoiaHR0cHM6Ly91cGZpbGUtZHJjbi5wbGF0Zm9ybS5oaWNsb3VkLmNvbS9GaWxlU2VydmVyL2ltYWdlL2IuMDI2MDA4NjAwMDIzMjQ3MjUxMS4yMDE5MDgyMDExNTQ0Mi5tbmRjWTZyN2JUT0xNcVdiNVBhZDIzZExWNXh0b1Z2WC4xMDAwLkI0QkUyQTdEM0I3NkFGMzBCMkJDNjlBQ0JFNjg3NDIxMTQwMjhEQzYwREZFOTVCMjM5QkI0QzM2OUQwOUVEMkEuanBnIn0.mqy2C3ZNYEM8FKt8r1LX0VFosJjpqVl7E7mw2N-uEhnmAJq3blBco8fp2TCEyUzi1qFMN7-cjv87mQqCEpgfozyU7xV0VXMGdcd9ZhOxtabZtQGxUXRpIPiK5iysp68d95_QJAf2YZIdA4P_1zU8ZGxH57njIXRUVdQWDB8poeuB9gOc72bufe3DmSkqYD9aKvcibpA44Iln58aj-I9xs-FpcDwE6Y9hTfLGT5vk_5hXs32qwt54kEH1JjKbzZRW7B-OaELJIzzOM49oZKrdkViG6c2Tco1xX1WcKSz298Wckj4suLBAqkam4AprQgoSETC__ORTfy9OHIS1m4_8uQ", "scope": "openid profile email", "token_type": "Bearer" }
  8. 由于Access Token的有效期(目前是60分钟)较短, 当Access Token失效, 或者即将失效时,可以使用Refresh Token通过/oauth2/v3/token 接口向帐号服务器请求获取新的Access Token。
    请求样例
    POST /oauth2/v3/token HTTP/1.1 Host: oauth-login.cloud.huawei.com Content-Type: application/x-www-form-urlencoded grant_type=refresh_token& client_id=12345& client_secret=bKaZ0VE3EYrXaXCdCe3d2k9few& refresh_token=CF2Mm03n0aos9iZZ8nIhfyDtoXy74CXeBi50gVVhMpB0IUzlv9ZwizEvTBhVoF820ZPim0JwNR9j2p1qgEQWnIVYZRlp4T6ezMgekUnsHBkvNev5rd2MdfQMLP

    返回样例

    HTTP/1.1 200 OK Content-Type: application/json;charset=UTF-8 Cache-Control: no-store Pragma: no-cache { "access_token": "CFyJ4J\/l6wuwcFqYOJG4maq2ca8RAV+g0i+mel6qCV5lvqH0PYtW0+BNwfHWg0AqMnW6ZdBvUgs7ijkxMFh1xVP\/B+vQXz3PWsivkKCuL78XtbLt7vs=", "id_token": "eyJhbGciOiJSUzI1NiIsImtpZCI6IjExOGRmMjU0YjgzNzE4OWQxYmMyYmU5NjUwYTgyMTEyYzAwZGY1YTQiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLCJhenAiOiI3ODI0NTY2Njc4OTgtc2M0MzE3Y2l0NGEwMjB0NzdrbGdsbWo1ZjA4YWtnMWIuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJhdWQiOiI3ODI0NTY2Njc4OTgtN2NkNGJpYWRkaGVwNGc4cnZic2VlOGtwcDA5Zm1hNzIuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJzdWIiOiIxMDE3MTIxMzkwMzgwNDE2MDc0MTQiLCJlbWFpbCI6Inh1ZXpoZW5odWF0anVAc2luYS5jb20iLCJlbWFpbF92ZXJpZmllZCI6dHJ1ZSwicGljdHVyZSI6Imh0dHBzOi8vbGg1Lmdvb2dsZXVzZXJjb250ZW50LmNvbS8tMm9lTTllT09zNTAvQUFBQUFBQUFBQUkvQUFBQUFBQUFBQkkvMVpOSC0xdmxxc3cvczk2LWMvcGhvdG8uanBnIiwiaWF0IjoxNTYxNDUxMTUyLCJleHAiOjE1NjE0NTQ3NTJ9.Eo9IHMkid596jvt1YYzNsRtDq9c9K9dbougkU41Noh7TXNiko86_RuWwHID6k1kDg398AwC3wwH-t2hLcUjgrXPNd9XYU96Jp4-UxdDszP6ywEJgvvBCyTHzsi2auvKt_MnfSrs3qOKfh7noJvXq8AY-Hi3vqSUks5kGqbZKVzCHhBDO3RD9Fs9YHsB6w0XVKZojPOBDaAT_TiijoChn-Q-e8NbSGUx52OgeH-Nw5lOj6JVb_7fb6ucWRzlhiQuzFjklevLVw2pjw1MxKbl1vfRp0X699uZBVjgl9hj1L7LSDObuPzLiXF7ojji5JKYC6zIwAtZQUZ_VUmSk01GDLQ", "expires_in": 3600, "scope": "openid profile email", "token_type": "Bearer" }

静默登录

静默登录整体流程

  1. 用户进行了触发静默登录的场景,根据应用实际场景由您自行设定。
  2. 应用客户端调用AccountAuthParamsHelper的默认构造方法配置鉴权参数。
  3. 帐号SDK向应用客户端返回包含授权参数的AccountAuthParams对象。
  4. 应用客户端调用AccountAuthManager.getService方法初始化AccountAuthService对象。
  5. 帐号SDK向应用客户端返回AccountAuthService对象。
  6. 应用客户端调用AccountAuthService.silentSignIn方法向帐号SDK发起静默登录请求。
  7. 帐号SDK检查用户是否符合静默登录的授权,并向应用客户端返回授权结果。
  8. 应用根据授权结果自行确定后续处理。

静默登录代码示例

  1. 调用AccountAuthParamsHelper的默认构造方法配置授权参数。
    Java
    AccountAuthParams authParams = new AccountAuthParamsHelper(AccountAuthParams.DEFAULT_AUTH_REQUEST_PARAM).createParams();

    Kotlin

    val authParams : AccountAuthParams = AccountAuthParamsHelper(AccountAuthParams.DEFAULT_AUTH_REQUEST_PARAM).createParams()
  2. 调用AccountAuthManager的getService方法初始化AccountAuthService对象。
    Java
    AccountAuthService service = AccountAuthManager.getService(MainActivity.this, authParams);

    Kotlin

    val service : AccountAuthService = AccountAuthManager.getService(this@MainActivity, authParams)
  3. 调用AccountAuthService.silentSignIn方法发起静默登录请求。
    Java
    Task task = service.silentSignIn();

    Kotlin

    val task : Task = service.silentSignIn()
  4. 处理授权结果。如果授权成功,可获取用户的帐号信息,允许用户登录。应用可根据authAccount.getAccountFlag的结果判断当前登录帐号的渠道类型。
    Java
    task.addOnSuccessListener(new OnSuccessListener<AuthAccount>() { @Override public void onSuccess(AuthAccount authAccount) { //获取帐号信息 Log.i(TAG, "displayName:" + authAccount.getDisplayName()); //获取帐号类型,0表示华为帐号、1表示AppTouch帐号 Log.i(TAG, "accountFlag:" + authAccount.getAccountFlag()); } });

    Kotlin

    task.addOnSuccessListener { authAccount -> //获取帐号信息 Log.i(TAG, "displayName:" + authAccount.displayName) //获取帐号类型,0表示华为帐号、1表示AppTouch帐号 Log.i(TAG, "accountFlag:" + authAccount.accountFlag); }

    如果授权失败,可能是用户之前未进行过登录授权,应用可自行确认是否需要调用AccountAuthService的getSignInIntent方法显式展示登录授权页面。
    Java

    task.addOnFailureListener(new OnFailureListener() { @Override public void onFailure(Exception e) { //登录失败,您可以尝试使用getSignInIntent()方法显式登录 if (e instanceof ApiException) { ApiException apiException = (ApiException) e; Log.i(TAG, "sign failed status:" + apiException.getStatusCode()); } } });

    Kotlin

    task.addOnFailureListener { e -> //登录失败,您可以尝试使用getSignInIntent()方法显式登录 if (e is ApiException) { Log.i(TAG, "sign failed status:" + e.statusCode) } }

退出帐号

退出帐号整体流程

  1. 用户在已经登录应用,在应用中执行退出操作。
  2. 应用调用AccountAuthService.signOut方法向帐号SDK请求退出帐号。
  3. 帐号SDK清除帐号登录信息后,向应用返回退出结果。

退出帐号代码示例

  1. 使用帐号登录授权时创建的AccountAuthService实例调用signOut接口。
    Java
    //service为登录授权时使用getService方法生成的AccountAuthService实例 Task signOutTask = service.signOut();

    Kotlin

    //service为登录授权时使用getService方法生成的AccountAuthService实例 val signOutTask = service.signOut()
  2. signOut完成后的处理。
    Java
    signOutTask.addOnCompleteListener(new OnCompleteListener<Void>() { @Override public void onComplete(Task<Void> task) { //完成退出后的处理 Log.i(TAG, "signOut complete"); } });

    Kotlin

    signOutTask.addOnCompleteListener { it -> //完成退出后的处理 Log.i(TAG, "signOut complete")

帐号取消授权

帐号取消授权整体流程

  1. 用户在已经登录应用并授权,在应用中执行取消授权。
  2. 应用客户端调用AccountAuthService.cancelAuthorization方法向帐号SDK请求取消授权。
  3. 帐号SDK清理帐号授权信息后,向应用客户端返回取消结果。

帐号取消授权代码示例

  1. 应用设置取消授权入口,此部分由应用自行开发。
  2. 应用调用AccountAuthService.cancelAuthorization方法,并处理返回结果。
    Java
    //service为登录授权时使用getService方法生成的AccountAuthService实例 service.cancelAuthorization().addOnCompleteListener(new OnCompleteListener<Void>() { @Override public void onComplete(Task<Void> task) { if (task.isSuccessful()) { //取消授权成功后的处理 Log.i(TAG, "onSuccess: "); } else { //异常处理 Exception exception = task.getException(); if (exception instanceof ApiException){ int statusCode = ((ApiException) exception).getStatusCode(); Log.i(TAG, "onFailure: " + statusCode); } } } });

    Kotlin

    //service为登录授权时使用getService方法生成的AccountAuthService实例 service.cancelAuthorization().addOnCompleteListener { task -> if (task.isSuccessful) { //取消授权成功后的处理 Log.i(TAG, "onSuccess: ") } else { //异常处理 val exception = task.exception if (exception is ApiException) { val statusCode = exception.statusCode Log.i(TAG, "onFailure: $statusCode") } } }

开发完成后,点击图标,运行Android Studio工程打包生成APK,并安装在测试手机上。运行界面如下图所示:

干得好,您已经成功完成了codelab并学到了:

帐号服务相关API介绍
您可以点击下方按钮下载源码。

源码下载

Code copied