作为一个开发者,开发任何一个App都少不了登陆功能(个别特例除外),传统的一般只有3种:账号(邮箱)密码、短信验证、扫码登陆。但是这三种方式都太繁琐,如果忘记密码,就可能需要向你的密保邮箱或者手机发送验证码,重新填写密码,然后再去登陆,这个过程很麻烦。不光是一个开发者,作为一个用户来说,我也深受其害(当然也有一些app使用人脸解锁、指纹识别、手势解锁等功能,但是不太常见)。后来上网查阅资料,移动、电信、联通都有各自的一键登录SDK出台,同时市面上也有一些其它的一键登录的SDK出现。由于我是sharesdk的老用户,无意间发现它们官网有一个mob秒验,我就体验了一下,下面详细的讲解一下我的整个使用过程。
产品中心
。注:为了更好地使用产品,请填写实名认证信息。
开发者平台
,进入管理控制台
。点击秒验
右侧的+
,然后在弹窗中选择确定添加
。
然后点击OK
。
点击秒验
,点击立即审核
。
然后填写应用类型、所属行业、应用简介、平台、包名和签名。
这里着重强调一下,如果你不知道你的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);
}
}
如果嫌弃麻烦,可以直接用命令行获取。
keytool -list -v -keystore C:\Users\Administrator\Desktop\data.jks
经测试,这两者获取的签名信息是一致的。
审核完成就可以愉快的开发了。
根目录的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.com/secverify集成文档
点击 一键认证
加载进度提示:
点击登陆(默认是同意协议的)
验证成功
提示:第一次验证验证比较慢,大概5秒左右。当第一次验证成功之后,再次进入App,不到1秒就可以验证登陆。
<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" />
请看以下截图:
1.拨号移动,上网联通。
2.拨号联通,上网移动。
我国三大运营商都有对应的免密登录的SDK出台,我搜索了移动、电信、联通的关于一键登录的SDK文档,发现移动的文档写的最完整,电信的一般,联通的官网打不开了。
具体文档链接如下:
一键登录的系统交互流程都是差不多的,主要分为四个步骤:
具体如下图所示:
优点:
缺点:
至于是否收费,以及收费标准如何,这就不是我能够操心的事了,请看官方文档或者咨询相关客服。我只是个开发人员,既然mob秒验这么好用的话,我当然会支持的。