Android | 极光一键登录集成手册

4,129 阅读12分钟

黑暗中,追寻那微亮的曙光。

前言

某天翻阅极光文档时,发现极光也推出了一键登录,先来看个效果图:

之前有幸体验了 Mob 的一键登录,而今来体验下极光的一键登录,扫描二维码想下载个 Demo 体验玩一波,尴尬的是,扫出了维护中,本站暂时关闭,艾玛😓😓😓。此问题已反馈极光工作人员。

说句实在话,而今的互联网变更速度,简直让人目不暇接,单单从用户体验来讲,着实让人各种眼光一亮,闪闪冒金星。现在还能记得 Android 4.x 版本的大黑主题,五彩斑斓的黑色。😂😂😂

回到正题上,单纯从用户登录而言,同样也是各种迭代升级,不断的进化,不断的提升用户友好度。从传统手机号码 + 验证码方式,当现在三方登录,再到而今的一键登录,很庆幸,可以感受互联网带来的魅力。

回顾下传统登录方式,也就是通过手机号码 + 验证码的优势:

  • 操作简单: 输入手机号,输入验证码,即可通过,简单快捷;
  • 知晓人多: 至少我回村大爷大妈都知道大部分软件都可以直接通过手机号 + 验证码方式直接注册,然后就可以随便玩了。

再来说说个人认为的劣势吧。

  • 验证码短信不及时: 很多时候都会出现这么一种情况,点击了验证码,也开始了倒计时,但是手机迟迟接受不到验证码的信息,着急的时候真心很无奈,尤其高峰期;
  • 手残党易输入错误: 单纯个人而言,很多时候会尴尬的输入错误,然后包括到现在为止,每次输入验证码都要小心翼翼并且一个个校对很多次。😂😂😂

当然以上仅仅是个人使用过程中个人理解,也欢迎各位交流学习。

那么这个一键登录,相比传统又具有什么优势呢?

  • 显而易见的,从用户输入手机号、发送验证码、验证验证码有效性,直接升级到只需要点个按钮即可完成上述三步操作;
  • 针对后台而言,也省略了对接第三方发送短信 SDK 、提供前端接口以及验证前端发送数据有效性;
  • 针对前端而言,用户一步操作即可替换原有三步操作,且直接可以拿到有效手机号,省去很多 Code,何乐而不为?并且再也不需要挨个找运营商官方文档挨个痛苦集成了。

小伙伴说了,你看了吗,你就胡咧咧。好,哥儿们我给你附上三大运行商的链接:

三大运营商地址已附上,不服的小伙伴随时查阅~

其实,万物归根,根本还是简单了。大道归一,大道为简,才是真理。花里胡哨搞了 n 多,仅仅就是注册登录,除非死铁粉,不然至少个人直接 Say Bye or 跳过。

实践

说的天花烂坠,不如真正实践一波。何况好东西,谁不想赶快体验一波?感受下它带来的魅力呢?

一、翻阅极光,简单了解

此物诞生于 18 年,天呐,我现在才知道:

打开极光关于认证介绍,简单截个图:

在这里插入图片描述

目前已支持平台:

  • Android
  • iOS

未支持(包含尚未开放)平台:

  • Web (仅支持中国移动以及中国电信,还需要联系商务)
  • Flutter (未支持,热门的呀,咋会不支持的呢)

二、移步 Android SDK 集成指南

首先极光官网创建个项目,其次记得配置对应平台所需信息,这里为大家附上截取官网的一个说明:

关键信息已红线标明。

随后我们开始设置 Android 应用包名以及应用签名,如下图所示:

这里单独注明下之前记录的获取 MD5 方式:

之后配置我们的一键登录 RSA 加密公钥:

关于 RSA 加密公钥,可自己代码生成,也可以直接使用在线网址直接生成,将公私钥保存下来即可,简单方便快捷:

比如我在这里使用的非对称加密公钥:

-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDBsfT9nfWqRs1Z10m1U7znvGwE
8ddPsRUvSurJaSV7jxEVVZUUiUoeK1lh+fVOoMAosxCEv+iqQDysUHR52QcPTXEv
Mv0wp5YlCHIj7xckKVU2jxl49zVmaUxhvUXH1C9dbkOBGRtSt9bC7TkvYtVa4X3n
Xh0+GMBQ8MNNBfywSwIDAQAB
-----END PUBLIC KEY-----

