作为一个开发者,开发任何一个App都少不了登陆功能(个别特例除外),传统的一般只有3种:账号(邮箱)密码、短信验证、扫码登陆。但是这三种方式都太繁琐,如果忘记密码,就可能需要向你的密保邮箱或者手机发送验证码,重新填写密码,然后再去登陆,这个过程很麻烦。不光是一个开发者,作为一个用户来说,我也深受其害(当然也有一些app使用人脸解锁、指纹识别、手势解锁等功能,但是不太常见)。后来上网查阅资料,移动、电信、联通都有各自的一键登录SDK出台,同时市面上也有一些其它的一键登录的SDK出现。由于我是sharesdk的老用户,无意间发现它们官网有一个mob秒验,我就体验了一下,下面详细的讲解一下我的整个使用过程。
一、开发者账号和管理中心
(一)打开官网注册账号,然后登陆进去。点击右上角的产品中心
。
注:为了更好地使用产品,请填写实名认证信息。
(二)点击开发者平台
,进入管理控制台
。
(三)创建应用,应用名称建议和你开发的应用名称保持一致。
(四)完善应用信息,便于审核通过。
(五)添加秒验功能模块
点击秒验
右侧的+
,然后在弹窗中选择确定添加
。
然后点击OK
。
(六)提交审核
点击秒验
,点击立即审核
。
然后填写应用类型、所属行业、应用简介、平台、包名和签名。
获取签名MD5字符串的3种方式:
方式1:这里着重强调一下,如果你不知道你的App的签名是什么,可以使用这个工具类。(项目创建签名之后,获取了签名,再来这个
应用审核
填写签名信息。)
/**
* 描述:
* 获取签名信息工具类
*/
public class PackageUtils {
private static final char[] hexDigits = {48, 49, 50, 51, 52, 53, 54, 55,
56, 57, 97, 98, 99, 100, 101, 102};
private static final String TAG = "PackageUtils".getClass().getSimpleName();
/**
* 获取当前应用程序的包名
*
* @param context 上下文对象
* @return 返回包名
*/
public String getAppPackageName(Context context) {
//当前应用pid
int pid = android.os.Process.myPid();
//任务管理类
ActivityManager manager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
//遍历所有应用
List<ActivityManager.RunningAppProcessInfo> infos = manager.getRunningAppProcesses();
for (ActivityManager.RunningAppProcessInfo info : infos) {
if (info.pid == pid) {
return info.processName;
}
}
return "";
}
/**
* 获取32位的包签名
*/
public String getAppSignature(Activity activity) {
PackageManager manager = activity.getPackageManager();
/** 通过包管理器获得指定包名包含签名的包信息 **/
PackageInfo packageInfo = null;
try {
// 传入包名
packageInfo = manager.getPackageInfo(getAppPackageName(activity), PackageManager.GET_SIGNATURES);
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
/******* 通过返回的包信息获得签名数组 *******/
Signature[] signatures = packageInfo.signatures;
String result = hexdigest(signatures[0].toByteArray());
if (result != null) {
Log.d(TAG, "签名: " + result);
return result;
} else {
Log.d(TAG, "没获得签名,请重试");
}
return null;
}
public String hexdigest(byte[] paramArrayOfByte) {
try {
MessageDigest localMessageDigest = MessageDigest.getInstance("MD5");
localMessageDigest.update(paramArrayOfByte);
byte[] arrayOfByte = localMessageDigest.digest();
char[] arrayOfChar = new char[32];
int i = 0;
int j = 0;
while (true) {
if (i >= 16) {
return new String(arrayOfChar);
}
int k = arrayOfByte[i];
int m = j + 1;
arrayOfChar[j] = hexDigits[(0xF & k >>> 4)];
j = m + 1;
arrayOfChar[m] = hexDigits[(k & 0xF)];
i++;
}
} catch (Exception localException) {
}
return null;
}
}
然后在你的首个 Activity
的 onCreate()
或者 Application
的 onCreate()
方法里面加入两行代码,通过日志就可以查看了。
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 加入两行代码
String appSignature = new PackageUtils().getAppSignature(MainActivity.this);
Log.d("MainActivity ", "32位的签名为: " + appSignature);
}
}
方式2:如果嫌弃麻烦,可以直接用命令行获取。
- 前提:1.把jdk里面的`keytool.exe所在路径加入环境变量。2.生成签名文件,这里的命令最后一个参数需要签名文件存放路径。
keytool -list -v -keystore C:\Users\Administrator\Desktop\data.jks
方式3:点击Gradle的Task里面的signingReport
(七)审核中
审核完成就可以愉快的开发了。
二、安装SDK包和使用
根目录的gradle文件:
module的gradle文件:
下载SDK包:
出现一个错误:
解决问题:
经过这几步我们已经配置好了,接下来就是编写代码了。
三、核心代码解析
初始化SDK
在我们的Application文件里面onCreate方法里声明初始化:
MobSDK.init(this);
或者直接在Manifest.xml
里面appliaction节点添加属性android:name="com.mob.MobApplication"
。
预登陆:提前调用预登录接口,可以加快免密登录过程,提高用户体验
SecVerify.preVerify(new OperationCallback() {
@Override
public void onComplete(Object data) {
// Nothing to do
}
@Override
public void onFailure(VerifyException e) {
// Nothing to do
}
});
免密登录:
SecVerify.verify(new MyVerifyCallback());
// 核心类
class MyVerifyCallback extends VerifyCallback{
@Override
public void onOtherLogin() {
// 用户点击“其他登录方式”,处理自己的逻辑
CommonProgressDialog.dismissProgressDialog();
Toast.makeText(MainActivity.this, "其他账号登录", Toast.LENGTH_SHORT).show();
}
@Override
public void onComplete(VerifyResult data) {
CommonProgressDialog.dismissProgressDialog();
if (data != null) {
Log.d(TAG, data.toJSONString());
// 获取授权码成功,将token信息传给应用服务端,再由应用服务端进行登录验证,此功能需由开发者自行实现
CommonProgressDialog.showProgressDialog(MainActivity.this);
// 自己的登陆逻辑
LoginTask.getInstance().login(data, new ResultListener<LoginResult>() {
@Override
public void onComplete(LoginResult data) {
CommonProgressDialog.dismissProgressDialog();
Log.d(TAG, "Login success. data: " + data.toJSONString());
vibrate();
// 服务端登录成功,跳转成功页
gotoSuccessActivity(data);
}
@Override
public void onFailure(DemoException e) {
// 登录失败
Log.e(TAG, "login failed", e);
CommonProgressDialog.dismissProgressDialog();
// 错误码
int errCode = e.getCode();
// 错误信息
String errMsg = e.getMessage();
// 更详细的网络错误信息可以通过t查看,请注意:t有可能为null
Throwable t = e.getCause();
String errDetail = null;
if (t != null) {
errDetail = t.getMessage();
}
String msg = "获取授权码成功,应用服务器登录失败" + "\n错误码: " + errCode + "\n错误信息: " + errMsg;
if (!TextUtils.isEmpty(errDetail)) {
msg += "\n详细信息: " + errDetail;
}
if (!devMode) {
msg = "当前网络异常";
}
Toast.makeText(MainActivity.this, msg, Toast.LENGTH_SHORT).show();
}
});
}
}
@Override
public void onFailure(VerifyException e) {
// 登录失败
CommonProgressDialog.dismissProgressDialog();
Log.e(TAG, "verify failed", e);
// 错误码
int errCode = e.getCode();
// 错误信息
String errMsg = e.getMessage();
// 更详细的网络错误信息可以通过t查看,请注意:t有可能为null
Throwable t = e.getCause();
String errDetail = null;
if (t != null) {
errDetail = t.getMessage();
}
String msg = "错误码: " + errCode + "\n错误信息: " + errMsg;
if (!TextUtils.isEmpty(errDetail)) {
msg += "\n详细信息: " + errDetail;
}
if (!devMode) {
msg = "当前网络异常";
if (errCode == VerifyErr.C_ONE_KEY_USER_CANCEL_GRANT.getCode()
|| errCode == VerifyErr.C_LACK_OF_PERMISSIONS.getCode()
|| errCode == VerifyErr.C_NO_SIM.getCode()
|| errCode == VerifyErr.C_UNSUPPORTED_OPERATOR.getCode()) {
msg = errMsg;
}
}
Toast.makeText(MainActivity.this, msg, Toast.LENGTH_SHORT).show();
}
}
private void gotoSuccessActivity(LoginResult data) {
Intent i = new Intent(this, SuccessActivity.class);
i.putExtra(Const.EXTRAS_DEMO_LOGIN_RESULT, data);
startActivityForResult(i, REQUEST_CODE);
}
private void vibrate() {
Vibrator vibrator = (Vibrator) this.getSystemService(Context.VIBRATOR_SERVICE);
if (vibrator != null) {
if (Build.VERSION.SDK_INT >= 26) {
VibrationEffect vibrationEffect = VibrationEffect.createOneShot(500, 20);
vibrator.vibrate(vibrationEffect);
} else {
vibrator.vibrate(500);
}
}
}
自定义授权页(这个不是重点就不做过多展开了)
更多详情,请查看官方文档:http://wiki.mob/secverify集成文档
四、Demo示例图解
点击 一键认证
加载进度提示:
点击登陆(默认是同意协议的)
验证成功
提示: 第一次验证验证比较慢,大概5秒左右。当第一次验证成功之后,再次进入App,不到1秒就可以验证登陆。
五、注意事项:
(一)必须打开流量,秒验是通过4G网络来确定手机号的。我刚开始不知道,打开的wifi,未开启流量导致识别失败,后来开启了流量之后,OK了。
(二)别忘了加权限。
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
<uses-permission android:name="android.permission.GET_TASKS" />
(三)如果是双卡手机,请确保拨号和上网都使用同一张SIM卡,否则会出错误。(我手机的两张卡分别:一张移动,一张联通的SIM卡)
请看以下截图:
1.拨号移动,上网联通。
- 设置拨号移动,上网联通:
- 运行出错示例图:
2.拨号联通,上网移动。
- 设置拨号联通,上网移动:
- 运行出错示例图:
六、免密登陆大致流程
我国三大运营商都有对应的免密登录的SDK出台,我搜索了移动、电信、联通的关于一键登录的SDK文档,发现移动的文档写的最完整,电信的一般,联通的官网打不开了。
具体文档链接如下:
- 移动 - 互联网能力开放平台
- 电信 - 天翼账号开放平台
- 联通 - WO+ 开放平台 http://open.wo ? 打不开了?啥回事?
一键登录的系统交互流程都是差不多的,主要分为四个步骤:
- 第一步,号码认证SDK初始化。
- 第二步,唤起授权页。
- 第三步,同意授权并登录。
- 第四步,发起取号。
具体如下图所示:
七、优缺点:
(一)优点:
- 1.用户输入手机号码或获得用户授权后,一键即可完成认证,方便快捷,省时省力,减少登陆时的耗时。大概1秒即可登陆,太方便了。
- 2.减少忘记账号密码时的短信和邮箱麻烦,你只要有手机号就可以登陆了。比普通的手机短信验证方便多了。
- 3.支持中国三大运营商全网手机号码认证,一点接入,全国全网覆盖。
- 4.适用于以手机号进行注册、登陆、安全风控的场景,可实现用户无感知校验,拓宽校验场景。
- 5.针对双卡手机,可以一键切换手机号码验证,也挺方便的。
(二)缺点:
- 1.通话和网络的SIM卡必须为同一张卡。否则会导致验证失败。
- 2.请确保打开流量,否者会导致验证失败。
- 3.请确保手机卡正常使用,停机欠费可能导致验证失败。
- 4.官方文档建议完善一下,入口有点不好找,建议完善一下。另外建议把常见问题和开发者最关心的问题都加上去。
至于是否收费,以及收费标准如何,这就不是我能够操心的事了,请看官方文档或者咨询相关客服。我只是个开发人员,既然mob秒验这么好用的话,我当然会支持的。
八、相关资料下载:
- 下载中心:http://www.mob/download
- 集成文档:http://wiki.mob/secverify集成文档/
- 示例代码:https://github/MobClub/SecVerify-for-Android
更多推荐
一键登录只需1秒,赶紧了解一下
发布评论