Android SDK 接入

本文是Android客户端SDK 集成说明文档。

1. 概述

官网下载SDK后进行解压,解压后包含:

  • Demo工程

  • 具体认证服务SDK

  • AppSignGet.apk,用来获取对应包名的APP签名信息

2. 前期准备

2.1 准备工作

如果应用开启了手机号认证服务, 请确保终端设备已经开启4G网络(联通、移动支持3G网络, 但接口耗时会增加),手机号认证授权之后,联通电信可立即使用, 移动需等待10分钟后使用。

2.2 运行demo工程

解压Android Demo工程, 需要将包名、applicationId、应用密钥、服务密钥(手机号认证)修改为正确的值。

2.3 搭建开发环境

应用必须运行在Android 4.1+平台上。

2.3.1 导入aar

1

2.3.2 使用aar

12

2.3.3 混淆忽略

若开启资源混淆,需要配置

"R.drawable.authsdk*",
"R.layout.authsdk*",
"R.anim.authsdk*",
"R.id.authsdk*",
"R.string.authsdk*",
"R.style.authsdk*",

-keep class com.nirvana.** { *; }
-keep class com.uc.crashsdk.** { *; }
-keep class com.idsmanager.doraemon.** { *; }

2.3.4 权限添加

<uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /> <!-- 检查wifi网络状态 -->
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <!-- 检查网络状态 -->
    <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" /> <!-- 切换网络通道 -->
    <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" /> <!-- 开关wifi状态,解决国内机型移动网络权限问题需要 -->
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <!-- 本地信息缓存 -->
    <!-- 可选权限 -->
    <uses-permission android:name="android.permission.READ_PHONE_STATE" />

2.3.5 Activity 声明

<!--联通电信授权页-->  
<activity
    android:name="com.mobile.auth.gatewayauth.LoginAuthActivity"  
    android:configChanges="orientation|keyboardHidden|screenSize"  
    android:exported="false"
    android:theme="@style/authsdk_activity_dialog"          使用弹窗模式必须添加!!!
    android:launchMode="singleTop" />  
<!--协议页面webview-->  
<activity  
    android:name="com.mobile.auth.gatewayauth.activity.AuthWebVeiwActivity"  
    android:configChanges="orientation|keyboardHidden|screenSize"  
    android:exported="false"  
    android:launchMode="singleTop" 
    android:screenOrientation="behind" />  
 <!--移动授权页-->  
 <activity  
    android:name="com.cmic.sso.sdk.activity.LoginAuthActivity"  
    android:configChanges="orientation|keyboardHidden|screenSize"
    android:exported="false"  
    android:launchMode="singleTop" />

2.3.6 Support 包

使用v4包com.android.support:support-v4版本高于25.4.0,或者v7包com.android.support:appcompat-v7版本高于25.4.0.

2.3.7 获取app md5 签名值

使用Android studio gradle,点击signingReport,得到MD5签名值,将冒号去掉并转小写。

说明

debug包和release包签名是不一样的,避免用debug的签名值用于生产测试。

111

3. SDK 调用说明

需要在APP中集成安全认证客户端SDK,并在服务端完成API对接。应用密钥和服务密钥获取请查看应用管理。

3.1 本机号码登录

12

  • 调用代码IDaaSDoraemonManager.getInstance获取安全认证SDK单例对象doraemonManager;

  • 调用doraemonManager的setDoraemonSDKInfo设置初始化应用秘钥参数;

  • 初始化手机号认证获取token实例mTokenListener =new TokenResultListener() {};

  • 初始化手机号认证SDK实例mPhoneNumberAuthHelper=PhoneNumberAuthHelper.getInstance(context, mToke nListener);

  • 设置手机号认证秘钥mPhoneNumberAuthHelper.setAuthSDKInfo(AUTH_SECRET);

  • 调用代码检测设备是否支持续本机号码登录mPhoneNumberAuthHelper.checkEnvAvailable(PhoneNumberAuthHelper.SERVICE_TYPE_LOGIN);

  • 调用本机号码登录方法mPhoneNumberAuthHelper.getLoginToken(this,timeout);

  • 获取到token后,调用doraemonManager.getMobileExtendParamsJson(token,null,newMobileExtendParamsService());获取最终请求invoke认证接口参数。

