微信开放平台开发系列文章:

微信开放平台开发第三方授权登陆(一):开发前期准备

微信开放平台开发第三方授权登陆(二):PC网页端

微信开放平台开发第三方授权登陆(三):Android客户端

微信开放平台开发第三方授权登陆(四):微信公众号

微信开放平台开发第三方授权登陆(五):微信小程序

 

目录​​​​​​​

一、需求

二、开发流程

三、开发使用的技术及工具

四、具体实现步骤

1.前端(Android)

1)Android微信授权登录开发环境配置

2)引导用户点击登录并授权

3)接收微信服务端返回的数据并向服务端发送请求

4)根据服务端返回数据进行解析并显示给前端Android页面

2.服务端(Java)

1).统一返回JSON

2).相关参数配置:

3).请求响应逻辑

4).根据Token获取用户信息:

五、注意事项:

六、应用关键参数位置


当微信开放平台开发第三方授权登陆(一):开发前期准备完成后,已经获取到应用的AppID和AppSecret、且已经成功申请到微信登陆功能。可以进行第三方登陆授权开发。

注意:

目前移动应用上微信登录只提供原生的登录方式,需要用户安装微信客户端才能配合使用

对于Android应用,建议总是显示微信登录按钮,当用户手机没有安装微信客户端时,请引导用户下载安装微信客户端

 

开放平台中创建移动应用时,需要添加包名(一定要和开发的包名完全一致,不能是填写的包名的子包,否则微信无法回调成功)

安装验签工具:Gen_Signature_Android2.apk。

填写包名,然后会生成应用签名,填写应用签名就可以了。

 

一、需求

拥有第三方微信登录功能,并获取到用户信息。

二、开发流程

Android移动应用:(App唤醒微信客户端授权登陆)

1. 应用发起微信授权登录请求,用户允许授权应用后,微信会拉起应用或重定向到第三方网站(服务端),并且带上授权临时票据code参数;

2. 通过code参数加上AppID和AppSecret等,通过API换取access_token;

3. 通过access_token进行接口调用,获取用户基本数据资源或帮助用户实现基本操作。

微信开放平台开发第三方授权登陆(三):Android客户端_第1张图片

获取用户基本信息的流程

 

三、开发使用的技术及工具

1、.后端采用IDEA2017 进行开发

2、使用Android Studio 3.1.3 进行开发

3、后端必须基于JDK7以上版本,采用JDK8开发,前端基于Android SDK4.4

4、使用fastJson对json数据进行处理

四、具体实现步骤

1.前端(Android)

目录结构如下:

微信开放平台开发第三方授权登陆(三):Android客户端_第2张图片

1)Android微信授权登录开发环境配置

I.添加微信依赖

Android Studio环境

在build.gradle文件中,添加依赖

dependencies {

    compile 'com.tencent.mm.opensdk:wechat-sdk-android-with-mta:+'

}

dependencies {

    compile 'com.tencent.mm.opensdk:wechat-sdk-android-without-mta:+'

}

Eclipse环境下:

在工程中新建一个libs目录,将开发工具包中libs目录下的libammsdk.jar复制到该目录中(如下图所示,建立了一个名为SDK_Sample 的工程,并把jar包复制到libs目录下)。

微信开放平台开发第三方授权登陆(三):Android客户端_第3张图片

右键单击工程,选择Build Path中的Configure Build Path...,选中Libraries这个tab,并通过Add Jars...导入工程libs目录下的libammsdk.jar文件。(如下图所示)。

微信开放平台开发第三方授权登陆(三):Android客户端_第4张图片

在需要使用微信终端API的文件中导入相应的类。

import com.tencent.mm.opensdk.openapi.WXTextObject;

 

 

II. AndroidManifest.xml 设置

添加如下权限支持:

                        

III.若要混淆代码,为保证sdk正常使用,需在配置proguard.cfg(proguard-rule.pro):

# wechat-keep class com.tencent.mm.opensdk.** {*;}-keep class com.tencent.wxop.** {*;}-keep class com.tencent.mm.sdk.** {*;}

2)引导用户点击登录并授权

I.layout.xml

添加button:

        

