iOS第三方登录大全(上)

QQ、微信、微博接入

通用说明

所有第三方登录都需遵循以下步骤:

  • 注册第三方应用的AppID、Key、Secret
  • 添加第三方SDK及其所需系统依赖库,各文档内有详细说明,若依旧编译错误请参考下图加入所有库:

  • 在Targets->Info->URL Types添加各自的URL Schemes
  • 在info.plist添加LSApplicationQueriesSchemes字段并添加白名单
  • 在AppDelegate中初始化,各自回调,实现代理
  • 具体请看下文

QQ接入

官方文档

移动应用接入概述

SDK下载地址

SDK环境搭建

API使用说明

2.1 配置QQ需要的静态库,分别是

1
2
3
Security.framework”, “libiconv.dylib”,“SystemConfiguration.framework”,  
CoreGraphics.Framework”,“libsqlite3.dylib”,“CoreTelephony.framework”,
libstdc++.dylib”,“libz.dylib

2.2 在配置文件Info.plist中配置应用白名单,必须添加以下所有字段,否则可能无法跳转

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
   <key>LSApplicationQueriesSchemes</key>
<array>
<string>mqqapi</string>
<string>mqq</string>
<string>mqqOpensdkSSoLogin</string>
<string>mqqconnect</string>
<string>mqqopensdkdataline</string>
<string>mqqopensdkgrouptribeshare</string>
<string>mqqopensdkfriend</string>
<string>mqqopensdkapi</string>
<string>mqqopensdkapiV2</string>
<string>mqqopensdkapiV3</string>
<string>mqzoneopensdk</string>
<string>wtloginmqq</string>
<string>wtloginmqq2</string>
<string>mqqwpa</string>
<string>mqzone</string>
<string>mqzonev2</string>
<string>mqzoneshare</string>
<string>wtloginqzone</string>
<string>mqzonewx</string>
<string>mqzoneopensdkapiV2</string>
<string>mqzoneopensdkapi19</string>
<string>mqzoneopensdkapi</string>
<string>mqqbrowser</string>
<string>mttbrowser</string>
</array>

2.3 点击XCode项目名,选择Info,添加腾讯的URL Types

identifier填tencent URL Schemes:tencent前缀后+QQ App ID(用户自己申请的账号)

2.4 在AppDelegate中配置

1
2
3
4
5
6
7
8
9
10
// 1
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation{
return [TencentOAuth HandleOpenURL:url];


}
// 2
- (BOOL)application:(UIApplication *)application handleOpenURL:(NSURL *)url{
return [TencentOAuth HandleOpenURL:url];
}

2.5 构建单例工具类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
static CIAccountThirdLoginUtil *thirdLogin;

@interface CIAccountThirdLoginUtil()<TencentSessionDelegate>

@property TencentOAuth *tencentOAuth;

@property (nonatomic,copy)void (^thirdLoginSuccess)(NSDictionary *);
@property (nonatomic,copy)void (^thirdLoginFailure)(NSError *);

@end


@implementation CIAccountThirdLoginUtil
//获取单例
+ (CIAccountThirdLoginUtil *)getInstance{
if (!thirdLogin) {
thirdLogin = [[CIAccountThirdLoginUtil alloc] init];

}

return thirdLogin;
}

2.6 在工具类中构建登录QQ方法

1
2
3
4
5
6
7
8
- (void)loginQQSuccess:(void (^)(id response))successBlock failure:(void (^)(NSError *error))failureBlock{
_thirdLoginSuccess = successBlock;
_thirdLoginFailure = failureBlock;

_tencentOAuth = [[TencentOAuth alloc] initWithAppId:QQ_APP_ID andDelegate:self];
NSArray *permissions= [NSArray arrayWithObjects:@"get_user_info",@"get_simple_userinfo",@"add_t",nil];
[_tencentOAuth authorize:permissions inSafari:NO];
}

2.7 实现QQ代理方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#pragma mark - TencentSessionDelegate

//登录成功回调
- (void)tencentDidLogin{
if (_tencentOAuth.accessToken && 0 != [_tencentOAuth.accessToken length]){
[_tencentOAuth getUserInfo];
}else{
NSError *error = [CIAccountError createError:ErrorThirdLoginFailure];
_thirdLoginFailure(error);
}
}
//登录失败回调
- (void)tencentDidNotLogin:(BOOL)cancelled{
if (cancelled) {
NSError *error = [CIAccountError createError:ErrorThirdLoginCancel];
_thirdLoginFailure(error);
}else{
NSError *error = [CIAccountError createError:ErrorThirdLoginFailure];
_thirdLoginFailure(error);
}
}
//没有网络
- (void)tencentDidNotNetWork{
NSError *error = [CIAccountError createError:ErrorNetNone];
_thirdLoginFailure(error);
}
//获取回调的用户信息
- (void)getUserInfoResponse:(APIResponse *)response{
NSDictionary *result = @{@"openid":_tencentOAuth.openId,
@"nickname":response.jsonResponse[@"nickname"],
@"account_type":@"qq",
@"access_token":_tencentOAuth.accessToken,
@"third_appid":QQ_APP_ID};
_thirdLoginSuccess(result);
}