3.2 本机号码校验

123

  • 调用代码IDaaSDoraemonManager.getInstance获取安全认证SDK单例对象doraemonManager;

  • 调用doraemonManager的setDoraemonSDKInfo设置初始化应用秘钥参数;

  • 初始化手机号认证获取token实例mVerifyListener=newTokenResultListener() {};

  • 初始化手机号认证SDK实例mPhoneNumberAuthHelper= PhoneNumberAuthHelper.getInstance(context, mToke nListener);

  • 设置手机号认证秘钥mPhoneNumberAuthHelper.setAuthSDKInfo(AUTH_SECRET);

  • 调用代码检测设备是否支持本机号码校验mPhoneNumberAuthHelper.checkEnvAvailable(PhoneNumberAuthHelper.SERVICE_TYPE_LOGIN);

  • 调用手机号认证方法mPhoneNumberAuthHelper.setAuthListener(mVerifyListener); mPhoneNumberAuthHelper.getVerifyToken(timeout);

  • 获取到token后,调用doraemonManager.getMobileExtendParamsJson(token,null,newMobileExtendParamsService());获取最终请求invoke认证接口参数。

4. 手机号认证SDK方法说明

4.1 主类IDaaSDoraemonManager介绍

4.1.1 获取认证实例

/**
     * 获取认证实例
     *
     * @return 获取该类的单例实例对象
     */
    public static IDaaSDoraemonManager getInstance(Context context);

4.1.2 获取sdk版本号(getVersion)

/**
     * 获取sdk版本号
     *
     * @return 字符串,sdk版本号
     */
    public String getVersion();

4.1.3 设置阿里云安全认证应用秘钥(setDoraemonSDKInfo)
/**
     * 初始化SDK调用参数,app生命周期内调用一次
     *
     * @param base64EncodeKey app对应的秘钥
     */
    public void setDoraemonSDKInfo(String base64EncodeKey);

4.1.4 获取最终请求invoke认证接口参数
/**
     * 获取最终请求invoke认证接口参数
     *
     * @param accessToken 调用不同的服务获取到不同认证的信息(手机号认证、IFAA),例如手机号认证是accees_token, IFAA是Json字符串
     * @param phoneNumber 手机号码(只有本机号码校验才需要必传)
     * @param service     结果回调到主线程
     */
    public void getMobileExtendParamsJson(String accessToken, String phoneNumber, MobileExtendParamsService service);

4.2 主类PhoneNumberAuthHelper介绍

4.2.1 获取认证实例(getInstance)
/**
 * 获取手机号认证服务示例,此实例为单例,获取多次为同一对象
 * @param context       Android上下文
 * @param tokenListener 需要实现的获取token回调
 * @return PhoneNumberAuthHelper
 */  
public static PhoneNumberAuthHelper getInstance(Context context,  TokenResultListener tokenListener)

4.2.2 检查认证环境(checkAuthEnvEnable)

/**
 * SDK环境检查函数,检查终端是否⽀持手机号认证,通过TokenResultListener返回code
 * type 1:本机号码校验 2: ⼀键登录
 * 600024 终端⽀持认证
 * 600013 系统维护,功能不可⽤
 */
 public void checkEnvAvailable(@IntRange(from = 1, to = 2) int type)

4.2.3 加速本机号码校验(accelerateVerify)
/**  
 public void accelerateVerify(int overdueTime, final PreLoginResultListener listener);

4.2.4 本机号码校验token(getVerifyToken)
/**
* 获取认证token
*
* @param totalTimeout 超时时间 单位ms
*/
 public void getVerifyToken(final int totalTimeout)

4.2.5 加速授权页拉起(accelerateLoginPage)
/**
* 加速授权⻚唤起
*
* @param overdueTime 预取号有效期
* @param listener    预取号回调
*/
public void accelerateLoginPage(final int overdueTime, final PreLogin ResultListener listener)

4.2.6 本机号码登录唤起授权页(getLoginToken)

/**
* 获取登录token 调起本机号码登录授权⻚⾯,在⽤户授权后获取本机号码登录的Token
*
* @param totalTimeout 超时时间 单位ms
*/
public void getLoginToken(final Context context, final int totalTimeout)