II.监听button点击事件,拉起微信授权页

       findViewById(R.id.wechat_login_btn).setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                if (isWXAppInstalledAndSupported()) {  // 用户是否安装微信客户端                    // send oauth request                    final SendAuth.Req req = new SendAuth.Req();                    req.scope = "snsapi_userinfo";                    req.state = "none";                    api.sendReq(req);                    finish();                } else {                    // TODO: 这里需要引导用户去下载微信客户端                    Toast.makeText(WXEntryActivity.this, "用户没有安装微信", Toast.LENGTH_SHORT).show();                }            }        });

III.用户手机是否安装微信客户端检查  

  private boolean isWXAppInstalledAndSupported() {        IWXAPI msgApi = WXAPIFactory.createWXAPI(this, null);        msgApi.registerApp(Constants.APP_ID);        boolean sIsWXAppInstalledAndSupported = msgApi.isWXAppInstalled()                && msgApi.isWXAppSupportAPI();        return sIsWXAppInstalledAndSupported;    }

3)接收微信服务端返回的数据并向服务端发送请求

用户统一授权后,微信会返回数据,需要在.wxapi.WXEntryActivity下对数据进行处理。

I.新建wxapi包(包名固定,且必须是在微信开放平台注册的包名下)

II.新建Activity类,命名为WXEntryActivity

WXEntryActivity,并继承Activity类,实现IWXAPIEventHandler接口的两个方法

public interface IWXAPIEventHandler {    void onReq(BaseReq var1);    void onResp(BaseResp var1);}

WXEntryActivity实现

public class WXEntryActivity extends Activity implements IWXAPIEventHandler {

private IWXAPI api;  // 在onCreate中进行了初始化

onReq方法

    // 微信发送请求到第三方应用时,会回调到该方法    @Override    public void onReq(BaseReq req) {        Toast.makeText(this, "Test ", Toast.LENGTH_SHORT).show();        switch (req.getType()) {            case ConstantsAPI.COMMAND_GETMESSAGE_FROM_WX:                break;            case ConstantsAPI.COMMAND_SHOWMESSAGE_FROM_WX:                break;            default:                break;        }}

onResp方法

在onResp中需要实现逻辑,微信返回的数据在这里会被接收。

微信返回的数据包含code。在onResp需要实现向服务端发送请求,带上code等参数,后端再通过相应的参数去请求微信服务端,最终将获取到的用户信息返回给前端Android。

// 第三方应用发送到微信的请求处理后的响应结果,会回调到该方法    @Override    public void onResp(final BaseResp resp) {        int result = 0;        Toast.makeText(this, "baseresp.getType = " + resp.getType(), Toast.LENGTH_SHORT).show();        //成功后发送请求        switch (resp.errCode) {            case BaseResp.ErrCode.ERR_OK:                result = R.string.errcode_success;                final String code = ((SendAuth.Resp) resp).code;//需要转换一下才可以                new Thread(new Runnable() {                    @Override                    public void run() {                //向服务端发送请求,预计返回用户信息数据,返回给前端进行显示。                        String url = "http://p2a3b8.natappfree.cc" +                                "/wechat/open/callback/android" + "?" +                                "state=" + "android" +//这里的state需与后端进行探讨                                "&code=" + code;                        String str = ApacheHttpUtil.get(url);                        JSONObject jsonObject = (JSONObject) JSONObject.parse(str);                        weChatUserInfo = (WeChatUserInfo) JSON.parseObject(jsonObject.get("data").toString(), new TypeReference() {                        });                    }                }).start();                while (true) {// TODO: 这里处理方案不合理,死循环或将造成界面卡死(需要前端优化)                    if (weChatUserInfo != null) {                        Intent intent = new Intent(WXEntryActivity.this, WechatUserInfoViewItem.class);                        /* 通过Bundle对象存储需要传递的数据 */                        Bundle bundle = new Bundle();                        bundle.putString("wechatopenid", weChatUserInfo.getOpenid());                        bundle.putString("wechatnickname", weChatUserInfo.getNickname());                        bundle.putString("wechatsex", weChatUserInfo.getSex().toString());                        bundle.putString("wechatprovince", weChatUserInfo.getProvince());                        bundle.putString("wechatcity", weChatUserInfo.getCity());                        bundle.putString("wechatcountry", weChatUserInfo.getCountry());                        bundle.putString("wechatheadimgurl", weChatUserInfo.getHeadimgurl());                        bundle.putString("wechatprivilege", weChatUserInfo.getPrivilege());                        bundle.putString("wechatunionid", weChatUserInfo.getOpenid());                        /*把bundle对象assign给Intent*/                        intent.putExtras(bundle);                        startActivity(intent);                        break;                    }                }                break;            case BaseResp.ErrCode.ERR_USER_CANCEL:                result = R.string.errcode_cancel;   // 发送取消                break;            case BaseResp.ErrCode.ERR_AUTH_DENIED:                result = R.string.errcode_deny;   // 发送被拒绝                break;            case BaseResp.ErrCode.ERR_UNSUPPORT:                result = R.string.errcode_unsupported;  // 不支持错误                break;            default:                result = R.string.errcode_unknown;  // 发送返回                break;        }        Toast.makeText(this, result, Toast.LENGTH_LONG).show();    }

重写onNewIntent方法

在WXEntryActivity中将接收到的intent及实现了IWXAPIEventHandler接口的对象传递给IWXAPI接口的handleIntent方法,

