更新日期:2020.07.02
依赖版本:
'cn.jiguang.sdk:jcore:2.3.4'
'cn.jiguang.sdk:jverification:2.6.2'
新版本对认证activity内容进行了包装,导致原本对反射调用失效,新的实现如下:
@SuppressLint("ResourceType")
override fun onActivityStarted(activity: Activity) {
if (activity::class.java == CtLoginActivity::class.java) {
val phoneNumber = activity.intent.getStringExtra("mobile")
val operatorType = activity.intent.getStringExtra("operator")
if (TextUtils.isEmpty(phoneNumber)) {
activity.onBackPressed()
} else {
val jsonObject = JSONObject()
jsonObject.putOpt("mobile", phoneNumber)
jsonObject.putOpt("operator", operatorType)
EventManagerImpl.get().post(null, SimpleEvent(AppConstant.EVENT_JPUSH_VERIFY, jsonObject))
try {
val realFiled = BaseActivity::class.java.getDeclaredField("ctLoginActivity")
realFiled.isAccessible = true
val realValue = realFiled.get(activity)
val p = cn.jiguang.verifysdk.activity.a::class.java.getDeclaredMethod("onClick", View::class.java)
val view = View(AppContext.get())
view.id = 1007
p.invoke(realValue, view)
} catch (e: Exception) {
LogUtil.e(e.toString())
activity.onBackPressed()
}
}
} else if (activity::class.java == LoginAuthActivity::class.java) {
val phoneNumber = activity.intent.getStringExtra("securityphone")
val type = activity.intent.getStringExtra("operatorType")
val operatorType = when (type) {
"1" -> {
"CM"
}
"3" -> {
"CT"
}
else -> {
"CU"
}
}
if (TextUtils.isEmpty(phoneNumber)) {
JVerificationInterface.dismissLoginAuthActivity()
} else {
val jsonObject = JSONObject()
jsonObject.putOpt("mobile", phoneNumber)
jsonObject.putOpt("operator", operatorType)
EventManagerImpl.get().post(null, SimpleEvent(AppConstant.EVENT_JPUSH_VERIFY, jsonObject))
try {
val realFiled = BaseActivity::class.java.getDeclaredField("ctLoginActivity")
realFiled.isAccessible = true
val realValue = realFiled.get(activity)
val p = cn.jiguang.verifysdk.l.a::class.java.getDeclaredMethod("p")
p.isAccessible = true
p.invoke(realValue)
} catch (e: Exception) {
LogUtil.e(e.toString())
JVerificationInterface.dismissLoginAuthActivity()
}
}
}
}
依赖版本:
'cn.jiguang.sdk:jcore:2.3.0'
'cn.jiguang.sdk:jverification:2.5.5'
基本流程:
- SDK初始化:api-->JPushInterface.init;注意一定必须要在主线程初始化,否则即使初始化成功,也会导致后面到步骤出错;报错是因为只有3大运营商的认证SDK初始化全部成功,极光认证的相关功能才可以使用,极光官方给出到说法是会在2.6.0版本修复。
- 提前获取预登录信息:api-->JPushInterface.preLogin;提前调用可以减少获取认证token的时间,这一步可以省略;调用时机可以在退出登录时,启动后发现未登录的时候,或者在打开登录页面时候(这个时候略微有点晚,可能会卡住页面)。
- 获取一键登录token:api-->JVerificationInterface.loginAuth;这个api会唤起极光的认证页面CtLoginActivity(电信和联通的认证页面)和LoginAuthActivity(移动的认证页面),所以首先需要在AndroidManifest中注册这两个activity;这两个activity中包含的主要信息有脱敏后手机号,对应运营协议,以及认证按钮等。由于获取认证token的api没有公开,默认只支持通过点击认证页面上的认证按钮,然后在loginAuth的回调中获取。虽然认证页面Activity的样式可以通过AndroidManifest设置style或者在api中配置对应setting来改变,但页面内容显示只能通过api的配置参数来调整,所以当公司设计的UI与极光默认UI相差较多时,改起来非常痛苦。
绕过极光认证页面实现完全自定义视图但方法如下:
1)设置activity生命监听registerActivityLifecycleCallbacks(ActivityLifecycleCallbacks callback),在onActivityStarted回调中对CtLoginActivity和LoginAuthActivity进行处理;(之所以不在onActivityCreated方法处理,是因为有几次未能拿到Intent内对数据)
2)如果监听到CtLoginActivity,从intent内拿取基本信息:手机号(加密过的,中间4位*),运营商类型( "CU" :联通,"CT":电信,"CM" :移动);通过反射获取onClick方法,然后模拟点击页面上的认证按钮,调用SDK内部的获取认证token的方法,结果将在在loginAuth方法回调中返回。
val phoneNumber = activity.intent.getStringExtra("mobile")
val operatorType = activity.intent.getStringExtra("operator")
if (TextUtils.isEmpty(phoneNumber)) {
activity.onBackPressed()
} else {
//将基本信息传递到页面上
val jsonObject = JSONObject()
jsonObject.putOpt("mobile", phoneNumber)
jsonObject.putOpt("operator", operatorType)
EventManagerImpl.get().post(null, SimpleEvent(AppConstant.EVENT_JPUSH_VERIFY, jsonObject))
try {
//模拟认证按钮点击
val p = activity.javaClass.getDeclaredMethod("onClick", View::class.java)
val view = View(AppContext.get())
view.id = 1007
p.invoke(activity, view)
} catch (e: Exception) {
activity.onBackPressed()
}
}
3)如果监听到LoginAuthActivity,从intent内拿取基本信息:手机号(加密过的,中间4位*),运营商类型( "3":电信,"1" :移动,其他:联通);通过反射获取类中的p方法,调用SDK内部的获取认证token的方法,结果将在在loginAuth方法回调中返回。
val phoneNumber = activity.intent.getStringExtra("securityphone")
val type = activity.intent.getStringExtra("operatorType")
//统一运营商标识
val operatorType = when (type) {
"1" -> {
"CM"
}
"3" -> {
"CT"
}
else -> {
"CU"
}
}
if (TextUtils.isEmpty(phoneNumber)) {
JVerificationInterface.dismissLoginAuthActivity()
} else {
//将基本信息传递到页面上
val jsonObject = JSONObject()
jsonObject.putOpt("mobile", phoneNumber)
jsonObject.putOpt("operator", operatorType)
EventManagerImpl.get().post(null, SimpleEvent(AppConstant.EVENT_JPUSH_VERIFY, jsonObject))
try {
//反射调用认证方法
val p = activity.javaClass.getDeclaredMethod("p")
p.isAccessible = true
p.invoke(activity)
} catch (e: Exception) {
JVerificationInterface.dismissLoginAuthActivity()
}
}
4)调用loginAuth方法,设置弹出极光认证页面不可见(我是将页面模式设置为弹窗模式,长宽均为0),通过VerifyListener监听方法结果(由认证页面返回);方法成功后会创建2)或3)中的Activity,经过上面几步的处理,可以拿到基本信息(手机号,运营商),认证token(返回到VerifyListener内),然后关闭了极光的认证页面。
另外,使用运营商认证必须要在页面上显示对应运营商的协议:
{
"运营商": "联通",
"协议名称": "《联通统一认证服务条款》",
"协议地址": "https://opencloud.wostore.cn/authz/resource/html/disclaimer.html?fromsdk=true"
}, {
"运营商": "电信"
"协议名称": "《天翼账号服务与隐私协议》"
"协议地址": "https://ctaccount.21cn.com/agreementList.html?hidetop=true"
}, {
"运营商": "移动",
"协议名称": "《中国移动认证服务条款》"
"协议地址": "https://wap.cmpassport.com/resources/html/contract.html"
}
- 现在应该已经拿到了页面需要的全部信息,可以自定义绘图了。
- 将第3步获取的token传递到后台验证;需要注意token是有有效时间的,如果token失效,可重复第3步,重新获取token。
2020-04-21