4.2.7 退出授权页(quitLoginPage)
/**
* 退出授权认证⻚
* sdk完成回调之后不会关闭授权⻚,需要开发者主动调⽤quitLoginPage退出授权⻚
*/
public void quitLoginPage()

4.2.8 关闭授权页loading(hideLoginLoading)

/**
* 关闭授权⻚loading
* sdk完成回调之后不会关闭loading,需要开发者主动调⽤hideLoginLoading关闭loading
*/
public void hideLoginLoading()

4.2.9 返回默认上⽹卡运营商(getCurrentCarrierName)
/**
* 返回默认上⽹卡运营商
*
* @return CMCC、CUCC、CTCC
*/
public String getCurrentCarrierName()

4.2.10 使用xml添加自定义控件至本机号码登录授权页 (addAuthRegisterXmlConfig)
/**
* 添加⾃定义View
*
* @param xmlConfig
*/
public void addAuthRegisterXmlConfig(AuthRegisterXmlConfig xmlConfig)

⼀次add,XML内绘制的⾃定义控件全部添加完成。

初始化 addAuthRegisterXmlConfig 类时需要先调静态内部类Builder()⾥⾯的 2 个⽅法。

  • setLayout: 开发者传⼊⾃定义的控件的xml资源ID。

  • AbstractPnsViewDelegate:授权⻚使⽤xml添加⾃定义布局时,可以配合该Delegate类实现xml中相 关view的操作,⽐如事件监听以及动态UI改动等等,当xml对应的view加载后SDK将调⽤ onViewCreated(View)⽅法通知view已经创建OK,此时可以获取xml中的view并进⾏相关事件绑定等 操作。

说明

onViewCreated(View)中返回的View不能用强引用,或者使用完需及时释放,否则容易造成内存泄漏。

调用示例

mAlicomAuthHelper.addAuthRegisterXmlConfig(new AuthRegisterXmlConfig .Builder()
 .setLayout(R.layout.xxxxxx, new AbstractPnsViewDelegate() {
    @Override public void onViewCreated(View view) {
        //这⾥返回的View,不建议⽤强引⽤,或者使用完及时释放,否则容易造成内存泄漏
        findViewById(R.id.xxxx).setOnClickListener(new View.OnClickL istener() {
            @Override public void onClick(View v) {
                //do something
            }
        });
    }
})
.build());

4.2.11 添加代码编写的自定义控件至登录授权页(addAuthRegistViewConfig)
/**
* 动态添加控件
*
* @param viewID 开发者⾃定义控件名称
* @param viewConfig 配置开发者⾃定义控件的控件来源、位置和处理逻辑
*/
public void addAuthRegistViewConfig(String viewID, AuthRegisterViewConfig viewConfig)

说明

每次调用 getVerifyToken 授权请求之前,都需初始化⼀次 AuthRegisterViewConfig,因为在授权页关闭时都会清空注⼊进去的 AuthRegisterViewConfig, 具体实现请见demo⼯程。

初始化 AuthRegisterViewConfig 类时需要先调静态内部类Builder()⾥⾯的 3 个⽅法。

  • setView: 开发者传⼊⾃定义的控件,开发者需要提前设置好控件的布局属性,SDK 只⽀持 RelativeLayout 布局。

  • setRootViewId:设置控件的位置,⽬前SDK 授权⻚允许在3个位置插⼊开发者控件。RootViewId.ROOT_VIEW_ID_TITLE_BAR,标题栏。RootViewId.ROOT_VIEW_ID_BODY,授权⻚空⽩处。RootViewId.ROOT_VIEW_ID_NUMBER,授权⻚号码掩码区域。

  • setCustomInterface:设置控件事件。public Builder setCustomInterface(CustomInterface customInterface)。

调⽤示例:

mAlicomAuthHelper.addAuthRegistViewConfig("switch_acc_tv", new AuthRe gisterViewConfig.Builder()
.setView(mRL)
.setRootViewId(AuthRegisterViewConfig.RootViewId.ROOT_VIEW_ID_BODY)
.setCustomInterface(new CustomInterface() {
   @Override
    public void onClick(Context context) {
    startActivityForResult(new Intent(context, SecondActivity.class), 1234);
    }
 }).build());