以及非对称加密私钥:

-----BEGIN PRIVATE KEY-----
MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAMGx9P2d9apGzVnX
SbVTvOe8bATx10+xFS9K6slpJXuPERVVlRSJSh4rWWH59U6gwCizEIS/6KpAPKxQ
dHnZBw9NcS8y/TCnliUIciPvFyQpVTaPGXj3NWZpTGG9RcfUL11uQ4EZG1K31sLt
OS9i1VrhfedeHT4YwFDww00F/LBLAgMBAAECgYEAk4SuOs4oANRFp4vgtjodYDzP
5AAwZKBQqyEaqeTryCvQ7fetP+PD0DBhtc4CNy0UzKp8BS6Hy8p6qx3nZ7mTto3H
aRIG+K+UhD1BOi8ZaxlIV+DBIyEHOnIjwIgKXg0j5bXqI+qLo6zC84O5hlEJPwDR
Wy6tmj8dGXPxY75JUukCQQD3c0YGjdx0Qw6e+zH0g0cYKGmbGiDI1y+5QnZ83Yi2
i3kZUTCLEPIHaiC50u9VD5G6XaPEBv/psLFSbwD84zVHAkEAyGM2hpiVEsu/FTwr
rsONH8O350xTOHmtNHdwRXRgQEvuf5GUMluwxnca/mWb38IVHKQCwGlLxEUZkuXR
A8u+3QJAetjnsulKwQ1pfNQIgPOLoBqwEyhtjkgGkVrFqEfzT2z+uersxp2rCrNN
e/OUjg4ksvk6DF/NPR9TaTFitCm4kQJAeAbtRwun5z1BNF/5LlIVetxJkHKoOmCv
fYi5J/EAIiMZNTIm2U8QgKAg/BYymoFvEduvhj7L0kEtg07CtopYxQJBANW27X9y
DLuxwi6mYJauG1VQ6z4cjDm+TxuuOVcxba4q+VgHufycKyuqsSu6BaqiPeg2+2XF
Td22XO52Jc3EGw8=
-----END PRIVATE KEY-----

搞定之后,提交审核即可。

这些操作完成记得和极光的商务沟通下,不然会被打回 这些操作完成记得和极光的商务沟通下,不然会被打回 这些操作完成记得和极光的商务沟通下,不然会被打回

重要的事情说三遍~

客服小姐姐声音很甜~

极光同样为我们提供了俩种集成方案:

  • 本地工程配置
  • jcenter 自动集成步骤

2020 年了,必须自动集成搞起来呀~

2.1 配置权限

    <!-- Required -->
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
    <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
    <uses-permission android:name="android.permission.WRITE_SETTINGS"
        tools:ignore="ProtectedPermissions" />
    <uses-permission android:name="android.permission.GET_TASKS" />

    <!-- Optional -->
    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" /> <!-- 用于开启 debug 版本的应用在6.0 系统上 层叠窗口权限 -->
    <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
    <uses-permission android:name="android.permission.WAKE_LOCK" />
    <uses-permission android:name="android.permission.VIBRATE" />

2.2 处理兼容 Android P 默认限制使用 Http 请求

在 res 目录下新建 xml 目录,并新建一个名为 network_security_config.xml 的文件,拷贝如下内容到 xml 里:

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <base-config cleartextTrafficPermitted="true">
        <trust-anchors>
            <certificates src="system" />
        </trust-anchors>
    </base-config>
</network-security-config>

在 AndroidManifest.xml 中配置下:

    <application
        ...
        android:networkSecurityConfig="@xml/network_security_config" >
        
    </application>

2.3 检查 project 的 gradle 已支持 jcenter

一般而言,Android Studio 项目默认配置了 Jcenter,但是我们还是要检查一番。

点开工程下 gradle 文件,检查是否配置如下注释俩个地方。

buildscript {
    repositories {
        google()
        jcenter() // 这个
    }
    // ...
}

allprojects {
    repositories {
        google()
        jcenter() // 还有这个东东
    }
}
    // ...

2.4 在 module 的 gradle 中配置并添加依赖

android {
    // ...
    defaultConfig {
        // ...
        ndk {
            //兼容的 cpu 类型
            abiFilters 'armeabi'
        }
        // 极光配置
        manifestPlaceholders = [
                JPUSH_PKGNAME : applicationId,
                JPUSH_APPKEY : "App Key", //Portal上注册的包名对应的 appKey.
                JPUSH_CHANNEL : "developer-default", //暂时填写默认值即可.
        ]
    } 
}

