·URL Scheme:App间的跳转及通信
·App间跳转场景
·登陆系统:
·跨平台,跨App
·标记用户,个性化的推送
·使用第三方登录(减少注册成本 / 无须维护敏感信息)
·微信 / QQ / 微博 / facebook / Twitter
·登录系统通用技术
·framework的使用和集成
·常用的第三方认证和账户体系
·业务逻辑的设计和实现
·库Library
·代码共享 / 保护核心代码
·提高编译速度 / 减少代码提及(系统)
·静态库
·.a文件
·编译时期拷贝
·增大代码提及 / 不可改变
·动态库
·.dylib
·编译时期只存储引用,运行时加载到内存
·无须拷贝减少体积 / 性能损失 / 安全性

·Framework
·资源的打包方式
·支持静态库 / 动态库
·系统的Framework都是动态库
·支持Extension共享 - Embedded framework
静态库的制作:
·创建static Library实现业务逻辑
·设置需要暴露的头文件
·模拟器 / 设备分别编译 / 设置Settings
·合并静态库lipo - create ***.a ***.a -output ***.a
·静态库(.a)本身是二进制文件
·需要手动引入头文件使用
·一般需要设置Other Linker Flags等

·创建framework实现业务逻辑
·设置public的头文件
·模拟器 / 设备 / 分别编译 / 设置Settings
·合并framework
·引入framework 即包含头文件
·头文件的引入
·一般需要设置Other Linker Flags等

OAuth授权
·第三方登录使用用户名 / 密码(安全 / 用户成本)
·开放协议,标准的方式去访问需要用户授权的API服务
OpenID
·明文的安全性 / 不同的业务,无法隔离
·隐藏明文 / 每个App独立的openID