获取 token 成功之后,需把通过setView()注⼊进去的view 置为 null。

4.2.12 ⼀键登录修改授权页主题(setAuthUIConfig)
/** * 修改授权⻚⾯主题,开发者可以通过 此⽅法修改授权⻚⾯主题,需在 getLoginToken接⼝ 之前调⽤ * * @param authUIConfig 登录授权⻚UI⾃定义配配置 */ public void setAuthUIConfig(AuthUIConfig authUIConfig)

调⽤示例:

setAuthUIConfig(new AuthUIConfig.Builder()
.setLogBtnText("本机号码登录")
.setLogBtnClickableColor(Color.BLACK)
.setLogBtnUnClickableColor(Color.BLUE)
.setLogBtnTextColor(Color.WHITE).setLogoHidden(false)
.setNavColor(0xff026ED2)
.setNavText("免密登录")
.setNavTextColor(Color.WHITE)
.setNumberColor(Color.WHITE)
.setNumberSize(28)
.setNumberColor(0xff000000).create());

5. 手机号认证SDK 回调说明

5.1 获取token 回调

  • 回调返回的ret都通过 TokenRet tokenRet = JSON.parseObject(ret, TokenRet.class) 解析;

  • 授权⻚唤起成功、获取token成功都会回调onTokenSuccess⽅法(要区分两次成功可以通过返回码来 区分);

  • 获取token失败会回调onTokenFailed.

示例代码

mTokenListener = new TokenResultListener() {
 @Override
 public void onTokenSuccess(final String ret) {
 MainActivity.this.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    /*
                     *   setText just show the result for get token。
                     *   use ret to verfiy number。
                     */
                    //ResultCode#CODE_START_AUTHPAGE_SUCCESS是授权⻚唤起成功码,若不需要处理,则过滤
                     if (ResultCode.CODE_START_AUTHPAGE_SUCCESS.equa ls(tokenRet.getCode())) {
                           return;
                    }

                    TokenRet tokenRet = JSON.parseObject(ret, TokenR et.class);
                    if (tokenRet != null) {
                        token = tokenRet.getToken();
                    }
                    mAlicomAuthHelper.quitLoginPage();
                }
            });
        }

        @Override
        public void onTokenFailed(final String ret) {
            MainActivity.this.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    /*
                     *  setText just show the result for get token
                     *  do something when getToken failed, such as u se sms verify code.
                     */
                    TokenRet tokenRet = JSON.parseObject(ret, TokenR et.class);
                    mAlicomAuthHelper.quitLoginPage();
                }
            });
        }
    };

5.2 加速唤起授权页/加速本机号码校验回调
public interface PreLoginResultListener {
/**
* @param  vendor 返回预取成功运营商
*/
void onTokenSuccess(String vendor);
/**
* @param vendor 返回预取失败运营商
* @param ret 返回失败原因
*/
void onTokenFailed(String vendor, String ret);
}

预取号回调示例代码

mPreLoginResultListener = new PreLoginResultListener() {
            @Override
            public void onTokenSuccess(final String s) {
                MainActivity.this.runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                       /*
                        *  推荐在登录⻚初始化的时候调⽤
                        *  如果没有合适的调⽤时机
                        *  不调⽤此接⼝也没关系
                        *  千万不要APP冷启动初始化就调⽤!!!!
                        *  不要调⽤完预取号后⻢上调⽤getLoginToken!!!
                        *  最好判断⽤户是否登录,若已登录不要使⽤此接 ⼝!!!!
                        */
                        mRetTV.setText("预取号成功:" + s);
                    }
                });
            }

            @Override
            public void onTokenFailed(final String s, final String s 1) {
                /*
                 *  预取号调⽤失败
                 *  不⽤太关注,还是可以直接在⽤户点击"登录"时,调⽤getLoginT oken
                 */
                mRetTV.setText("预取号失败:" + s + s1);
            }
        });
     }
}

5.3 控件点击事件回调

授权页控件点击事件通过此回调返回