    @Override    protected void onNewIntent(Intent intent) {        super.onNewIntent(intent);        setIntent(intent);        api.handleIntent(intent, this);    }

III.在manifest文件添加WXEntryActivity,并加上exported属性,设置为true,:

                                                                                                                                                            

4)根据服务端返回数据进行解析并显示给前端Android页面

获取数据已经跳转代码如上(onResp方法中)。需要前端优化处理

public class WechatUserInfoViewItem extends FragmentActivity {    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.wechat_user_info);        Bundle bundle = this.getIntent().getExtras();        TextView wechatopenid = (TextView) findViewById(R.id.wechatopenid);        wechatopenid.setText(bundle.getString("wechatopenid"));        TextView wechatnickname = (TextView) findViewById(R.id.wechatnickname);        wechatnickname.setText(bundle.getString("wechatnickname"));        TextView wechatsex = (TextView) findViewById(R.id.wechatsex);        wechatsex.setText(bundle.getString("wechatsex"));        TextView wechatprovince = (TextView) findViewById(R.id.wechatprovince);        wechatprovince.setText(bundle.getString("wechatprovince"));        TextView wechatcity = (TextView) findViewById(R.id.wechatcity);        wechatcity.setText(bundle.getString("wechatcity"));        TextView wechatcountry = (TextView) findViewById(R.id.wechatcountry);        wechatcountry.setText(bundle.getString("wechatcountry"));        TextView wechatunionid = (TextView) findViewById(R.id.wechatunionid);        wechatunionid.setText(bundle.getString("wechatunionid"));    }}

布局xml:

<?xml version="1.0" encoding="utf-8"?>                                                                                                                                                                                   

2.服务端(Java)

服务端需要做的是:接受Android前端发送的请求,获取code,根据AppId和APPSecret等向微信服务端发送请求,然后获取到Token,再根据Token获取到用户基本信息。最终通过JSON的方式返回给前端。

1).统一返回JSON

@Getter @Setterpublic class Result {    private int code;    private String msg;    private T data;    /*** 成功时候的调用* */    public static  Result success(T data){        return new  Result(data);    }    /*** 失败时候的调用* */    public static  Result error(CodeMsg cm){        return new  Result(cm);    }    private Result(T data) {        this.code = 0;        this.msg = "success";        this.data = data;    }    private Result(CodeMsg cm) {        if(cm == null) {            return;        }        this.code = cm.getCode();        this.msg = cm.getMsg();    }}

 

2).相关参数配置:

# 微信开放平台Android

wechat.open.android.appid =

wechat.open.android.appsecret =

 

3).请求响应逻辑

