Android微信第三方登录
转载请注明出处:
http://blog.csdn.net/Kaission/article/details/54670275
前言:
- 前阵子由于公司需求做了微信、qq原生的第三方登录,由于需求不让使用第三方,像Mob、友盟等,踩了不少坑,在此记录一下,方便以后碰到同样的问题,有个正确的引导。由于qq的比较容易实现,在此本人只整理的微信;由于个人水平有限,如果文章中有错误,请直接联系本人进行改正。谢谢
这里特别吐槽一下官方的开发文档,对于没经验的小白来说,看得懂实在是有些困难,而且jar包都更新迭代了好些次了,开发文档还是老样子。。。
好了,接下来开始我们的接入吧。
首先:
微信的第三方登录功能是付费的,每年需要300软妹币(但是官方开发文档中却说免费提供,坑…),你需要做的是注册,提交相关资料,然后付费(微信的分享功能是免费的),静待审核通过,官方说大概是一周左右的时间。需要注意的是,注册时填写的项目的包名(包名一般是项目的Manifest文件中的包名)和MD5签名字符串,签名字符串官方有获取的工具,对于你后来的调试时非常重要的,后面还会提及到,在此先声明一下。
根据项目需求下载需要的Demo [官方Demo及签名工具下载 ]
以上工作都准备好之后,就可以进入我们的接入工作了
本人的工作环境是Eclipse,AS上面只会更简单,步骤出入不大,差别自行百度,在此不做重点说明
这个是需要引入的jar包,dfs s 直接粘贴复制到项目的libs目录中,然后buildpath就可以了
接下来,就是关键的代码区了
第一步:在你逻辑需要的地方添加如下代码,发起微信的授权登录:
// 初始化IWXAPI
//这里的第一个参数是环境变量,第二个参数是在微信开放平台上审核通过得到的APP_ID,注意别和secret弄混了
//api变量是IWXAPI类的对象
api = WXAPIFactory.createWXAPI(Content, APP_ID, true);
api.registerApp(APP_ID);
if (api != null && api.isWXAppInstalled()) {
final SendAuth.Req req = new SendAuth.Req();
req.scope = "snsapi_userinfo";
req.state = "wechat_sdk_demo";
api.sendReq(req);
DLog.i(TAG, "api: " + api.toString());
} else
Toast.makeText(Content, "用户未安装微信", Toast.LENGTH_SHORT)
.show();
这样就可以调起微信的授权界面了。需要注意的是,微信的第三方登录,需要用户必须安装微信客户端,才能发起登录请求。
这是微信客客户端未登录的效果(也就是微信客户端未登录用户):
当微信客户端已经有用户登录时,效果是这样的:
这样,第一步就完成了。
接下来是第二步,也是最关键的:
这里需要自定义一个类,WXEntryActivity(必须是这个名字,不然微信回调,也就是上一步点击确认登录的回调);这个类需要继承Activity和实现IWXAPIEventHandler接口,此外,WXEntryActivity类的存放位置也是有讲究的,必须在包名路径下新建一个wxapi的文件夹里面,是必须这么写。效果如下:
第三步,就是有关WXEntryActivity这个类里面的详细代码了:
书接第一步,点击授权登录后,IWXAPIEventHandler这个接口会有两个实现的方法onReq、onResp,重要的是后面那个方法,在这个回调方法里,我们要获取微信登录返回到code,
在这里插一句。微信登录大概是这么个流程:首先我们请求微信登录,去获取code。然后拿着这个code再去请求获得openid、accessToken,最后拿着openid 和accessToken才能获取到用户的信息,像name,头像图片的url等。
那么,我们要怎么获取到code呢?这里还有个坑,且听我慢慢道来。。。。
上面说到了这个回调:onResp
我们可以这样写:
@Override
public void onResp(BaseResp arg0) {
// TODO Auto-generated method stub
//微信授权返回code的回调
int errorCode = arg0.errCode;
switch (errorCode) {
case BaseResp.ErrCode.ERR_OK:
//这里是坑,请注意回避。。。。。。
// 用户同意;此处Android端是token,而不是code;官方的demo里面竟然是code,唉唉唉...
String code = ((SendAuth.Resp) arg0).token;
DLog.i(TAG, "code:" + code);
if (code != null) {
getAccess_token(code);
}
break;
case BaseResp.ErrCode.ERR_AUTH_DENIED:
// 用户拒绝
break;
case BaseResp.ErrCode.ERR_USER_CANCEL:
// 用户取消
break;
default:
break;
}
//这里需要结束当前的activity,也就是我们的WXEntryActivity,不然会一直卡在这个activity里无法回到我们自己的activity中(本人就是这个问题纠结了好久啊)
finish();
}
好了,现在我们是拿到了code这个参数了,可是要怎么去获取openid、accessToken进而获取用户信息呢?
去请求这个地址path,填写好我们上一步拿到的code参数,以及之前在微信开放平台审核通过后给的APP_ID和APP_SECERT,就可以返回openid、accessToken了。返回到是一个json字符串,需要解析下。
String path = "https://api.weixin.qq.com/sns/oauth2/access_token?appid="
+ APP_ID
+ "&secret="
+ APP_SECRET
+ "&code="
+ code
+ "&grant_type=authorization_code";
最后,我们拿着openid、accessToken,请求这个地址:
String path = "https://api.weixin.qq.com/sns/userinfo?access_token="
+ access_token + "&openid=" + openid;
同样,返回的也是一个json字符串,需要解析下,就可以拿到nickname、headimgurl等等;
哈哈哈哈,到这里,我们的微信登录就大功告成啦!
咦,等会儿,有同学会说,为什么我都严格按照上面的步骤写的,,怎么会没有成功登录微信呢?发起授权登录没有反应?
唉,继续讲吧,还没有结束嘞!
原本我以为这样就是可以的了,没想到微信在这里又给我们善良的小伙伴们挖了一个坑,微信啊微信…
反思之后,原来我们现在的这个项目是一个Debug包,微信这么严谨的大公司,是不允许不正规的项目登录他们的服务器滴,那,怎么办呢?
没办法,也是唯一的办法,就是签名打包呗,讲下具体操作:
有关Eclipse及AS的签名打包的方法,请读者们自行百度,在这里我只讲重点。
当你完成签名打包,生成一个release.apk文件时,安装到你的测试机或模拟器上,然后重新将我们的包名进行签名,也就是文章一开始提到的微信提供的那个签名工具,就是这个东西:
在这里输入你的包名,然后重新生成一个md5的签名字符串,去微信开放平台重填上就好,一般不需要再次审核了。
这次是真的真的完成了,好辛苦,晚上奖励鸡腿一个,哈哈。
没有成功的同学,可以随时找我,在这里,把我的WXEntryActivity完整的代码贴上吧,写的不好,没有优化,凑活着看吧,哈哈。
public class WXEntryActivity extends Activity implements IWXAPIEventHandler {
private static final String TAG = "WXEntryActivity";
public static final String APP_ID = "你的appid";
public static final String APP_SECRET = "你的appkey";
private IWXAPI api;
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
DLog.i(TAG, "APP_ID: " + APP_ID);
DLog.i(TAG, "APP_SECRET: " + APP_SECRET);
api = WXAPIFactory.createWXAPI(this, App.WX_APPID, false);
//将你收到的intent和实现IWXAPIEventHandler接口的对象传递给handleIntent方法
api.handleIntent(getIntent(), this);
}
@Override
protected void onNewIntent(Intent intent) {
// TODO Auto-generated method stub
super.onNewIntent(intent);
setIntent(intent);
}
@Override
public void onReq(BaseReq arg0) {
// TODO Auto-generated method stub
finish();
}
@Override
public void onResp(BaseResp arg0) {
// TODO Auto-generated method stub
//微信授权返回code的回调
int errorCode = arg0.errCode;
switch (errorCode) {
case BaseResp.ErrCode.ERR_OK:
// 用户同意;此处Android端是token,而不是code
String code = ((SendAuth.Resp) arg0).token;
DLog.i(TAG, "code:" + code);
if (code != null) {
getAccess_token(code);
}
break;
case BaseResp.ErrCode.ERR_AUTH_DENIED:
// 用户拒绝
break;
case BaseResp.ErrCode.ERR_USER_CANCEL:
// 用户取消
break;
default:
break;
}
finish();
}
/**
* 获取openid accessToken值用于后期操作
*
* @param code
* 请求码
*/
private void getAccess_token(final String code) {
new Thread(new Runnable() {
@Override
public void run() {
String path = "https://api.weixin.qq.com/sns/oauth2/access_token?appid="
+ APP_ID
+ "&secret="
+ APP_SECRET
+ "&code="
+ code
+ "&grant_type=authorization_code";
try {
//SinaHttpsUtil 为网路请求工具
String res = SinaHttpsUtil.httpsGet(path, "");// 请求https连接并得到json结果
DLog.i(TAG, "res :" + res);
JSONObject jsonObject = new JSONObject(res);
if (null != jsonObject) {
String openid = jsonObject.getString("openid")
.toString().trim();
String access_token = jsonObject
.getString("access_token").toString().trim();
DLog.i(TAG, "openid:" + openid + " access_token:"
+ access_token);
// 获取个人信息
getUserMsg(access_token, openid);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
}
/**
* 获取微信的个人信息
*
* @param access_token
* @param openid
*/
private void getUserMsg(final String access_token, final String openid) {
new Thread(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
String path = "https://api.weixin.qq.com/sns/userinfo?access_token="
+ access_token + "&openid=" + openid;
try {
String res = SinaHttpsUtil.httpsGet(path, "");// 请求https连接并得到json结果
JSONObject jsonObject = new JSONObject(res);
if (null != jsonObject) {
String nickname = jsonObject.getString("nickname");
int sex = Integer.parseInt(jsonObject.get("sex")
.toString());
String headimgurl = jsonObject.getString("headimgurl");
DLog.i(TAG, "getUserMesg 拿到了用户微信基本信息.. nickname:"
+ nickname + " sex:" + sex + " headimurl:"
+ headimgurl);
}
} catch (Exception e) {
e.printStackTrace();
}
return;
}
}).start();
}
}