dependencies {
    // ...
    implementation 'cn.jiguang.sdk:jverification:2.5.2'
    implementation 'cn.jiguang.sdk:jcore:2.1.4
}

关于依赖最新版本号可直接访问如下链接查看即可:

2.5 添加极光认证混淆配置

	-dontoptimize
	-dontpreverify
	
	-dontwarn cn.jpush.**
	-keep class cn.jpush.** { *; }
	-dontwarn cn.jiguang.**
	-keep class cn.jiguang.** { *; }
	-dontwarn com.cmic.**
	-keep class com.cmic.** { *; }
	-dontwarn com.unicom.**
	-keep class com.unicom.** { *; }
	-dontwarn cn.com.chinatelecom.**
	-keep class cn.com.chinatelecom.** { *; }

2.6 Application 中初始化极光认证

package com.hlq.jiguangdemo.app

import android.app.Application
import android.util.Log
import cn.jiguang.verifysdk.api.JVerificationInterface
import com.hlq.jiguangdemo.BuildConfig

/**
 * @author:heliquan
 * @date:2020-01-10 00:29
 * @desc:
 */
class BaseApplication : Application() {

    override fun onCreate() {
        super.onCreate()
        initJPushSetting()
    }

    /**
     * 初始化极光认证
     */
    private fun initJPushSetting() {
        JVerificationInterface.init(
            this,
            5000
        ) { code, msg ->
            val logMsg = when (code) {
                8000 -> {
                    "===> 极光认证初始化成功~! $msg"
                }
                else -> {
                    "===> 极光认证初始化失败!   $msg"
                }
            }
            Log.e("HLQ_Struggle", logMsg)
        }
        // 打开调试模式
        JVerificationInterface.setDebugMode(BuildConfig.DEBUG)
    }

}

别忘记 AndroidManifest 中配置 name 属性。

    <application
        ...
        android:name=".app.BaseApplication"
        ...>

三、实战

Android 6.0 动态申请权限,这个锅刚出来时那是相当痛苦啊,各种忧愁。同样,我这边有个设备是 Android 9.0 系统,那么在基于以上配置完成后,我们首先开始动态申请权限。

3.1 动态申请 READ_PHONE_STATE 权限

关于权限管理库,网上琳琅满目,在此特意推荐一款个人使用较为不错的动态权限管理库:

使用也是很 easy,Follow me~

由于个人习惯使用 Kotlin ,我们先进行 PermissionsDispatcher 基础配置 (app/build)

// ...

apply plugin: 'kotlin-kapt'

// ...

dependencies {
    // ...
    // 动态权限申请
    implementation "org.permissionsdispatcher:permissionsdispatcher:4.6.0"
    kapt "org.permissionsdispatcher:permissionsdispatcher-processor:4.6.0"
}

随后我们在要申请权限的地方新增注解并开始动态请求权限:

package com.hlq.jiguangdemo

import android.Manifest
import android.os.Bundle
import android.view.View
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import cn.jiguang.verifysdk.api.JVerificationInterface
import permissions.dispatcher.NeedsPermission
import permissions.dispatcher.OnShowRationale
import permissions.dispatcher.RuntimePermissions

// 第一步:新增 RuntimePermissions 注解,标明在编译时生成对应请求映射
@RuntimePermissions
class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
    }

    /**
     * 一键登录
     */
    public fun oneKeyLogin(view: View) {
        // 第四步:检查权限是否授予
        // 写这个之前记得 build 下,Runtime 运行时生成
        requestReadPhoneStateWithPermissionCheck()
    }

    private fun handlerOneKeyLogin() {
        // 这里开始编写实际的一键登录具体请求代码
    }

     /**
     * 权限请求回调
     */
    override fun onRequestPermissionsResult(
        requestCode: Int,
        permissions: Array<out String>,
        grantResults: IntArray
    ) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults)
        onRequestPermissionsResult(requestCode, grantResults)
    }

     /**
     * 第二步:指明对应要动态申请的权限,可声请多个权限
     */
    @NeedsPermission(Manifest.permission.READ_PHONE_STATE)
    fun requestReadPhoneState() {
        handlerOneKeyLogin()
    }

    /**
     * 第三步:解释说明申请权限具体作用,随后 Build
     */
    @OnShowRationale(Manifest.permission.READ_PHONE_STATE)
    fun onRequestReadPhoneStateRationale() {
        Toast.makeText(this, "请同意 App 请求授权!", Toast.LENGTH_SHORT).show()
    }

}