public interface AuthUIControlClickListener {
/**
*
* @param code     控件点击事件code
* @param context  Android上下⽂
* @param jsonObj  点击事件返回的具体内容,不同控件返回的事件内容有所不同
*/
void onClick(String code, Context context, JSONObject jsonObj);
}

示例代码

mAlicomAuthHelper.setUIClickListener(new AuthUIControlClickListener( ) {
            @Override
            public void onClick(String code, Context context, JSONObj ect jsonObj) {
                Log.e("xxxxxx", "OnUIControlClick:code=" + code + ", jsonObj=" + (jsonObj ==     null ? "" : jsonObj.toJSONString()));
}
});

5.4 建议代码调用顺序

/*
*   1.初始化获取token实例
*/
mTokenListener = new TokenResultListener() {}

/*
*   2.初始化SDK实例
*/
mAlicomAuthHelper = PhoneNumberAuthHelper.getInstance(context, mToke nListener);
/*
*   3.设置SDK秘钥
*/
mAlicomAuthHelper.setAuthSDKInfo();
/*
*   4.检测终端⽹络环境是否⽀持手机号认证,根据回调结果确定是否可以使⽤本机号码登录功能
*/
mAlicomAuthHelper.checkEnvAvailable(PhoneNumberAuthHelper#SERVICE_TY PE_LOGIN);

/*
*   5.若步骤4返回true,则根据业务情况,调⽤预取号或者本机号码登录接⼝
*     详⻅demo接⼊⼯程
*/
mAlicomAuthHelper.getLoginToken(context, 5000);

5.5 本机号码登录获取⼿机号

当成功获取到getLoginToken成功获取token后,将token传递至服务端,服务端携带token调用阿里云的getMobile接口即可进行最终的取号操作。

5.6 本机号码校验结果

当成功获取到getVerifyToken成功获取token后,将token传递至服务端,服务端携带token调用阿里云的VerifyMobile接口即可进行最终的取号操作。

6. Demo 示例

package com.idsmanager.doraemonapplication;

import android.app.ProgressDialog;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import android.widget.EditText;
import android.widget.Toast;

import com.idsmanager.doraemon.IDaaSDoraemonManager;
import com.idsmanager.doraemon.service.MobileExtendParamsService;
import com.idsmanager.doraemonapplication.config.BaseUIConfig;
import com.mobile.auth.gatewayauth.PhoneNumberAuthHelper;
import com.mobile.auth.gatewayauth.ResultCode;
import com.mobile.auth.gatewayauth.TokenResultListener;
import com.mobile.auth.gatewayauth.model.TokenRet;

public class MainActivity extends AppCompatActivity {
    private static final String TAG = "MainActivity";
    //需要替换为自己的AUTH_SECRET和APP_KEY信息
    public static final String AUTH_SECRET = "IzVsTj8yEifpKEjasDeKbz580U4diLNQT3H6aWPjTBFWWZYlKLUQaoIfdMrLv8Zg/YoSQokBZ+1O/RU95RGyKwf/YUQIhG+8jkkF6I+5IcWy9GsGqS+a/ipOZfkTCJGiw9DkMlXDGp2mDpSITCddqBB6Fbpis+7AS71JkZRl7+q5EldwSCsZeKiqhO8jD9+tERkKp8FpEjbVjKRPEl/hw7Q0PicoYdNeXTir6noRhpMA3wtquA1pv8/s9TCs0dpfgpVYL6rERtzU1dPlRkHIq4c7TYMUVttR9e3xG2MxOmCJVWwqmPGsSrMPpQyfPC0c";
    public static final String APP_KEY = "MG10MDdoQWFBZ00zNUxteg==";
    private PhoneNumberAuthHelper mPhoneNumberAuthHelper;
    private TokenResultListener tokenResultListener;
    private TokenResultListener mVerifyListener;
    private BaseUIConfig mUIConfig;
    private ProgressDialog mProgressDialog;
    private EditText etPhone;
    String phoneNumber;
    IDaaSDoraemonManager doraemonManager;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        etPhone =findViewById(R.id.et_phone);
        doraemonManager = IDaaSDoraemonManager.getInstance(MainActivity.this);
        doraemonManager.setDoraemonSDKInfo(APP_KEY);
        //本机号码登录
        findViewById(R.id.btn_one_login).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        oneLogin();

                    }
                });
            }
        });
        //本机号码校验
        findViewById(R.id.btn_phone_check).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                phoneCheck();
            }
        });
    }
    //本机号码校验
    private void phoneCheck() {
        phoneNumber = etPhone.getText().toString();
        //判断手机号是否合法
        if (!TextUtils.isEmpty(phoneNumber)) {
            mVerifyListener = new TokenResultListener() {
                @Override
                public void onTokenSuccess(String s) {
                    Log.i(TAG, "获取token成功:" + s);
                    try {
                        TokenRet pTokenRet = TokenRet.fromJson(s);
                        final String token = pTokenRet.getToken();
                        hideLoadingDialog();
                        if (ResultCode.CODE_SUCCESS.equals(pTokenRet.getCode()) && !TextUtils.isEmpty(token)) {
                            doraemonManager.getMobileExtendParamsJson(token, null, new MobileExtendParamsService() {
                                @Override
                                public void invoke(final String base64EncodedMobileExtendParamsJson, final String base64EncodedMobileExtendParamsJsonSign) {
                                    Log.d(TAG, "invoke() called with: base64EncodedMobileExtendParamsJson = [" + base64EncodedMobileExtendParamsJson + "], base64EncodedMobileExtendParamsJsonSign = [" + base64EncodedMobileExtendParamsJsonSign + "]");
                                    MainActivity.this.runOnUiThread(new Runnable() {
                                        @Override
                                        public void run() {
                                            Toast.makeText(MainActivity.this, "invoke成功,base64EncodedMobileExtendParamsJson=" + base64EncodedMobileExtendParamsJson + ";base64EncodedMobileExtendParamsJsonSign=" + base64EncodedMobileExtendParamsJsonSign, Toast.LENGTH_LONG).show();
                                        }
                                    });
                                }

                                @Override
                                public void success(final boolean success) {
                                    Log.d(TAG, "success() called with: success = [" + success + "]");
                                    MainActivity.this.runOnUiThread(new Runnable() {
                                        @Override
                                        public void run() {
                                            Toast.makeText(MainActivity.this, "success,success=" + success, Toast.LENGTH_LONG).show();
                                        }
                                    });
                                }

                                @Override
                                public void message(final String error) {
                                    Log.d(TAG, "message() called with: error = [" + error + "]");
                                    MainActivity.this.runOnUiThread(new Runnable() {
                                        @Override
                                        public void run() {
                                            Toast.makeText(MainActivity.this, "message,error=" + error, Toast.LENGTH_LONG).show();
                                        }
                                    });
                                }
                            });
                            Log.d(TAG, "onTokenSuccess() called with: (tokenRet.getToken() = [" + (token + "]"));
                        }
                        mPhoneNumberAuthHelper.setAuthListener(null);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }

                @Override
                public void onTokenFailed(final String s) {
                    Log.i(TAG, "获取token失败:" + s);
                    MainActivity.this.runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            Toast.makeText(MainActivity.this, "获取token失败:" + s, Toast.LENGTH_LONG).show();
                        }
                    });
                    hideLoadingDialog();
                    setResult(2);
                    mPhoneNumberAuthHelper.setAuthListener(null);
                }
            };
            mPhoneNumberAuthHelper = PhoneNumberAuthHelper.getInstance(getApplicationContext(), mVerifyListener);
            mPhoneNumberAuthHelper.getReporter().setLoggerEnable(true);
            mPhoneNumberAuthHelper.setAuthSDKInfo(AUTH_SECRET);
            showLoadingDialog("正在进行本机号码校验");
            numberAuth(5000);
        } else {
            Toast.makeText(MainActivity.this, "请输入手机号", Toast.LENGTH_LONG).show();
        }
    }
    //本机号码登录
    private void oneLogin() {
        tokenResultListener = new TokenResultListener() {
            @Override
            public void onTokenSuccess(String s) {
                Log.d(TAG, "onTokenSuccess() called with: s = [" + s + "]");
                TokenRet tokenRet = null;
                try {
                    tokenRet = TokenRet.fromJson(s);
                    if (ResultCode.CODE_START_AUTHPAGE_SUCCESS.equals(tokenRet.getCode())) {
                        Log.i("TAG", "唤起授权页成功:" + s);
                        hideLoadingDialog();
                    }

                    if (ResultCode.CODE_SUCCESS.equals(tokenRet.getCode())) {
                        hideLoadingDialog();
                        mPhoneNumberAuthHelper.quitLoginPage();
                        Toast.makeText(MainActivity.this, "本机号码登录获取token成功,token=" + tokenRet.getToken(), Toast.LENGTH_LONG).show();

                        doraemonManager.getMobileExtendParamsJson(tokenRet.getToken(), null, new MobileExtendParamsService() {
                            @Override
                            public void invoke(String base64EncodedMobileExtendParamsJson, String base64EncodedMobileExtendParamsJsonSign) {
                                Log.d(TAG, "invoke() called with: base64EncodedMobileExtendParamsJson = [" + base64EncodedMobileExtendParamsJson + "], base64EncodedMobileExtendParamsJsonSign = [" + base64EncodedMobileExtendParamsJsonSign + "]");
                            }

                            @Override
                            public void success(boolean success) {
                                Log.d(TAG, "success() called with: success = [" + success + "]");
                            }

                            @Override
                            public void message(String error) {
                                Log.d(TAG, "message() called with: error = [" + error + "]");
                            }
                        });
                        Log.d(TAG, "onTokenSuccess() called with: (tokenRet.getToken() = [" + (tokenRet.getToken() + "]"));
                    }
                } catch (Exception e) {
                    Log.d(TAG, "onTokenSuccess() called with: e) = [" + e + "]");
                    e.printStackTrace();
                    hideLoadingDialog();
                }
            }

            @Override
            public void onTokenFailed(String s) {
                Log.d(TAG, "onTokenFailed() called with: s = [" + s + "]");
                mPhoneNumberAuthHelper.setAuthListener(null);
            }
        };
        mPhoneNumberAuthHelper = PhoneNumberAuthHelper.getInstance(MainActivity.this, tokenResultListener);
        mPhoneNumberAuthHelper.getReporter().setLoggerEnable(true);
        mPhoneNumberAuthHelper.setAuthSDKInfo(AUTH_SECRET);
        mPhoneNumberAuthHelper.checkEnvAvailable(PhoneNumberAuthHelper.SERVICE_TYPE_AUTH);
        mUIConfig = BaseUIConfig.init(MainActivity.this, mPhoneNumberAuthHelper);
        mUIConfig.configAuthPage();
        getLoginToken(5000);
    }




    public void numberAuth(int timeout) {
        mPhoneNumberAuthHelper.setAuthListener(mVerifyListener);
        mPhoneNumberAuthHelper.getVerifyToken(timeout);
    }

    /**
     * 拉起授权页
     *
     * @param timeout 超时时间
     */
    public void getLoginToken(int timeout) {
        mPhoneNumberAuthHelper.getLoginToken(this, timeout);
        showLoadingDialog("正在唤起授权页");
    }

    public void showLoadingDialog(String hint) {
        if (mProgressDialog == null) {
            mProgressDialog = new ProgressDialog(this);
            mProgressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
        }
        mProgressDialog.setMessage(hint);
        mProgressDialog.setCancelable(true);
        mProgressDialog.show();
    }

    public void hideLoadingDialog() {
        if (mProgressDialog != null) {
            mProgressDialog.dismiss();
        }
    }
}