2.8 登录时调用工具类的loginQQ方法

1
2
3
4
5
[thirdLoginUtil loginQQSuccess:^(id response) {
[self thirdLogin:response];
//拿到返回的数据进行客户端自身登录
} failure:^(NSError *error) {
}];

微信接入

官方文档

iOS接入指南

SDK下载地址

微信登录功能

2.1 配置微信需要的静态库,分别是

1
"SystemConfiguration.framework","libz.dylib","libsqlite3.0.dylib","libc++.dylib"

2.2 在配置文件Info.plist中配置应用白名单,必须添加以下所有字段,否则可能无法跳转

1
2
3
4
5
<key>LSApplicationQueriesSchemes</key>
<array>
<string>wechat</string>
<string>weixin</string>
</array>

2.3 点击XCode项目名,选择Info,添加微信的URL Types

identifier:weixin URL Schemes:weixin前缀后+QQ App ID(用户自己申请的账号)

2.4 在AppDelegate中配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// 1
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
//微信注册
[WXApi registerApp:WX_APP_ID];
return YES;
}
// 2
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation{
return [WXApi handleOpenURL:url delegate:self];
}
// 3
- (BOOL)application:(UIApplication *)application handleOpenURL:(NSURL *)url{
return [WXApi handleOpenURL:url delegate:self];
}


#pragma mark - WXApiDelegate
// 4
- (void)onReq:(BaseReq*)req{

}
// 5
- (void)onResp:(BaseResp*)resp {

//获取用户信息

}

2.5 为微信创建一个另外的单例工具类 实现如下方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110

- (void)loginWxAuthWithBlock:(void (^)(NSDictionary *userInfo))block {
//先判断有无安装微信
if (![WXApi isWXAppInstalled]) {
return;
}
SendAuthReq* req = [[SendAuthReq alloc] init];
req.scope = @"snsapi_userinfo";
req.state = @"CIAccount";
req.openID = WX_APP_ID;

[WXApi sendReq:req];
_blockGetUserInfoSuccess = block;
}

- (void)getWxAuthUserInfo:(BaseResp*)resp {

NSMutableDictionary *results = [[NSMutableDictionary alloc] init];
[results setObject:@"ret" forKey:@"0"];//获取失败
SendAuthResp *temp = (SendAuthResp*)resp;

if (![temp.state isEqualToString:@"CIAccount"]) {
[self results:nil withRet:@"-1"];//state(QQID 不匹配)
return;
}

if (temp.errCode == 0) {//用户同意
NSString *wxAuthUrlString = @"https://api.weixin.qq.com/sns/oauth2/access_token";
NSDictionary *authParams = @{
@"appid":WX_APP_ID,
@"secret":WX_APP_SECRET,
@"code":[NSString stringWithFormat:@"%@", temp.code],
@"grant_type":@"authorization_code"
};
WS(weakSelf);
[CINetworkUtils getWithUrl:wxAuthUrlString withParameters:authParams success:^(id responseObject) {
__strong typeof (weakSelf) StrongSelf = weakSelf;
if (!StrongSelf) {
return ;
}
if (!responseObject) {
//返回值为空 code没有通过验证
[StrongSelf results:nil withRet:@"-6"];
}else{
StrongSelf.authInfo = responseObject;
[StrongSelf getUserInfo];
}
} failure:^(NSError *error) {
__strong typeof (weakSelf) strongSelf = weakSelf;
if (!strongSelf) {
return ;
}
//code没有通过验证 发送错误码
[strongSelf results:nil withRet:@"-7"];
}];

}else if (temp.errCode == -2) {//用户取消授权
[self results:nil withRet:@"-2"];
}else if (temp.errCode == -4 ){//用户拒绝授权
[self results:nil withRet:@"-4"];
}
}

- (void)getUserInfo {

WS(weakSelf);
NSString *wxUserInfoUrlString = @"https://api.weixin.qq.com/sns/userinfo";
NSDictionary *authParams = @{
@"access_token":_authInfo[@"access_token"],
@"openid":_authInfo[@"openid"]
};
[CINetworkUtils getWithUrl:wxUserInfoUrlString withParameters:authParams success:^(id responseObject) {

__strong typeof (weakSelf) strongSelf = weakSelf;
if (!strongSelf) {
return;
}
strongSelf.userInfo = responseObject;
if (strongSelf.blockGetUserInfoSuccess) {
if (strongSelf.userInfo) {
//成功
[strongSelf results:responseObject withRet:@"1"];
}else {
[strongSelf results:nil withRet:@"-8"];//没有获取到用户信息
}
}
}
failure:^(NSError *error) {
__strong typeof (weakSelf) strongSelf = weakSelf;
if (!strongSelf) {
return;
}
//请求出错,没有获取到用户信息
[strongSelf results:nil withRet:@"-9"];
}];

}

- (void)results:(NSDictionary *)results withRet:(NSString *)type{

if (!results) {
_blockGetUserInfoSuccess(@{@"ret":type});
return;
}

NSMutableDictionary *dic = [[NSMutableDictionary alloc] initWithDictionary:results];
[dic setObject:@"1" forKey:@"ret"];
[dic setObject:_authInfo[@"access_token"] forKey:@"access_token"];
_blockGetUserInfoSuccess(dic);
}

