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:+'

需要的实体类先建好

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




    


你可能感兴趣的:(android,微信扫码登陆)