FAQ

1.首次取号时,为什么APP网络通信正常,手机号认证一直失败?

  • 首先检测sim卡有没有欠费,能不能通过移动网络上网。

  • Android 国内某些厂商的系统,wifi 网络权限与移动网络权限是分开管理的,检测APP是否仅仅只有WLAN 网络权限,而移动蜂窝网络权限缺失。

2.checkEnvAvailable函数返回false?

  • 检测是否有插入sim卡

  • 检测蜂窝网络开关是否开启

3. 获取token失败,一般有哪些原因?
  • 手机设置检测网络制式,中国移动支持2G/3G/4G、中国联通支持3G/4G、中国电信支持4G,但各大运营商网络在4G网络成功率较高

  • 接口超时时间是否过短,建议3000~5000ms

  • SIM能否欠费,是否可以蜂窝网络上网。

  • 切换卡的过程中,需要等网络稳定后,再使用认证登录功能。

4.Android双卡手机本机号码登录过程中,本机号码登录逻辑是怎么样的?

  • 使用默认上网卡进行一键登录认证。

5.返回错误码600005,手机终端不安全有哪些原因?

  • ⼿机⽹络是否连接了代理。

  • ⼿机是否处于hook状态,或者安装了相关的hook框架。

  • APP是否处于attached状态。

  • ⼿机是否被root。

  • 是否在模拟器环境中运⾏。

  • APP是否处于调试状态,使⽤ getReporter.setLoggerEnable(true) 可以关闭此项检测。

