Android进阶之微信扫码登录

news/2024/11/22 21:42:30/

遇到新需求要搭建微信扫码登录功能,这篇文章是随着我的编码过程一并写的,希望能够帮助有需求的人和以后再次用到此功能的自己。

首先想到的就是百度各种文章,当然去开发者平台申请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<String> 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<String> privilege) {this.privilege = privilege;}public List<String> 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";//开放平台创建应用产生的AppIDprivate final String appID = "xxxxxxxxxxxxxxx";//开放平台创建应用产生的密钥private final String appsecret = "xxxxxxxxxxxxxxxxxxxxxxxxxxx";@Overrideprotected 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() {@Overridepublic void onFailure(@NonNull Call call, @NonNull IOException e) {}@Overridepublic 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() {@Overridepublic void onFailure(@NonNull Call call, @NonNull IOException e) {}@Overridepublic 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&timestamp=%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() {@Overridepublic void onFailure(@NonNull Call call, @NonNull IOException e) {}@Overridepublic 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() {@Overridepublic void onFailure(@NonNull Call call, @NonNull IOException e) {}@Overridepublic 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);}}});}@Overridepublic void onAuthGotQrcode(String s, byte[] bytes) {//获取二维码图片。并显示出来,用户扫码二维码之后从回调(onAuthFinish)显示Bitmap bmp = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);if (ivQrCode != null){ivQrCode.setImageBitmap(bmp);}}@Overridepublic void onQrcodeScanned() {}@Overridepublic void onAuthFinish(OAuthErrCode oAuthErrCode, String s) {//用户授权成功之后可以从这里拿到数据,或者错误信息//获取用户信息 第五步getUserData(s);}
}

activity_main

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context=".MainActivity"><ImageViewandroid:id="@+id/iv_qr_code"app:layout_constraintTop_toTopOf="parent"app:layout_constraintBottom_toBottomOf="parent"app:layout_constraintStart_toStartOf="parent"app:layout_constraintEnd_toEndOf="parent"android:layout_width="200px"android:layout_height="200px"/></androidx.constraintlayout.widget.ConstraintLayout>

http://www.ppmy.cn/news/986020.html

相关文章

美国过境签证申请也要面签吗?

随着人们出国旅行的增加&#xff0c;美国过境签证成为了一个热门话题。对于许多人来说&#xff0c;了解美国过境签证的流程和要求非常重要。在这篇文章中&#xff0c;知识人网小编将介绍美国过境签证是否需要面签&#xff0c;以及相关的注意事项。 首先&#xff0c;让我们来了解…

css中flex后文本溢出的问题

原因&#xff1a; 为了给flex item提供一个合理的默认最小尺寸&#xff0c;flex将flex item的min-width 和 min-height属性设置为了auto flex item的默认设置为&#xff1a; min-width&#xff1a; auto 水平flex布局 min-height&#xff1a;auto 垂直flex布局 解决办法&…

flutter开发实战-自定义相机camera功能

flutter开发实战-自定义相机camera功能。 Flutter 本质上只是一个 UI 框架&#xff0c;运行在宿主平台之上&#xff0c;Flutter 本身是无法提供一些系统能力&#xff0c;比如使用蓝牙、相机、GPS等&#xff0c;因此要在 Flutter 中调用这些能力就必须和原生平台进行通信。 实现…

综合案例(面向对象)

使用面向对象思想完成数据读取和处理基于面向对象思想重新认知第三方库使用&#xff08;PyEcharts&#xff09; 数据分析案例 某公司&#xff0c;有2份数据文件&#xff0c;现需要对其进行分析处理&#xff0c;计算每日的销售额并以柱状图表的形式进行展示。 数据内容 综合案…

14.python设计模式【模板方法模式】

内容&#xff1a;定义一个操作中的算法的骨架&#xff0c;而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重定义该算法某特定步骤。 角色&#xff1a; 抽象类&#xff08;AbstractClass&#xff09;&#xff1a;定义抽象的原子操作&#xff08;钩子…

安全初级—正则表达式、This关键字、闭包

文章目录 正则表达式字面量字符元字符转义符特殊字符字符类预定义模式重复类量词符贪婪模式修饰符 This关键字使用场合使用注意点避免多层 this避免数组处理方法中的 this避免回调函数中的 this 绑定 this 的方法Function.prototype.call()Function.prototype.apply()Function.…

解决Spring循环依赖

当我们使用Spring框架构建应用程序时&#xff0c;循环依赖是一个常见的问题。循环依赖指的是两个或多个Bean之间相互依赖&#xff0c;形成了一个循环的依赖关系。在这篇博客中&#xff0c;我们将深入探讨Spring循环依赖的原理&#xff0c;包括原因、解决方案和示例代码。 什么…

内存函数讲解

&#x1f495;"痛苦难以避免&#xff0c;而磨难可以选择。"-->村上春树&#x1f495; 作者&#xff1a;Mylvzi 文章主要内容&#xff1a;数据在内存中的存储 内存函数就是管理内存数据的函数&#xff0c;包含于头文件<string.h>中 1.memcpy函数-->内存…