上述代码中,第一步以及第二步必须填写,而为了程序的健壮性,一般我们还会添加例如用户拒绝权限以及用户点击 "不再询问" 的后续操作流程,此处仅仅是为了体验极光的一键登录,暂时完善个动态申请权限即可。😂😂😂

3.2 使用前环境检测

在使用极光一键认证前,我们需要具备如下几个条件:

  • 极光一键认证 SDK 是否已初始化完毕;
  • 当前的手机网络环境是否可以使用认证(基于流量);
  • 是否授予对应权限,获取手机状态等

基于以上三点,我们开始完善 oneKeyLogin 一键登录方法:

    /**
     * 一键登录
     */
    public fun oneKeyLogin(view: View) {
        // 检查当前是否初始化成功极光 SDK
        if (JVerificationInterface.isInitSuccess()) {
            // 判断当前的手机网络环境是否可以使用认证。
            if (!JVerificationInterface.checkVerifyEnable(this)) {
                Toast.makeText(this, "[2016],msg = 当前网络环境不支持认证", Toast.LENGTH_SHORT).show()
                return
            }
            // 检查权限是否授予
            requestReadPhoneStateWithPermissionCheck()
        } else {
            Toast.makeText(this, "极光 SDK 尚未初始化成功~!", Toast.LENGTH_SHORT).show()
        }
    }

3.3 一键登录

首先我们查看 API 文档了解关键信息:

这点真心佩服极光开发工程师,几乎都是如果没有则自动获取,很是方便,尤其对于我这样又懒又菜的小白而言。

接口描述也很是贴心,一起来看:

而关于点击授权事件返回码,我们提前了解下,方便后续集成:

为了便于博文演示,还是决定输入一些返回结果,古老的 findViewById 不好玩了,尝尝 Kotlin 神器吧,来先激活一下(app/build):

    // 启动 Kotlin Android Extensions
    androidExtensions {
        experimental = true
    }

随后,我们开始完善我们的一键登录细节:

    /**
     * 处理一键登录细节
     */
    private fun handlerOneKeyLogin() {
        // 配置 Login Setting
        val settings = LoginSettings()
        settings.isAutoFinish = true // 登录完成后自动关闭授权页
        settings.timeout = 15 * 1000 // 设置超时时间,单位毫秒。 合法范围(0,30000],范围以外默认设置为10000
        settings.authPageEventListener = object : AuthPageEventListener() {
            override fun onEvent(cmd: Int, msg: String?) {
                Log.e(TAG, "===> onEvent code:$cmd msg:$msg")
            }
        }
        // 开始一键登录
        JVerificationInterface.loginAuth(
            this, settings
        ) { code, content, operator ->
            when (code) {
                6000 -> { // Login Token 获取成功

                }
                else -> {

                }
            }
            tv_login_result.text = "code:$code \n content:$content \n operator:$operator"
        }
    }

说的再天花烂坠,没个实际效果也是空说,我们 Run 一波,瞅瞅效果如何:

速度很快,有没有感觉到~

3.4 获取手机号

在上述步骤中,我们通过一键登录获取到了 loginToken,而在实际项目中,我们很多时候都需要获取到用户实际的手机号码,那么我们如何根据 loginToken 获取用户手机号呢?

别急,往下看~

这个时候就需要服务端童鞋帮助咯,提供一个接口,通过咱传递的 loginToken 获取对应的手机号码信息咯。

这里不作为重点,这里不具体演示 App 发请求获取手机号咯。

