iOS第三方登录及分享入门指南 —— QQ(一)

导语:

第三方登录和分享是现在App的「主流功能」,不管友盟,还是ShareSDK,都有很好的集成文档,Please feel free to check!至于写这篇指南的初衷是刚好公司最近做Standard Module,也刚好需要集成这一块,还得做成友盟那样以供使用。(心累,迫于老大的淫威之下

QQ SDK官方文档

实现QQ登录

一、准备工作

  1. 腾讯开放平台,注册成为开发者。
  2. 创建应用,申请你的appidappkey

!!!Ps:在准备工作的时候,可能会遇到一个坑:QQ互联开放平台腾讯开放平台是相互独立的,所以 若已在QQ互联创建过应用,可在创建应用时选择关联QQ互联,输入在QQ互联创建的网页应用APPID、APPKEY即可完成关联。(两个平台做一样的事,鹅厂真心钱多

创建应用.png
appid和appkey的用途
  • appid:应用的唯一标识。在OAuth2.0认证过程中,appid的值即为oauth_consumer_key的值。
  • appkey:appid对应的密钥,访问用户资源时用来验证应用的合法性。在OAuth2.0认证过程中,appkey的值即为oauth_consumer_secret的值。

二、集成SDK

下载好完整包,如图导入工程需要的文件。

14932765373824.jpg
  • TencentOpenAPI.framework打包了iOS SDK的头文件定义和具体实现
  • TencentOpenApi_iOS_Bundle.bundle 打包了iOS SDK需要的资源文件

三、配置工程

1. 添加SDK依赖的系统库文件

Security.framework
SystemConfiguration.framework
CoreTelephony.framework
CoreGraphics.Framework
libiconv.tbd
libsqlite3.tbd
libstdc++.tbd
libz.tbd

2. 修改必要的工程配置属性

在工程配置中的Build Settings一栏中找到Linking配置区,给Other Linker Flags配置项添加属性值-fobjc-arc

配置属性.jpg
3. 修改Info.plist文件

在XCode中,选中TARGETS一栏,在Info标签栏中找到URL Types,添加一条新的URL scheme。(必须填写

Identifier: tencentopenapi
URL Schemes: tencent + "appid"

想要实现应用间跳转,而不是打开一个登陆网页,在Info.plist中添加LSApplicationQueriesSchemes

<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>mqqopensdkapiV3</string>
<string>mqqopensdkapiV3</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>mqzoneopensdk</string>
</array>

四、代码实现

1.AppDelegate

在AppDelegate中添加头文件,并重写AppDelegate的handleOpenURLopenURL方法

  • iOS9之前,分别重写handleOpenURL && openURL方法

      //handleOpenURL(ios10已弃用)
      NS_DEPRECATED_IOS(2_0, 9_0, "Please use application:openURL:options:")
      - (BOOL)application:(UIApplication *)application handleOpenURL:(NSURL *)url{
          [TencentOAuth HandleOpenURL:url];
          return YES;
      }
         
      //openURL(iOS10已弃用)
      NS_DEPRECATED_IOS(4_2, 9_0, "Please use application:openURL:options:")
      - (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation{
          [TencentOAuth HandleOpenURL:url];
          return YES;
      }
    
  • iOS9之后,handleOpenURL && openURL 合成为同一个方法

      //handleOpenURL && openURL
      - (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options{
          [TencentOAuth HandleOpenURL:url];
          return YES;
      }
    
2.登录控制器实现对应的代理事件

在LoginViewController添加对应的头文件,添加QQ Login点击事件,实现TencentSessionDelegate的对应delegate事件。

#import "LoginViewController.h"
#import <TencentOpenAPI/TencentOAuth.h>
 
@interface LoginViewController ()<TencentSessionDelegate>
@property (nonatomic, strong) TencentOAuth* tencentOAuth;
@end

@implementation LoginViewController

- (void)loginBtnClicked{
    self.tencentOAuth = [[TencentOAuth alloc] initWithAppId:@"你申请的appID" andDelegate:self];

    //在这个数组里,可以添加你想要用户授权的信息的相关字段
    //注意,若是授权太多信息, 用户可能会拒绝授权
    NSArray *permissions = [NSArray arrayWithObjects:
                            @"get_user_info",
                            @"get_simple_userinfo",
                            @"add_t",
                            nil];
    //授权类型
    [self.tencentOAuth setAuthShareType:AuthShareType_QQ];
    //调用SDK登录
    [self.tencentOAuth authorize:permissions inSafari:false];
}

- (void)tencentDidNotNetWork{
    NSLog(@"网络连接失败");
}

- (void)tencentDidLogin{
    if (self.tencentOAuth.accessToken && 0 != [self.tencentOAuth.accessToken length]){
        //accessToken有效期3个月,想要获取用户信息,必须调用getUserInfo
        NSLog(@"记录登录用户的OpenID、Token以及过期时间");
        [self.tencentOAuth getUserInfo];
    }else{
        NSLog(@"登录不成功 没有获取accesstoken");
    }
}

- (void)tencentDidNotLogin:(BOOL)cancelled{
    if (cancelled){
        NSLog(@"用户取消登录");
    }else{
        NSLog(@"登录失败");
    }
}
3.获取用户信息

当DidLogin调用getUserInfo,会有此回调返回userInfo

- (void)getUserInfoResponse:(APIResponse *)response{
 if (response  && response.retCode == URLREQUEST_SUCCEED) {
     NSDictionary* userInfo = [response jsonResponse];
     NSLog(@"%@",userInfo);
 }else{
     NSLog(@"QQ auth fail ,getUserInfoResponse:%d", response.detailRetCode);
 }
}
4.登录篇注意事项
  • �当未调起原生客户端授权,只弹出网页,检查URL scheme设置 && 是否添加LSApplicationQueriesSchemesInfo.plist

  • 当Xcode提示“未选择授权类型”,可添加:

      [self.tencentOAuth setAuthShareType:AuthShareType_QQ];
    

分割线,接下来讲讲QQ分享

实现QQ分享

步骤同上一、二、三

代码实现

1.在AppDelegate中初始化OAuth
@interface AppDelegate ()<QQApiInterfaceDelegate>
@property (nonatomic, strong) TencentOAuth* tencentOAuth;
@end

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // Override point for customization after application launch.
    // 根据自己的AppID初始化OAuth
    self.tencentOAuth = [[TencentOAuth alloc] initWithAppId:@"QQAppID" andDelegate:nil];
    return YES;
}
2.在AppDelegate中实现回调事件

此回调事件,需要在AppDelegate里添加头文件<TencentOpenAPI/QQApiInterface.h>,重写handleOpenURL && openURL方法

  • 添加头文件

      #import <TencentOpenAPI/QQApiInterface.h>
    
  • 重写handleOpenURL方法

      //iOS9之前,分别重写`handleOpenURL && openURL`方法
      //handleOpenURL(ios10已弃用)
      NS_DEPRECATED_IOS(2_0, 9_0, "Please use application:openURL:options:")
      - (BOOL)application:(UIApplication *)application handleOpenURL:(NSURL *)url{
          if ([url.scheme isEqualToString:[NSString stringWithFormat:@"tencent%@",QQAppID]]) {
              return [QQApiInterface handleOpenURL:url delegate:self];
      }
      else{
              return YES;
          }
      }
    
      //iOS9之后,`handleOpenURL && openURL` 合成为同一个方法
      //handleOpenURL && openURL
      - (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options{
          if ([url.scheme isEqualToString:[NSString stringWithFormat:@"tencent%@",QQAppID]]) {
              return [QQApiInterface handleOpenURL:url delegate:self];
      }
      else{
              return YES;
          }
      }
    
  • 处理回调事件

      @interface AppDelegate ()<QQApiInterfaceDelegate>
    
      - (void)onReq:(QQBaseReq *)req{
            NSLog(@"处理来至QQ的请求");
        }
         
      - (void)onResp:(QQBaseResp *)resp{
          NSLog(@"处理来至QQ的响应");
          NSLog(@"response")
          switch (resp.type)
          {
              case ESENDMESSAGETOQQRESPTYPE:
              {
                  SendMessageToQQResp* sendResp = (SendMessageToQQResp*)resp;
                  if ([sendResp.result isEqualToString:@"0"]) {
                      UIAlertController* vc = [UIAlertController alertControllerWithTitle:@"成功" message:@"QQ分享成功" preferredStyle:UIAlertControllerStyleAlert];
                      [vc addAction:[UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
                      }]];
                      [self.window.rootViewController presentViewController:vc animated:YES completion:nil];
                  }
                  else {
                      UIAlertController* vc = [UIAlertController alertControllerWithTitle:@"失败" message:@"QQ分享失败" preferredStyle:UIAlertControllerStyleAlert];
                      [vc addAction:[UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
                         }]];
                      [self.window.rootViewController presentViewController:vc animated:YES completion:nil];
                  }
                  break;
              }
              default:
              {
                  break;
              }
          }
      }
         
      - (void)isOnlineResponse:(NSDictionary *)response{
          NSLog(@"处理QQ在线状态的回调");
          NSLog(@"response : %@",response);
      }
    
3.在ShareViewController中导入对应的头文件
#import <TencentOpenAPI/TencentOAuth.h>
#import <TencentOpenAPI/TencentMessageObject.h>
#import <TencentOpenAPI/TencentApiInterface.h>
#import <TencentOpenAPI/QQApiInterface.h>
#import <TencentOpenAPI/QQApiInterfaceObject.h>
4.在ShareViewController实现分享事件示例代码
  • 文本

      - (void)shareText {
    
          if (![TencentOAuth iphoneQQInstalled]) {
              UIAlertController* vc = [UIAlertController alertControllerWithTitle:@"你还没有安装QQ客户端" message:nil preferredStyle:UIAlertControllerStyleAlert];
              [vc addAction:[UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
              }]];
              [self presentViewController:vc animated:YES completion:nil];
          }
          else{
              QQApiTextObject* object = [QQApiTextObject objectWithText:@"分享的内容"];
              [object setShareDestType:ShareDestTypeQQ];
              SendMessageToQQReq* req = [SendMessageToQQReq reqWithContent:object];
      
              QQApiSendResultCode code = [QQApiInterface sendReq:req];
              NSLog(@"result code : %d",code);
          }
      }
    
  • 图片

      - (void)shareImage {
      
          if (![TencentOAuth iphoneQQInstalled]) {
          UIAlertController* vc = [UIAlertController alertControllerWithTitle:@"你还没有安装QQ客户端" message:nil preferredStyle:UIAlertControllerStyleAlert];
          [vc addAction:[UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
          }]];
          [self presentViewController:vc animated:YES completion:nil];
          }
          else{
              NSString* filePath = [[NSBundle mainBundle] pathForResource:@"icon" ofType:@"png"];
              NSData* imageData = [NSData dataWithContentsOfFile:filePath];
              QQApiImageObject* obj = [QQApiImageObject objectWithData:imageData previewImageData:imageData title:@"title" description:@"github猫"];
              [obj setShareDestType:ShareDestTypeQQ];
              SendMessageToQQReq* req = [SendMessageToQQReq reqWithContent:obj];
              QQApiSendResultCode code = [QQApiInterface sendReq:req];
              NSLog(@"result code : %d",code);
          }
      }
    
  • 新闻

      - (void)shareNews {
    
          if (![TencentOAuth iphoneQQInstalled]) {
              UIAlertController* vc = [UIAlertController alertControllerWithTitle:@"你还没有安装QQ客户端" message:nil preferredStyle:UIAlertControllerStyleAlert];
              [vc addAction:[UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
              }]];
              [self presentViewController:vc animated:YES completion:nil];
          }
          else{
              //分享跳转URL,注意要经过UTF8处理
              NSString *url = [@"http://xxx.xxx.xxx/" stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];
              //分享图预览图URL地址
              NSString *previewImageUrl = @"preImageUrl.png";
              QQApiNewsObject *newsObj = [QQApiNewsObject objectWithURL :[NSURL URLWithString:url]
                                                                   title: @"title"
                                                            description :@"description"
                                                         previewImageURL:[NSURL URLWithString:previewImageUrl]];
              SendMessageToQQReq *req = [SendMessageToQQReq reqWithContent:newsObj];
      
              //将内容分享到qq
              //QQApiSendResultCode sent = [QQApiInterface sendReq:req];
              //将内容分享到qzone
              QQApiSendResultCode sent = [QQApiInterface SendReqToQZone:req];
          }
      }
    
  • 分享类型:

分享消息类型 QQ好友 QQ空间 web QQ好友 web QQ空间
QQApiTextObject ✔️
QQApiImageObject ✔️
QQApiNewsObject ✔️ ✔️ ✔️ ✔️
QQApiAudioObject ✔️ ✔️ ✔️ ✔️
QQApiVideoObject ✔️ ✔️ ✔️ ✔️
5.分享篇注意事项
  • 分享的回调无法执行,请注意实现<QQApiInterfaceDelegate>,即

      [QQApiInterface handleOpenURL:url delegate:self(代理对象)];
    
  • 当Xcode打印“result code 为 -2”时(未知的分享类型),请注意实现setShareDestType方法,即

      QQApiTextObject* object = [QQApiTextObject objectWithText:@"分享的内容"];
      [object setShareDestType:ShareDestTypeQQ];
    

结束语

我在使用原生集成时,遇到的这些坑都由于Tencent的文档太久没更新导致花了一段时间。最后仔细的查看SDK接口才发现解决方式,希望能够给看到这篇文章的人提供到一点帮助。在接下来一段时间,还会继续写几篇关于 微信、微博、Facebook等等的SDK集成指南。还在研究中,共勉啦。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,362评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,330评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,247评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,560评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,580评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,569评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,929评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,587评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,840评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,596评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,678评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,366评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,945评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,929评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,165评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,271评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,403评论 2 342

推荐阅读更多精彩内容