6.权限问题

若出现权限相关问题,请检查 APP的权限是否申请正常。正常引用 aar,权限会自动 merge。若权限没有 merge,需要添加如下权限。

<uses-permission
    android:name="android.permission.INTERNET" />
<uses-permission
    android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission
    android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission
    android:name="android.permission.CHANGE_NETWORK_STATE" />

7. 非法手机号码

部分试点纯流量卡,未实名的手机号码会返回非法手机号码的情况。

8. VPN报错

用户开启VPN后使用SDK进行本机号码登录的时候,联通号码会出现源IP错误,电信号码会出现800008错误,移动号码会出现103111错误。请关闭VPN或者打开飞行模式再关闭后进行重试。

9. 页面非法修改

添加悬浮窗控件遮挡隐私协议、登录按钮以及掩码,或者将字体颜色设置为透明,sdk回调600005页面非法修改。

10. 当使用移动卡请求本机号码登录不成功,出现以下报错信息时:

ontokenfaild{"code":"600011","msg":"vendorCode:200025, msg:获得的手机授权码失败:{\"resultCode\":\"200025\",\"authType\":\"1\",\"authTypeDes\":\"WIFI下网关鉴权\",\"resultDesc\":\"发生未知错误\"}","requestCode":0,"vendorName":"CMCC"}请检查依赖v4包com.android.support:support-v4版本是否高于25.4.0或者v7包com.android.support:appcompat-v7版本是否高于25.4.0。

