移动应用微信登录开发指南
准备工作
移动应用微信登录是基于OAuth2.0协议标准构建的微信OAuth2.0授权登录系统。
在进行微信OAuth2.0授权登录接入之前,在微信开放平台注册开发者帐号,并拥有一个已审核通过的移动应用,并获得相应的AppID和AppSecret,申请微信登录且通过审核后,可开始接入流程。
1、目前移动应用上微信登录只提供原生的登录方式,需要用户安装微信客户端才能配合使用。
2、对于Android应用,建议总是显示微信登录按钮,当用户手机没有安装微信客户端时,请引导用户下载安装微信客户端。
3、对于iOS应用,考虑到iOS应用商店审核指南中的相关规定,建议开发者接入微信登录时,先检测用户手机是否已安装微信客户端(使用sdk中isWXAppInstalled函数 ),对未安装的用户隐藏微信登录按钮,只提供其他登录方式(比如手机号注册登录、游客登录等)。
授权流程说明
微信OAuth2.0授权登录让微信用户使用微信身份安全登录第三方应用或网站,在微信用户授权登录已接入微信OAuth2.0的第三方应用后,第三方可以获取到用户的接口调用凭证(access_token),通过access_token可以进行微信开放平台授权关系接口调用,从而可实现获取微信用户基本开放信息和帮助用户实现基础开放功能等。
微信OAuth2.0授权登录目前支持authorization_code模式,适用于拥有server端的应用授权。该模式整体流程为:
1. 第三方发起微信授权登录请求,微信用户允许授权第三方应用后,微信会拉起应用或重定向到第三方网站,并且带上授权临时票据code参数;
2. 通过code参数加上AppID和AppSecret等,通过API换取access_token;
3. 通过access_token进行接口调用,获取用户基本数据资源或帮助用户实现基本操作。
可拉起微信打开授权登录页:
这里的返回数值我们得搞清楚,如下:
//获取个人信息
看了这么多,其实都是微信官方的文档,相对来说写的还是非常的详细的,那么我们自己根据他的文档,也封装了自己的微信登陆工具类:
public class WeChatLogin {
private Activity activity;
private Context context;
public static String text = "";
public static String WX_CODE = "";
// IWXAPI 是第三方app和微信通信的openapi接口
public static IWXAPI wxApi;
private WeChatLogin() {
context = Application.getContext();
// 通过wxapofactory工厂,获取IWXAPI的实例
wxApi = WXAPIFactory.createWXAPI(Application.getContext(), Constants.WXAPPID, true);
// 将应用的appId注册到微信
wxApi.registerApp(Constants.WXAPPID);
}
/* 类级的内部类,也就是静态的成员式内部类,该内部类的实例与外部类的实例 没有绑定的关系,而且只有被调用到时才会装载,从而实现了延迟加载 */
private static class SingTonHolder {
/* 静态初始化器,由JVM来保证线程安全 */
private static WeChatLogin instance = new WeChatLogin();
}
/* 该单例实现了延迟加载和线程安全 */
public static WeChatLogin getInstance() {
return SingTonHolder.instance;
}
/**
* @方法说明:微信登录
* @方法名称:wx_Login
* @返回值:void
*/
public void wx_Login(Activity activity) {
this.activity = activity;
if (wxApi == null) {
wxApi = WXAPIFactory.createWXAPI(context, Constants.WXAPPID, false);
wxApi.registerApp(Constants.WXAPPID);
}
if (!wxApi.isWXAppInstalled()) {
ToastUtilPro.showToast("您手机上未检测到微信,请去安卓应用市场下载安装微信!");
return;
}
SendAuth.Req req = new SendAuth.Req();
req.scope = "snsapi_userinfo";
req.state = "wechat_sdk_demo_test";
// sendReq是第三方app主动发送消息给微信,发送完成之后会切回到第三方app界面。
wxApi.sendReq(req);
}
public void setContext(Context context) {
this.context = context;
}
/**
* @methods: 获得微信用户信息
*/
public void loadWXUserInfo() {
new Thread(new Runnable() {
@Override
public void run() {
String accessTokenUrl =
"https://api.weixin.qq.com/sns/oauth2/access_token?appid="
+ Constants.WXAPPID
+ "&secret="
+ Constants.WXAPPSECRET
+ "&code="
+ WX_CODE + "&grant_type=authorization_code";
//此处的HttpRequest,是封装了的一个http工具类,可以换成自己的,执行get请求即可
String tokenResult = HttpHelper.get(accessTokenUrl);
if (null != tokenResult&&tokenResult.contains("access_token")){
JSONObject tokenObj;
try {
tokenObj = new JSONObject(tokenResult);
String accessToken = tokenObj.optString("access_token");
String refresh_token = tokenObj.optString("refresh_token");
AmayaSPUtil.save("wechat_refresh_token",refresh_token);
String openId = tokenObj.optString("openid");
String userUrl = "https://api.weixin.qq.com/sns/userinfo?access_token="
+ accessToken + "&openid=" + openId;
String wxUserInfo = HttpHelper.get(userUrl);
if (!TextUtils.isEmpty(wxUserInfo)) {
WechatUserinfo wechatUserinfo = JSON.parseObject(wxUserInfo, WechatUserinfo.class);
//获取用户信息,进行相关逻辑操作
String openid = wechatUserinfo.getOpenid();
String headimgurl = wechatUserinfo.getHeadimgurl();
String nickname = wechatUserinfo.getNickname();
String unionid = wechatUserinfo.getUnionid();
}
} catch (JSONException e) {
e.printStackTrace();
}
}
}
}).start();
}
}
HttpHelper工具类:
public class HttpHelper {
private static String tag = HttpHelper.class.getSimpleName();
// private static HttpClient httpClient = new DefaultHttpClient();
/**
* get请求获取服务器返回数据
* @param url
* @return
*/
public static String get(String url){
HttpClient httpClient = new DefaultHttpClient();
LogUtil.e("HttpHelp", "request url: " + url);
String result = null;
HttpGet httpGet = new HttpGet(url);
boolean retry = true;
while(retry){
try {
HttpResponse httpResponse = httpClient.execute(httpGet);
if(httpResponse.getStatusLine().getStatusCode()<300){
InputStream is = httpResponse.getEntity().getContent();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buffer = new byte[1024*4];
int len = -1;
while((len=is.read(buffer))!=-1){
baos.write(buffer,0,len);
baos.flush();
}
result = new String(baos.toByteArray(),"UTF-8");
is.close();
baos.close();
httpClient.getConnectionManager().closeExpiredConnections();
break;
}
} catch (Exception e) {
e.printStackTrace();
retry = false;
}
}
LogUtil.e("HttpHelp", "response: " + result);
return result;
}
}
同级包名下建相关包名,以及回调
配置相关Manifest.xml文件
<activity
android:name=".wxapi.WXEntryActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:exported="true"
android:screenOrientation="portrait"
android:theme="@android:style/Theme.Translucent.NoTitleBar" />
public class WechatUserinfo {
/**
* openid : xxxxx
* nickname : xxxxx
* sex : 1
* language : zh_CN
* city :
* province :
* country :
* headimgurl : http://wx.qlogo.cn/mmopen/4phgzibSoW4icGjzicQcxtTWoEfBlMFfOoNQcCOfTYy50NVXQvzG3XjgCL15OXhtE0etdniamOUh7OEhfVT1Spic0Y92M9YfUafty/0
* privilege : []
* unionid : xxxxxxx
*/
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 String unionid;
private List<?> privilege;
public String getOpenid() {
return openid;
}
public void setOpenid(String openid) {
this.openid = openid;
}
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 String getUnionid() {
return unionid;
}
public void setUnionid(String unionid) {
this.unionid = unionid;
}
public List<?> getPrivilege() {
return privilege;
}
public void setPrivilege(List<?> privilege) {
this.privilege = privilege;
}
}