首先下载TencentOpenApi,在podfile中添加:
- # pod TencentOpenAPI
- pod 'TencentOpenAPI', :git => 'https://github.com/everfire130/TencentOpenAPI.git'
或者在腾讯开放平台中下载SDK:SDK下载 — QQ互联WIKI
- //
- // GSCLogin.h
- // GSCApp1
- //
- // Created by gsc on 2024/6/22.
- //
-
- #import
-
- NS_ASSUME_NONNULL_BEGIN
-
- typedef void(^GSCLoginFinishBlock)(BOOL isLogin);
-
- @interface GSCLogin : NSObject
-
- @property(nonatomic,strong,readonly)NSString *nick;
- @property(nonatomic,strong,readonly)NSString *address;
- @property(nonatomic,strong,readonly)NSString *avatarUrl;
-
- +(instancetype)sharedLogin;
-
- #pragma - mark - 登录
-
- -(BOOL)isLogin;
- -(void)loginWithFinishBlock:(GSCLoginFinishBlock)finishBlock;
- -(void)logOut;
-
- #pragma - mark - 分享
- -(void)shareToQQWithArticleUrl:(NSURL *)articleUrl;
-
-
- //
- // GSCLogin.m
- // GSCApp1
- //
- // Created by gsc on 2024/6/22.
- //
-
- #import "GSCLogin.h"
- #import "TencentOpenAPI/QQApiInterface.h"
- #import "TencentOpenAPI/TencentOAuth.h"
-
- @interface GSCLogin () <TencentSessionDelegate>
-
- @property (nonatomic, strong, readwrite) TencentOAuth *oauth;
- @property (nonatomic, copy, readwrite) GSCLoginFinishBlock finishBlock;
- @property (nonatomic, assign, readwrite) BOOL isLogin;
-
- @end
-
- @implementation GSCLogin
-
- +(instancetype)sharedLogin{
- static GSCLogin *login;
- static dispatch_once_t onceToken;
- dispatch_once(&onceToken, ^{
- login = [[GSCLogin alloc] init];
- });
- return login;
- }
-
- -(instancetype)init{
- self = [super init];
- if(self){
- _isLogin = NO;
- _oauth = [[TencentOAuth alloc] initWithAppId:@"123456" andDelegate:self];
- }
- return self;
- }
- #pragma - mark - 登录
-
- -(BOOL)isLogin{
- return _isLogin;
- }
- -(void)loginWithFinishBlock:(GSCLoginFinishBlock)finishBlock{
- _finishBlock = [finishBlock copy];
-
- _oauth.authMode = kAuthModeClientSideToken;
- [_oauth authorize:@[kOPEN_PERMISSION_GET_USER_INFO,
- kOPEN_PERMISSION_GET_SIMPLE_USER_INFO,
- kOPEN_PERMISSION_ADD_ALBUM,
- kOPEN_PERMISSION_ADD_TOPIC,
- kOPEN_PERMISSION_CHECK_PAGE_FANS,
- kOPEN_PERMISSION_GET_INFO,
- kOPEN_PERMISSION_GET_OTHER_INFO,
- kOPEN_PERMISSION_LIST_ALBUM,
- kOPEN_PERMISSION_UPLOAD_PIC,
- kOPEN_PERMISSION_GET_VIP_INFO,
- kOPEN_PERMISSION_GET_VIP_RICH_INFO]];
-
- }
- -(void)logOut{
- [_oauth logout:self];
- _isLogin = NO;
- }
-
- #pragma mark - delegate
-
- -(void)tencentDidLogin{
- _isLogin = YES;
- [_oauth getUserInfo];
- }
-
- -(void)tencentDidNotLogin:(BOOL)cancelled{
- if(_finishBlock){
- _finishBlock(NO);
- }
- }
-
- -(void)tencentDidNotNetWork{
-
- }
-
- -(void)tencentDidLogout{
-
- }
-
- -(void)getUserInfoResponse:(APIResponse *)response{
- NSDictionary *userInfo = response.jsonResponse;
- _nick = userInfo[@"nickname"];
- _address = userInfo[@"city"];
- _avatarUrl = userInfo[@"figureurl_qq_2"];
- if(_finishBlock){
- _finishBlock(YES);
- }
- }
- #pragma - mark - 分享
- -(void)shareToQQWithArticleUrl:(NSURL *)articleUrl{
- QQApiNewsObject *newsObj = [QQApiNewsObject objectWithURL:articleUrl title:@"ios" description:@"iosDevLearn" previewImageURL:nil];
- SendMessageToQQReq *req = [SendMessageToQQReq reqWithContent:newsObj];
- __unused QQApiSendResultCode sent = [QQApiInterface SendReqToQZone:req];
- }
-
-
- @end
-
-
-
- @end
-
- NS_ASSUME_NONNULL_END
- //
- // GSCMineViewController.m
- // GSCApp1
- //
- // Created by gsc on 2024/6/22.
- //
-
- #import "GSCMineViewController.h"
- #import "GSCLogin.h"
- #import "SDWebImage/SDWebImage.h"
-
-
- @interface GSCMineViewController ()<UITableViewDelegate, UITableViewDataSource>
-
- @property (nonatomic, strong, readwrite) UITableView *tableView;
- @property (nonatomic, strong, readwrite) UIView *tableViewHeaderView;
- @property (nonatomic, strong, readwrite) UIImageView *headerImageView;
-
- @end
-
- @implementation GSCMineViewController
-
- -(instancetype)init{
- self = [super init];
- if(self){
- self.tabBarItem.title = @"我的";
- self.tabBarItem.image = [UIImage imageNamed:@"icon.bundle/home@2x.png"];
- self.tabBarItem.selectedImage = [UIImage imageNamed:@"icon.bundle/home_selected@2x.png"];
- }
- return self;
- }
-
- - (void)viewDidLoad {
- [super viewDidLoad];
- self.view.backgroundColor = [UIColor whiteColor];
- [self.view addSubview:({
- _tableView = [[UITableView alloc] initWithFrame:self.view.bounds style:UITableViewStyleGrouped];
- _tableView.delegate = self;
- _tableView.dataSource = self;
- _tableView;
- })];
- }
-
-
- #pragma mark - Navigation
-
- -(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
- return 2;
- }
-
- -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
- UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"mineTableViewCell"];
- if(!cell){
- cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"mineTableView"];
- }
- return cell;
- }
-
- -(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
- return 60;
- }
-
- -(nullable UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section{
- if(!_tableViewHeaderView){
- _tableViewHeaderView = [[UIView alloc] initWithFrame:CGRectMake(0, 30, self.view.frame.size.width, self.view.frame.size.height)];
- _tableViewHeaderView.backgroundColor = [UIColor whiteColor];
-
- [_tableViewHeaderView addSubview:({
- _headerImageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 30, self.view.frame.size.width, self.view.frame.size.height)];
- _headerImageView.backgroundColor = [UIColor whiteColor];
- _headerImageView.contentMode = UIViewContentModeScaleAspectFit;
- _headerImageView.clipsToBounds = YES;
- _headerImageView.userInteractionEnabled = YES;
- _headerImageView;
- })];
-
- [_tableViewHeaderView addGestureRecognizer:({
- UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(_tapImage)];
- tapGesture;
- })];
- }
- return _tableViewHeaderView;
- }
-
- -(CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section{
- return 200;
- }
-
- -(void)tableView:(UITableView *)tableView willDisplayHeaderView:(nonnull UIView *)view forSection:(NSInteger)section{
- if(![[GSCLogin sharedLogin] isLogin]){
- [_headerImageView setImage:[UIImage imageNamed:@"icon.bundle/prettydog.png"]];
- }else{
- [self.headerImageView sd_setImageWithURL:[NSURL URLWithString:[GSCLogin sharedLogin].avatarUrl]];
- }
- }
-
- -(void)tableView:(UITableView *)tableView willDisplayCell:(nonnull UITableViewCell *)cell forRowAtIndexPath:(nonnull NSIndexPath *)indexPath{
- if(indexPath.row == 0){
- cell.textLabel.text = [[GSCLogin sharedLogin] isLogin] ? [GSCLogin sharedLogin].nick: @"昵称";
- }else{
- cell.textLabel.text = [[GSCLogin sharedLogin] isLogin] ? [GSCLogin sharedLogin].address:@"地区";
- }
-
- }
-
- #pragma mark -
-
- -(void)_tapImage{
- __weak typeof(self) weakSelf = self;
- if(![[GSCLogin sharedLogin] isLogin]){
- // 如果未登录则拉起登录
- [[GSCLogin sharedLogin] loginWithFinishBlock:^(BOOL isLogin){
- __strong typeof(self) strongSelf = self;
- if(isLogin){
- [strongSelf.tableView reloadData];
- }
- }];
- }else{
- // 已登录则退出登录
- [[GSCLogin sharedLogin] logOut];
- [self.tableView reloadData];
- }
- }
-
- @end
集成SDK实现登录与分享:
·申请接入,获取appid和apikey
·集成SDK设置对应的settings及URL Scheme
·业务逻辑的基础UI和交互(登录 / 分享 ...)
·通过用户登录验证和授权,获取Access Token
·通过Access Token获取用户的OpenID
·通过OpenAPI请求访问或修改用户授权的资源
·客户端保存相应用户信息,按需展示
·调用其它API实现分享等逻辑