2.6 在工具类中构造loginWX方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
- (void)loginWXSuccess:(void (^)(id response))successBlock failure:(void (^)(NSError *error))failureBlock{
//调用微信工具类的方法
[[CIAccountWXUtil sharedManager] loginWxAuthWithBlock:^(NSDictionary *userInfo) {
NSLog(@"%@",userInfo);
if (userInfo && userInfo[@"ret"]) {
NSString *ret = [NSString stringWithFormat:@"%@", userInfo[@"ret"]];
if ([ret isEqualToString:@"1"]) {
NSDictionary *param = @{@"account_type":@"weixin",
@"openid":userInfo[@"openid"],
@"nickname":userInfo[@"nickname"],
@"access_token":userInfo[@"access_token"],
@"third_appid":WX_APP_ID,@"unionid":userInfo[@"unionid"]};
successBlock(param);
}else {
NSError *error = [CIAccountError createError:ErrorThirdLoginFailure];

failureBlock(error);
}
}

}];
}

2.7 登录时调用工具类的loginWX方法

1
2
3
4
5
[thirdLoginUtil loginWXSuccess:^(id response) {
//获取数据实现客户端登录
} failure:^(NSError *error) {
[self ShowExclaHud:error.localizedDescription];
}];

2.8 tips

  • 开发者接入微信登录时,先检测用户手机是否已安装微信客户端(使用sdk中isWXAppInstalled函数 ),对未安装的用户隐藏微信登录按钮,只提供其他登录方式
    • 微信自身有一个bug,如果未登录微信返回后没有回调接口,无法判断到回调

微博接入

官方文档

接入文档&SDK
API列表
常见错误

2.1 在配置文件Info.plist中配置应用白名单,必须添加以下所有字段,否则可能无法跳转

1
2
3
4
5
6
7
8
<key>LSApplicationQueriesSchemes</key>
<array>
<string>sinaweibohd</string>
<string>sinaweibo</string>
<string>sinaweibosso</string>
<string>weibosdk</string>
<string>weibosdk2.5</string>
</array>

2.2 点击XCode项目名,选择Info,添加微博的URL Types

identifier:wb URL Schemes:wb前缀后+Weibo App ID(用户自己申请的账号)

2.3 在AppDelegate中配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
	// 1
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
//微博注册
[WeiboSDK enableDebugMode:YES];
[WeiboSDK registerApp:WeiBo_APP_ID];
return YES;
}
//2
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation{
return [WeiboSDK handleOpenURL:url delegate:self];
}

// 3
- (BOOL)application:(UIApplication *)application handleOpenURL:(NSURL *)url{
return [WeiboSDK handleOpenURL:url delegate:self];
}
#pragma mark - WeiBoDelegate
// 4
- (void)didReceiveWeiboRequest:(WBBaseRequest *)request{

}
// 5
- (void)didReceiveWeiboResponse:(WBBaseResponse *)response{
//获取用户信息
}

2.4 工具类中构造loginWB方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
- (void)loginWeiBoSuccess:(void (^)(id response))successBlock failure:(void (^)(NSError *error))failureBlock{
_thirdLoginSuccess = successBlock;
_thirdLoginFailure = failureBlock;

WBAuthorizeRequest *request = [WBAuthorizeRequest request];
request.redirectURI = WeiBo_RedirectURI;
request.scope = @"all";
request.userInfo = @{@"myKey": @"myValue"};
[WeiboSDK sendRequest:request];

}

#pragma mark - 微博登录在appdelegate回调

- (void)getWeiboUserInfo:(WBBaseResponse *)response{

NSString *weiboOpenId = [(WBAuthorizeResponse *)response userID];
if (weiboOpenId) {
//获取用户信息,昵称
NSString *weiboUrl = @"https://api.weibo.com/2/users/show.json";
NSDictionary *weiboParam = @{@"access_token":[(WBAuthorizeResponse *)response accessToken],
@"uid":weiboOpenId};
[CINetworkUtils getWithUrl:weiboUrl withParameters:weiboParam success:^(id responseObject) {
NSString *weiboNickName = responseObject[@"name"];
NSDictionary *param = @{@"openid":weiboOpenId,
@"nickname":weiboNickName,
@"account_type":@"weibo",
@"access_token":[(WBAuthorizeResponse *)response accessToken],
@"third_appid":WeiBo_APP_ID};
_thirdLoginSuccess(param);
} failure:^(NSError *error) {
NSError *createError = [CIAccountError createError:ErrorThirdLoginFailure];
_thirdLoginFailure(createError);
}];
}else{
NSError *error = [CIAccountError createError:ErrorThirdLoginFailure];
_thirdLoginFailure(error);
}
}

2.5 登录时调用loginWB方法

1
2
3
4
5
[thirdLoginUtil loginWeiBoSuccess:^(id response) {
//获取数据实现客户端登录
} failure:^(NSError *error) {
[self ShowExclaHud:error.localizedDescription];
}];