@ResponseBody    @RequestMapping("/callback/android")    public Result openWeChatCallback(HttpServletRequest httpServletRequest) {        String code = httpServletRequest.getParameter("code");        //String state = httpServletRequest.getParameter("state"); // TODO:        String url = null;        url = "https://api.weixin.qq.com/sns/oauth2/access_token?" +                "appid=" +                env.getProperty("wechat.open.android.appid").trim() +                "&secret=" +                env.getProperty("wechat.open.android.appsecret").trim() +                "&code=" +                code +                "&grant_type=authorization_code";        JSONObject wechatAccessToken = HttpClientUtils.httpGet(url);        if (wechatAccessToken.get("errcode") != null) {            return Result.error(CodeMsg.FAIL_GETTOKEN);        }        String accessToken = (String) wechatAccessToken.get("access_token");        String openid = (String) wechatAccessToken.get("openid");        String unionid = (String) wechatAccessToken.get("unionid");        if (StringUtils.isEmpty(accessToken) || StringUtils.isEmpty(openid) || StringUtils.isEmpty(unionid)) {            return Result.error(CodeMsg.FAIL_GETTOKEN);        }        // TODO:根据Openid或Unionid对数据库进行查询,如果查询到对应的用户数据,则不需要再向微信服务器发送请求去返回数据。        // TODO: 建议使用Unionid作为查询条件。        WeChatUserInfo weChatUserInfo = null;        wechatAccessToken = null;  // FIXME: 这里应该是从数据库中查询获取用户信息逻辑。        if (wechatAccessToken == null) {            // 新用户            weChatUserInfo = getUserInfoByAccessToken(accessToken);            // 数据库插入的操作        }        if (weChatUserInfo != null) {            return Result.success(weChatUserInfo);        }        return Result.error(CodeMsg.FAIL_GETUSERINFO);    }

4).根据Token获取用户信息:

/**     * 根据accessToken获取用户个人公开信息     *     * @param accessToken     * @return     */  private WeChatUserInfo getUserInfoByAccessToken(String accessToken) {        if (StringUtils.isEmpty(accessToken)) {            return null;  //"accessToken为空";        }        String get_userInfo_url = "https://api.weixin.qq.com/sns/userinfo?" +                "access_token=" +                accessToken +                "&openid=" +                env.getProperty("wechat.open.android.appid").trim();        String userInfo_result = HttpClientUtils.httpGet(get_userInfo_url, "utf-8");        if (!userInfo_result.equals("errcode")) {            WeChatUserInfo weChatUserInfo = JSON.parseObject(userInfo_result, new TypeReference() {            });            // TODO: 需要把头像信息下载到文件服务器,然后替换掉头像URL。微信的或许不可靠,假设微信用户更换了头像,旧头像URL是否会保存?而这个URL信息却存放在我们的数据库中,不可靠            return weChatUserInfo;        }        return null;  //"获取用户信息失败"    }

五、注意事项:

1.Android4.0以上版本,发送网络请求时,必须是以线程异步的方式发送请求,否则发送请求会失败。

六、应用关键参数位置

微信开放平台开发第三方授权登陆(三):Android客户端_第5张图片

 

微信开放平台开发第三方授权登陆(三):Android客户端_第6张图片

更多相关文章

  1. 详解Android客户端与服务器交互方式
  2. okhttp的应用详解与源码解析--okhttp客户端应用
  3. Android帮助文档翻译——开发指南(十五)获取用户位置
  4. 极光推送 使用实例 (一)服务端
  5. Android的SocketTCP客户端发送信息
  6. 如何使用Jdbc和Servlet操作Mysql数据库,编写Android登录注册服务
  7. Android ListView分页载入(服务端+android端)Demo
  8. android点滴(29) android中设置用户自定义的字体
  9. Android 客户端与服务器交互方式

随机推荐

  1. Android(安卓)应用语言设置的实现
  2. Android(安卓)开发笔记 动画效果 --Anima
  3. Android中TextToSpeech的简单使用
  4. SwipeRefreshLayout + RecyclerView 实现
  5. Android中使用代码执行shell命令
  6. android 4.0 内核(3.0)编译方法
  7. Android入门:SQLite
  8. Android动态设置edittext的hint属性显示
  9. android 开发之电子钢琴 源码
  10. android scroller用法及属性