遇到新需求要搭建微信扫码登录功能,这篇文章是随着我的编码过程一并写的,希望能够帮助有需求的人和以后再次用到此功能的自己。
首先想到的就是百度各种文章,当然去开发者平台申请AppID和密钥是必不可少的,等注册好发现需要创建应用以及审核(要官网,流程图及其他信息),想着先写一个Demo开发着,还不需要这么麻烦,
通过一篇文章发现微信还有测试账号 -> 微信扫码登录详细操作流程(微信公众平台开发)
那不正中我心怀,根据现有的比较清晰的文章写出了逻辑 -> Android安卓开发集成微信第三方扫描二维码登录-超级无敌具详细
将我申请的测试 AppID 和密钥 投进去之后,在回调的时候一直走不到 onAuthGotQrcode 方法里面去,看 oauth.auth() 获取二维码方法返回的也是 True,每次都直接走到 onAuthFinish 方法里面,这不扯呢,AppID 和 密钥都是申请好的,代码逻辑也是参考了多篇文章,理论上也没啥问题,而且获取方法也返回的 True,但是每次确报以下错误 ->
E/MicroMsg.SDK.GetQRCodeResult: resp errcode = -21
E/MicroMsg.SDK.GetQRCodeTask: onPostExecute, get qrcode fail, OAuthErrCode = OAuthErrCode:-1
遇到问题就解决呗,去文档上找错误码 -21 -1 啥的没找到,mmp,去百度此类错误,发现遇到的人不少,给出解决方案的都没有,但是有一篇文章的错误和我的差不多,也给了解决办法 ->
android 获取微信二维码 DiffDevOAuth.auth
果然没有解决,文档里还有说字段大小写字母错误的,参数名字错误的,这些我都检查过了, 但是通过错误可以看出来就是获取二维码失败了吧,失败的原因有很多,可能我们不是同一个问题导致的
在网上地毯式搜索之后发现了一个可以解释过去的问题 微信还分公众平台和开放平台,公众平台是以小程序为业务线的,我一瞅我这测试账号不就是从 公众平台申请的吗,难不成是这个问题,早晚都得申请应用,那就先申请了吧,这里要注意下,申请的话需要公司信息(可能还要往公司账户打一笔费用验证),正经官网,APP流程图,要提前做好准备,那就等到几天时间,等正经id和密钥出来再说吧,
过了差不多三四天,应用审核通过了,但是要申请开通微信登录,需要进行开发者资质认证,审核费用三百块,还要填写企业各种信息,营业执照,信用代码啥的
生成密钥还需要绑定了管理员银行卡的微信扫码验证
差不多经历了四五天,终于拿到了AppID 和密码,也开通了微信登录权限, 激动人心的时刻到了,我把正经的数据塞到那套逻辑里,二维码正常显示出来了!获取用户数据也是正常的!
总结:
微信公众平台申请的测试 AppID 和密钥 不能用于微信开放平台的操作,比如APP扫码登录,支付等
接下来我将我的源码贴出来(本人以下代码正常运行,如有需要只需替换 appID、appsecret即可,其他逻辑亲测可用),尽量写了详细的注释,或者通过上面我贴的链接也可以的
导入依赖比不可少
implementation 'com.squareup.okhttp3:okhttp:3.12.0'
implementation 'com.google.code.gson:gson:2.8.9'
//微信登录
implementation 'com.tencent.mm.opensdk:wechat-sdk-android:+'
需要的实体类先建好
GetAccessTokenBean
public class GetAccessTokenBean {
String access_token;
int expires_in;
}
GetTicketBean
public class GetTicketBean {
int errcode;
String errmsg;
String ticket;
int expires_in;
}
UserData
public class UserData {
private String access_token;
private int expires_in;
private String refresh_token;
private String openid;
private String scope;
private String unionid;
public void setAccess_token(String access_token) {
this.access_token = access_token;
}
public String getAccess_token() {
return access_token;
}
public void setExpires_in(int expires_in) {
this.expires_in = expires_in;
}
public int getExpires_in() {
return expires_in;
}
public void setRefresh_token(String refresh_token) {
this.refresh_token = refresh_token;
}
public String getRefresh_token() {
return refresh_token;
}
public void setOpenid(String openid) {
this.openid = openid;
}
public String getOpenid() {
return openid;
}
public void setScope(String scope) {
this.scope = scope;
}
public String getScope() {
return scope;
}
public void setUnionid(String unionid) {
this.unionid = unionid;
}
public String getUnionid() {
return unionid;
}
}
UserInfo
public class UserInfo {
private String openid;
private String nickname;
private int sex;
private String language;
private String city;
private String province;
private String country;
private String headimgurl;
private List privilege;
private String unionid;
public void setOpenid(String openid) {
this.openid = openid;
}
public String getOpenid() {
return openid;
}
public void setNickname(String nickname) {
this.nickname = nickname;
}
public String getNickname() {
return nickname;
}
public void setSex(int sex) {
this.sex = sex;
}
public int getSex() {
return sex;
}
public void setLanguage(String language) {
this.language = language;
}
public String getLanguage() {
return language;
}
public void setCity(String city) {
this.city = city;
}
public String getCity() {
return city;
}
public void setProvince(String province) {
this.province = province;
}
public String getProvince() {
return province;
}
public void setCountry(String country) {
this.country = country;
}
public String getCountry() {
return country;
}
public void setHeadimgurl(String headimgurl) {
this.headimgurl = headimgurl;
}
public String getHeadimgurl() {
return headimgurl;
}
public void setPrivilege(List privilege) {
this.privilege = privilege;
}
public List getPrivilege() {
return privilege;
}
public void setUnionid(String unionid) {
this.unionid = unionid;
}
public String getUnionid() {
return unionid;
}
}
EncryptUtils
public class EncryptUtils {
public static String getSHA(String info) {
byte[] digesta = null;
try {
// 得到一个SHA-1的消息摘要
MessageDigest alga = MessageDigest.getInstance("SHA-1");
// 添加要进行计算摘要的信息
alga.update(info.getBytes());
// 得到该摘要
digesta = alga.digest();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
// 将摘要转为字符串
String rs = byte2hex(digesta);
return rs;
}
private static String byte2hex(byte[] b) {
String hs = "";
String stmp = "";
for (byte aB : b) {
stmp = (Integer.toHexString(aB & 0XFF));
if (stmp.length() == 1) {
hs = hs + "0" + stmp;
} else {
hs = hs + stmp;
}
}
return hs;
}
}
获取二维码
public class MainActivity extends AppCompatActivity implements OAuthListener {
//图片控件,用于显示二维码
private ImageView ivQrCode;
//获取微信二维码需要用到的对象
IDiffDevOAuth oauth = null;
//时间转换格式
private final String TIME_FORMAT = "yyyyMMddHHmmss";
//开放平台创建应用产生的AppID
private final String appID = "xxxxxxxxxxxxxxx";
//开放平台创建应用产生的密钥
private final String appsecret = "xxxxxxxxxxxxxxxxxxxxxxxxxxx";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//初始化获取二维码的对象
oauth = DiffDevOAuthFactory.getDiffDevOAuth();
//获取图片控件对象
ivQrCode = findViewById(R.id.iv_qr_code);
//开始获取数据(第一步)
getAccessToken();
}
private void getAccessToken() {
//第一步请求
OkHttpClient client = new OkHttpClient();
Request.Builder builder = new Request.Builder();
String getAccessToken = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + appID + "&secret=" + appsecret;
Request request1 = builder.get().url(getAccessToken)
.build();
client.newCall(request1).enqueue(new Callback() {
@Override
public void onFailure(@NonNull Call call, @NonNull IOException e) {
}
@Override
public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
ResponseBody mBean = response.body();
if (mBean != null){
String res = mBean.string();//请求成功时返回的东西
GetAccessTokenBean mData = new Gson().fromJson(res,GetAccessTokenBean.class);
if (mData.access_token != null && !"".equals(mData.access_token)){
//拿到第一步数据,开始第二步
getTicket(mData.access_token);
}
}
}
});
}
private void getTicket(String l){
//第二步网络请求
OkHttpClient client = new OkHttpClient();
Request.Builder builder = new Request.Builder();
Request request1 = builder.get().url("https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=" + l + "&type=2")
.build();
client.newCall(request1).enqueue(new Callback() {
@Override
public void onFailure(@NonNull Call call, @NonNull IOException e) {
}
@Override
public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
ResponseBody mBean = response.body();
if (mBean != null){
//拿到数据进行数据组合
String res = mBean.string();//请求成功时返回的东西
GetTicketBean mData = new Gson().fromJson(res,GetTicketBean.class);
if (mData.ticket != null){
StringBuilder str = new StringBuilder();
Random random = new Random();
for (int i = 0; i < 8; i++){
str.append(random.nextInt(10));
}
String noncestr = str.toString();
String timeStamp = new SimpleDateFormat(TIME_FORMAT).format(new Date());
String string1 = java.lang.String.format("appid=%s&noncestr=%s&sdk_ticket=%s×tamp=%s", appID, noncestr, mData.ticket, timeStamp);
String sha = EncryptUtils.getSHA(string1);
//开始进行第三步
sign(noncestr,timeStamp,sha);
}
}
}
});
}
private void sign(String noncestr,String timeStamp,String sha){
if (oauth != null){
oauth.removeAllListeners();
oauth.stopAuth();
oauth.detach();
//第四步,获取二维码,获取到的二维码从回调(onAuthGotQrcode)里面显示
Boolean s = oauth.auth(appID,"snsapi_userinfo",noncestr,timeStamp,sha,this);
}
}
private void getUserData(String c){
//开始第五步
OkHttpClient client = new OkHttpClient();
Request.Builder builder = new Request.Builder();
Request request1 = builder.get().url("https://api.weixin.qq.com/sns/oauth2/access_token?appid="+ appID
+"&secret=" + appsecret + "&code=" +c+ "&grant_type=authorization_code")
.build();
client.newCall(request1).enqueue(new Callback() {
@Override
public void onFailure(@NonNull Call call, @NonNull IOException e) {
}
@Override
public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
ResponseBody mBean = response.body();
if (mBean != null){
String res = mBean.string();//请求成功时返回的东西
UserData mData = new Gson().fromJson(res,UserData.class);
if (mData.getOpenid() != null && !Objects.equals(mData.getOpenid(), "") &&
mData.getAccess_token() != null && !Objects.equals(mData.getAccess_token(), "")){
//拿到数据,最后一步获取用户信息
getUserInfo(mData.getOpenid(),mData.getAccess_token());
}
}
}
});
}
private void getUserInfo(String openID, String aToken){
//获取用户信息
OkHttpClient client = new OkHttpClient();
Request.Builder builder = new Request.Builder();
Request request1 = builder.get().url("https://api.weixin.qq.com/sns/userinfo?access_token=" +aToken+"&openid=" + openID)
.build();
client.newCall(request1).enqueue(new Callback() {
@Override
public void onFailure(@NonNull Call call, @NonNull IOException e) {
}
@Override
public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
ResponseBody mBean = response.body();
if (mBean != null){
String res = mBean.string();//请求成功时返回的东西
UserInfo mData = new Gson().fromJson(res,UserInfo.class);
}
}
});
}
@Override
public void onAuthGotQrcode(String s, byte[] bytes) {
//获取二维码图片。并显示出来,用户扫码二维码之后从回调(onAuthFinish)显示
Bitmap bmp = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
if (ivQrCode != null){
ivQrCode.setImageBitmap(bmp);
}
}
@Override
public void onQrcodeScanned() {
}
@Override
public void onAuthFinish(OAuthErrCode oAuthErrCode, String s) {
//用户授权成功之后可以从这里拿到数据,或者错误信息
//获取用户信息 第五步
getUserData(s);
}
}
activity_main