3.5 自定义授权页面 UI 样式

    /**
     * 自定义授权页面 UI 样式
     */
    private fun customUIStyle() {

        val qq = ImageView(this)
        qq.setImageResource(R.drawable.qq)

        val uiConfig = JVerifyUIConfig.Builder()
            .setAuthBGImgPath("main_bg")
            .setNavColor(-0xff7930)
            .setNavText("登录")
            .setNavTextColor(-0x1)
            .setNavReturnImgPath("umcsdk_return_bg")
            .setLogoWidth(70)
            .setLogoHeight(70)
            .setLogoHidden(false)
            .setNumberColor(-0xcccccd)
            .setLogBtnText("本机号码一键登录")
            .setLogBtnTextColor(-0x1)
            .setLogBtnImgPath("umcsdk_login_btn_bg")
            .setAppPrivacyOne("应用自定义服务条款一", "https://www.jiguang.cn/about")
            .setAppPrivacyTwo("应用自定义服务条款二", "https://www.jiguang.cn/about")
            .setAppPrivacyColor(-0x99999a, -0xff7a30)
            .setUncheckedImgPath("umcsdk_uncheck_image")
            .setCheckedImgPath("umcsdk_check_image")
            .setSloganTextColor(-0x666667)
            .setLogoOffsetY(50)
            .setLogoImgPath("logo_cm")
            .setNumFieldOffsetY(170)
            .setSloganOffsetY(230)
            .setLogBtnOffsetY(254)
            .setNumberSize(18)
            .setPrivacyState(false)
            .setNavTransparent(false)
            .addCustomView(
                qq, false
            ) { context, _ ->
                Toast.makeText(context, "动态注册的其他按钮222", Toast.LENGTH_SHORT).show()
            }
            .setPrivacyOffsetY(30).build()
        JVerificationInterface.setCustomUIWithConfig(uiConfig)
    }

随后在我们刚刚处理一键登录的方法中新增此项:

    /**
     * 处理一键登录细节
     */
    private fun handlerOneKeyLogin() {
        customUIStyle()
		// ...
    }

效果如下,为了演示,效果表介意咯。

有的小伙伴说了,那如果我想要添加自己的一些控件怎么办呢?

很 easy,参考如下截图即可,极光文档写的忒 6 咯,表怪我忒懒了。

3.6 设置授权页弹窗模式

这个更加 easy 了,由于忒晚了,这里就直接演示 low 到爆的效果咯,细节各位慢慢打磨吧~

先来瞅瞅极光小哥哥为我们搞好的文档:

Step 1:在 AndroidManifest 中添加授权页 Activity 并设置对应的 style

  <activity
      android:name="cn.jiguang.verifysdk.CtLoginActivity"
      android:configChanges="orientation|keyboardHidden|screenSize"
      android:launchMode="singleTop"
      android:screenOrientation="unspecified"
      android:theme="@style/ActivityDialogStyle" />

Step 2:配置具体弹窗 Style

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <style name="ActivityDialogStyle">
        <!--去掉action bar和标题栏-->
        <item name="android:windowActionBar">false</item>
        <item name="android:windowNoTitle">true</item>
        <!--背景透明-->
        <item name="android:windowIsTranslucent">true</item>
        <!--dialog圆角-->
        <item name="android:windowBackground">@drawable/jverify_dialog_bg</item>
    </style>
</resources>

Step 3:定义窗口圆角属性

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <corners android:radius="5dp"/>
</shape>

瞅一眼效果:

由于时间原因,暂时草草实现简单效果咯。想想明天的任务,头大。

四、叨叨几句

先说下测试的结果:

网络情况测试结果
开启 WiFi 关闭流量无法认证
开启 WiFi 开启流量一键登录成功
开启流量一键登录成功

特殊情况测试结果:

SIM 情况测试结果
有效 SIM 卡一键认证成功
无效 SIM 卡无法认证

认证速度,纯属个人瞎玩。测试依据,点击登录前记录当前时间戳,并与 SDK 返回时间对比,此处仅供参考。

网络情况测试结果
300 MB 宽带 WiFi 且开启流量218ms
移动网络98ms

其实整体流程而言,相对速度,等待期很短暂。

聊下集成上手度吧。

  • 上手 easy,文档写的相对来说蛮不错,新手通俗易懂;
  • 不足之处 Api 使用和文档有些出入,我遇到情况就是使用官网提供的版本发现有的方法没有,最后自己找的最新版本,这点有点坑。

简单说下极光一键登录流程吧:

当然里面包含很多的细节,比如说如何知晓当前流量归属哪儿个运营商,双卡操作等,这些涉及到我个人知识盲区,暂时不做了解。

整体来说,90 分,很不错。第一次知道极光便是推送,依稀记得简简单单几句话,推送搞定,当时那个兴奋呐,内心默默把极光小哥哥香了一遍。

最后,感谢极光小哥哥,让我再次感受并实实在在体验了一番。

参考资料

  1. 极光认证 Android 集成指南
  2. 极光 GitHub
  3. PermissionsDispatcher