版权声明
本文由陈怀哲首发自简书:http://www.jianshu.com/users/9f2e536b78fd/latest_articles;
微信公众号:陈怀哲(chenhuaizhe2016);
无需授权即可转载,但请自觉保留以上版权声明。
请确保先阅读过第一篇:《在iOS工程中集成facebook第三方登录》,再来看这一篇
上一篇我们已经可以通过facebook账号实现第三方登录了,但是发现每次app重新启动,都要重新登录。现在来解决这个问题。
Demo地址: facebookLoginDemo
</br>
在本地保存密码的工具
我们可以直接使用facebook的官方demo里面的两个类来管理我们的密码
** 一定要添加Security.framework这个依赖库**
SUCacheItem这个类实现了<NSSecureCoding>协议,对 profile和token进行归档和反归档。
@interface SUCacheItem : NSObject<NSSecureCoding>
@property (nonatomic, strong) FBSDKProfile *profile;
@property (nonatomic, strong) FBSDKAccessToken *token;
@end
SUCache这个类用来对SUCacheItem进行增删改查操作。
#import "SUCacheItem.h"
// A helper class to store items in keychain.
@interface SUCache : NSObject
+ (SUCacheItem *)itemForSlot:(NSInteger)slot;
+ (void)saveItem:(SUCacheItem *)item slot:(NSInteger)slot;
+ (void)deleteItemInSlot:(NSInteger)slot;
+ (void)clearCache;
@end
登录
现在的登录逻辑需要改一下,我们先判断一下本地储存token没有,如果本地游储存,判断是否是有效的,如果有效,就直接登录进去。如果无效了,就删除本地的token,进行登录操作。
代码修改成下面这样。
#pragma mark - login
//自定义login button的点击事件
- (IBAction)loginBtnClicked:(id)sender {
NSInteger slot = 0;
FBSDKAccessToken *token = [SUCache itemForSlot:slot].token;
if (token) {
[self autoLoginWithToken:token];
}
else {
[self newLogin];
}
}
- (void)autoLoginWithToken:(FBSDKAccessToken *)token {
[FBSDKAccessToken setCurrentAccessToken:token];
FBSDKGraphRequest *request = [[FBSDKGraphRequest alloc] initWithGraphPath:@"me" parameters:nil];
[request startWithCompletionHandler:^(FBSDKGraphRequestConnection *connection, id result, NSError *error) {
//token过期,删除存储的token和profile
if (error) {
NSLog(@"The user token is no longer valid.");
NSInteger slot = 0;
[SUCache deleteItemInSlot:slot];
[FBSDKAccessToken setCurrentAccessToken:nil];
[FBSDKProfile setCurrentProfile:nil];
}
//做登录完成的操作
else {
}
}];
}
- (void)newLogin {
FBSDKLoginManager *login = [[FBSDKLoginManager alloc] init];
[login
logInWithReadPermissions: @[@"public_profile"]
fromViewController:self
handler:^(FBSDKLoginManagerLoginResult *result, NSError *error) {
NSLog(@"facebook login result.grantedPermissions = %@,error = %@",result.grantedPermissions,error);
if (error) {
NSLog(@"Process error");
} else if (result.isCancelled) {
NSLog(@"Cancelled");
} else {
NSLog(@"Logged in");
}
}];
}
token 和 profile的保存
在通知事件里如果获取到了新的token或者profile,就把它们保存到SUCacheItem的实例中去。
注册通知
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(_updateContent:)
name:FBSDKProfileDidChangeNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(_accessTokenChanged:)
name:FBSDKAccessTokenDidChangeNotification
object:nil];
在通知的事件中处理token和profile的保存
#pragma mark - Notification
- (void)_updateContent:(NSNotification *)notification {
FBSDKProfile *profile = notification.userInfo[FBSDKProfileChangeNewKey];
[self labelDisplayWithProfile:profile];
}
- (void)_accessTokenChanged:(NSNotification *)notification
{
FBSDKAccessToken *token = notification.userInfo[FBSDKAccessTokenChangeNewKey];
if (!token) {
[FBSDKAccessToken setCurrentAccessToken:nil];
[FBSDKProfile setCurrentProfile:nil];
} else {
NSInteger slot = 0;
SUCacheItem *item = [SUCache itemForSlot:slot] ?: [[SUCacheItem alloc] init];
if (![item.token isEqualToAccessToken:token]) {
item.token = token;
[SUCache saveItem:item slot:slot];
}
}
}