Android进阶之微信扫码登录

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

首先想到的就是百度各种文章,当然去开发者平台申请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:+'

使用

        WxQUtils().create(object : WxQUtils.OnMListener {
            override fun onQSuccess(b: Bitmap?) {
                //获取二维码成功,给ImageView 赋值
                ivQe?.setImageBitmap(b)
            }

            override fun onUSuccess(b: WxQUtils.WxQBean) {
                //获取用户信息成功
                runOnUiThread {
                    Toast.makeText(this@WxLoginActivity, b.nickname, Toast.LENGTH_SHORT).show()
                }
            }

            override fun onError(msg: String?) {
                //出错了
                runOnUiThread { Toast.makeText(this@WxLoginActivity, msg, Toast.LENGTH_SHORT).show() }
            }
        })

WxQUtils 直接复制过来通过上面方法使用即可

/**
 * 微信扫码登录,工具类
 * */
public class WxQUtils implements OAuthListener{

    //获取微信二维码需要用到的对象
    private static IDiffDevOAuth oauth = null;
    //时间转换格式
    private static final String TIME_FORMAT = "yyyyMMddHHmmss";
    //开放平台创建应用产生的AppID
    private static final String appID = "xxxxxxxxxxxxxxxxxxxx";
    //开放平台创建应用产生的密钥
    private static final String appsecret = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";

    public void create(OnMListener listener){
        mOnListener = listener;
        //初始化获取二维码的对象
        oauth = DiffDevOAuthFactory.getDiffDevOAuth();
        //开始获取数据(第一步)
        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) {
                  mOnListener.onError("第一步网络请求出错~");
            }

            @Override
            public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
                ResponseBody mBean = response.body();
                if (mBean != null){
                    String res = mBean.string();//请求成功时返回的东西
                    WxQBean mData = new Gson().fromJson(res,WxQBean.class);
                    if (mData.getAccess_token() != null && !"".equals(mData.getAccess_token() )){
                        //拿到第一步数据,开始第二步
                        getTicket(mData.getAccess_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) {
                mOnListener.onError("第二步网络请求出错~");
            }

            @Override
            public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
                ResponseBody mBean = response.body();
                if (mBean != null){
                    //拿到数据进行数据组合
                    String res = mBean.string();//请求成功时返回的东西
                    WxQBean mData = new Gson().fromJson(res,WxQBean.class);
                    if (mData.getTicket() != 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 = String.format("appid=%s&noncestr=%s&sdk_ticket=%s&timestamp=%s", appID, noncestr, mData.getTicket(), 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,WxQUtils.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) {
                mOnListener.onError("第五步网络请求出错~");
            }

            @Override
            public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
                ResponseBody mBean = response.body();
                if (mBean != null){
                    String res = mBean.string();//请求成功时返回的东西
                    WxQBean mData = new Gson().fromJson(res,WxQBean.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) {
                mOnListener.onError("获取用户信息网络请求出错~");
            }

            @Override
            public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
                ResponseBody mBean = response.body();
                if (mBean != null){
                    String res = mBean.string();//请求成功时返回的东西
                    WxQBean mData = new Gson().fromJson(res,WxQBean.class);
                    mOnListener.onUSuccess(mData);
                }
            }
        });
    }


    @Override
    public void onAuthGotQrcode(String s, byte[] bytes) {
        //获取二维码图片。并显示出来,用户扫码二维码之后从回调(onAuthFinish)显示
        Bitmap bmp = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
        mOnListener.onQSuccess(bmp);
    }

    @Override
    public void onQrcodeScanned() {
    }

    @Override
    public void onAuthFinish(OAuthErrCode oAuthErrCode, String s) {
        //用户授权成功之后可以从这里拿到数据,或者错误信息
        //获取用户信息 第五步
        getUserData(s);
    }


    public interface OnMListener{
        void onQSuccess(Bitmap b); //获取二维码成功
        void onUSuccess(WxQBean b); //获取用户信息成功
        void onError(String msg); //失败
    }

    private static OnMListener mOnListener;


    //相关数据
    public static class WxQBean {
        private String access_token;
        private int expires_in;
        private String refresh_token;
        private String openid;
        private String scope;
        private String unionid;
        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 int errcode;
        private String errmsg;
        private String ticket;

        public String getAccess_token() {
            return access_token;
        }

        public void setAccess_token(String access_token) {
            this.access_token = access_token;
        }

        public int getExpires_in() {
            return expires_in;
        }

        public void setExpires_in(int expires_in) {
            this.expires_in = expires_in;
        }

        public String getRefresh_token() {
            return refresh_token;
        }

        public void setRefresh_token(String refresh_token) {
            this.refresh_token = refresh_token;
        }

        public String getOpenid() {
            return openid;
        }

        public void setOpenid(String openid) {
            this.openid = openid;
        }

        public String getScope() {
            return scope;
        }

        public void setScope(String scope) {
            this.scope = scope;
        }

        public String getUnionid() {
            return unionid;
        }

        public void setUnionid(String unionid) {
            this.unionid = unionid;
        }

        public String getNickname() {
            return nickname;
        }

        public void setNickname(String nickname) {
            this.nickname = nickname;
        }

        public int getSex() {
            return sex;
        }

        public void setSex(int sex) {
            this.sex = sex;
        }

        public String getLanguage() {
            return language;
        }

        public void setLanguage(String language) {
            this.language = language;
        }

        public String getCity() {
            return city;
        }

        public void setCity(String city) {
            this.city = city;
        }

        public String getProvince() {
            return province;
        }

        public void setProvince(String province) {
            this.province = province;
        }

        public String getCountry() {
            return country;
        }

        public void setCountry(String country) {
            this.country = country;
        }

        public String getHeadimgurl() {
            return headimgurl;
        }

        public void setHeadimgurl(String headimgurl) {
            this.headimgurl = headimgurl;
        }

        public List<String> getPrivilege() {
            return privilege;
        }

        public void setPrivilege(List<String> privilege) {
            this.privilege = privilege;
        }

        public int getErrcode() {
            return errcode;
        }

        public void setErrcode(int errcode) {
            this.errcode = errcode;
        }

        public String getErrmsg() {
            return errmsg;
        }

        public void setErrmsg(String errmsg) {
            this.errmsg = errmsg;
        }

        public String getTicket() {
            return ticket;
        }

        public void setTicket(String ticket) {
            this.ticket = ticket;
        }

    }


    //工具
    private static 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;
        }
    }
}

猜你喜欢

转载自blog.csdn.net/As_thin/article/details/131984390