11. 当使用移动卡请求本机号码登录不成功,出现以下报错信息时

ontokenfaild{"code":"600011","msg":"vendorCode:200028, msg:获得的手机授权码失败:{\"resultCode\":\"200028\”,\”authType\":\"1\",\"authTypeDes\”:\”网络鉴权\",\"resultDesc\”:\”网络异常\”}”,”requestCode":0,"vendorName":"CMCC"}

  • 请检查清单文件application标签下是否配置了android:usesCleartextTraffic="true",配置android:networkSecurityConfig文件

  • 如果设置了networkSecurityConfig文件,请在networkSecurityConfig文件里面配置

<application
        android:name=".DemoApplication"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme"
        android:usesCleartextTraffic="true"
        android:networkSecurityConfig="@xml/config"
        android:requestLegacyExternalStorage="true">
</application>

<network-security-config>
    <domain-config cleartextTrafficPermitted="true">
        <domain includeSubdomains="true">cmpassport.com</domain>
    </domain-config>
</network-security-config>

12. setSDKAuthSDKInfo的秘钥如何获取?

登录阿里云控制台,进入认证方案管理,点击”秘钥“进行复制,建议维护在APP服务端。此秘钥不是阿里云的AccessKey,AccessSecret。

13. 内存泄漏

1. Toast内存泄漏

  • 协议没勾选点击⼀键登录按钮显示Toast,退出授权⻚⻚出现内存泄漏。解决办法是 AuthUIConfig.setLogBtnToastHidden(true)隐藏默认Toast,根据点击事件的code⾃⼰显示 Toast即可。

  • ⻚⾯⾮法修改,当授权⻚号码栏、⼀键登录Button、协议栏出现重叠或者遮挡时点击⼀键登录按钮,显示Toast⻚ ⾯⾮法修改。解决办法,查看图层解决重叠即可。

2. TokenResultListener内存泄露

  • SDK内部会持有外部设置进来的TokenResultListener,在本机号码登录功能使⽤完毕之后通过 PhoneNumberAuthHelper.setAuthListener(null)将回调置空即可。