这两天尝试了接入微信登陆接口,中间也遇到了不少问题,记录一下,看了微信的demo感觉有点复杂,自己写了个小demo,方便查看。
首先需要参考微信文档
1.准备工作
1.先要在微信开放平台注册app,这个过程就不详细叙述了,注册好后可以拿到appID和appSecret。
2.下载微信的SDK,放入到项目中SDK地址
3.添加依赖库
4.添加URL Type
5.注册白名单以及设置App Transport Security Settings
6.在other linker flags添加$(inherited)
7.导入AFNetworking,我用的是CocoaPods导入。
2.开撸代码
1.注册app,appID就是微信开放平台注册应用的appID
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
//appID
[WXApi registerApp:appId];
return YES;
}
2.设置代理,onResp方法会从微信回来时调用
- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options{
return [WXApi handleOpenURL:url delegate:self];
}
#pragma mark - WXApiDelegate
- (void)onResp:(BaseResp *)resp{
if([resp isKindOfClass:[SendAuthResp class]]){
SendAuthResp *resp2 = (SendAuthResp *)resp;
[[NSNotificationCenter defaultCenter] postNotificationName:@"wxLogin" object:resp2];
}else{
NSLog(@"授权失败");
}
}
3.登陆,先判断是否装过微信,装过则通过sendAuthReq进行验证会跳转到微信,没有则提示未装微信
- (void)login{
//判断微信是否安装
if([WXApi isWXAppInstalled]){
SendAuthReq *req = [[SendAuthReq alloc] init];
req.scope = @"snsapi_userinfo";
req.state = @"App";
[WXApi sendAuthReq:req viewController:self delegate:self];
}else{
[self setupAlertController];
}
}
4验证完成,在OnResp方法发送通知将code,传给登陆界面,登陆界面可以用code获取accessToken,这里特别要注意,用AFNetworking请求时要在接收类型添加"text/plain",否则请求成功了也会进入failure方法,拿不到结果。
- (void)wxLogin:(NSNotification*)noti{
//获取到code
SendAuthResp *resp = noti.object;
_code = resp.code;
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
NSString *url = [NSString stringWithFormat:@"https://api.weixin.qq.com/sns/oauth2/access_token?appid=%@&secret=%@&code=%@&grant_type=%@",appId,appSecret,_code,@"authorization_code"];
manager.requestSerializer = [AFJSONRequestSerializer serializer];
[manager.requestSerializer setValue:@"text/html; charset=utf-8" forHTTPHeaderField:@"Content-Type"];
NSMutableSet *mgrSet = [NSMutableSet set];
mgrSet.set = manager.responseSerializer.acceptableContentTypes;
[mgrSet addObject:@"text/html"];
//因为微信返回的参数是text/plain 必须加上 会进入fail方法
[mgrSet addObject:@"text/plain"];
[mgrSet addObject:@"application/json"];
manager.responseSerializer.acceptableContentTypes = mgrSet;
[manager GET:url parameters:nil progress:^(NSProgress * _Nonnull downloadProgress) {
} success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
NSLog(@"success");
NSDictionary *resp = (NSDictionary*)responseObject;
NSString *openid = resp[@"openid"];
NSString *unionid = resp[@"unionid"];
NSString *accessToken = resp[@"access_token"];
NSString *refreshToken = resp[@"refresh_token"];
if(accessToken && ![accessToken isEqualToString:@""] && openid && ![openid isEqualToString:@""]){
[[NSUserDefaults standardUserDefaults] setObject:openid forKey:WX_OPEN_ID];
[[NSUserDefaults standardUserDefaults] setObject:accessToken forKey:WX_ACCESS_TOKEN];
[[NSUserDefaults standardUserDefaults] setObject:refreshToken forKey:WX_REFRESH_TOKEN];
[[NSUserDefaults standardUserDefaults] synchronize];
}
[self getUserInfo];
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
}];
}
5.拿到accessToken后可以通过accessToken来获取用户信息了
- (void)getUserInfo{
//获取个人信息
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
NSString *url = [NSString stringWithFormat:@"https://api.weixin.qq.com/sns/userinfo?access_token=%@&openid=%@",[[NSUserDefaults standardUserDefaults] objectForKey:WX_ACCESS_TOKEN],[[NSUserDefaults standardUserDefaults] objectForKey:WX_OPEN_ID]];
NSMutableSet *mgrSet = [NSMutableSet set];
mgrSet.set = manager.responseSerializer.acceptableContentTypes;
[mgrSet addObject:@"text/html"];
//因为微信返回的参数是text/plain 必须加上 会进入fail方法
[mgrSet addObject:@"text/plain"];
[mgrSet addObject:@"application/json"];
manager.responseSerializer.acceptableContentTypes = mgrSet;
[manager GET:url parameters:nil progress:^(NSProgress * _Nonnull downloadProgress) {
} success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
NSLog(@"success");
NSLog(@"%@",responseObject);
NSDictionary *resp = (NSDictionary*)responseObject;
self->_nicknameLabel.text = resp[@"nickname"];
self->_sexLabel.text = [resp[@"sex"] intValue] == 1 ? @"男" : @"女";
self->_addressLabel.text = [NSString stringWithFormat:@"%@%@%@",resp[@"country"],resp[@"province"],resp[@"city"]];
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
NSLog(@"fail");
NSLog(@"%@",task.response);
}];
}
6.另外accessToken的有效期是2小时,如果过期,可以使用refreshToken重新获取,refreshToken的有效期是30天,假如过期了,则需要重新登陆
- (void)refreshAccessToken{
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
NSString *url = [NSString stringWithFormat:@"https://api.weixin.qq.com/sns/oauth2/refresh_token?appid=%@&refresh_token=%@&grant_type=%@",[[NSUserDefaults standardUserDefaults] objectForKey:WX_OPEN_ID],[[NSUserDefaults standardUserDefaults] objectForKey:WX_REFRESH_TOKEN],@"REFRESH_TOKEN"];
NSMutableSet *mgrSet = [NSMutableSet set];
mgrSet.set = manager.responseSerializer.acceptableContentTypes;
[mgrSet addObject:@"text/html"];
//因为微信返回的参数是text/plain 必须加上 会进入fail方法
[mgrSet addObject:@"text/plain"];
[mgrSet addObject:@"application/json"];
manager.responseSerializer.acceptableContentTypes = mgrSet;
[manager GET:url parameters:nil progress:^(NSProgress * _Nonnull downloadProgress) {
} success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
NSLog(@"success");
NSDictionary *resp = (NSDictionary*)responseObject;
NSString *openid = resp[@"openid"];
NSString *accessToken = resp[@"access_token"];
NSString *refreshToken = resp[@"refresh_token"];
if(refreshToken){
if(accessToken && ![accessToken isEqualToString:@""] && openid && ![openid isEqualToString:@""]){
[[NSUserDefaults standardUserDefaults] setObject:openid forKey:WX_OPEN_ID];
[[NSUserDefaults standardUserDefaults] setObject:accessToken forKey:WX_ACCESS_TOKEN];
[[NSUserDefaults standardUserDefaults] setObject:refreshToken forKey:WX_REFRESH_TOKEN];
[[NSUserDefaults standardUserDefaults] synchronize];
}
}else{
//如果refreshToken为空,说明refreshToken也过期了,需要重新登陆
[self login];
}
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
NSLog(@"fail");
NSLog(@"%@",task.response);
}];
}