微信开放平台开发第三方授权登陆(三):Android客户端
微信开放平台开发系列文章:
微信开放平台开发第三方授权登陆(一):开发前期准备
微信开放平台开发第三方授权登陆(二):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进行接口调用,获取用户基本数据资源或帮助用户实现基本操作。
获取用户基本信息的流程
三、开发使用的技术及工具
1、.后端采用IDEA2017 进行开发
2、使用Android Studio 3.1.3 进行开发
3、后端必须基于JDK7以上版本,采用JDK8开发,前端基于Android SDK4.4
4、使用fastJson对json数据进行处理
四、具体实现步骤
1.前端(Android)
目录结构如下:
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目录下)。
右键单击工程,选择Build Path中的Configure Build Path...,选中Libraries这个tab,并通过Add Jars...导入工程libs目录下的libammsdk.jar文件。(如下图所示)。
在需要使用微信终端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(安卓)系统架构分析
- Android开发者官网:Android(安卓)4.4发布10个月市占仅17.9%
- Android软硬整合技术(HAL&Framework)
- 让Qt应用程序跑在Android上
- android开发(46) 使用 textview实现文字的阴影效果,浮雕效果
- android 工程师 你必须知道的
- 技术---Java
- Android(安卓)开发之Matrix图片处理类的使用
- Android中的权限问题