- Upgrade Pods

- Fix refresh token when call response failure
- Various fix
- Release 0.7
This commit is contained in:
giuseppenuc committed 2016-04-19 16:35:26 +02:00
1 parent 6f2f24a533
commit f5750d801c
238 files changed
+4768 -3106

No files matched your search

@@ -363,6 +363,28 @@ FBSDK_EXTERN NSString *const FBSDKAppEventParameterValueNo;
parameters:(NSDictionary *)parameters
accessToken:(FBSDKAccessToken *)accessToken;
/*
* Push Notifications Logging
*/
/*!
@abstract
Log an app event that tracks that the application was open via Push Notification.
@param payload Notification payload received via `UIApplicationDelegate`.
*/
+ (void)logPushNotificationOpen:(NSDictionary *)payload;
/*!
@abstract
Log an app event that tracks that a custom action was taken from a push notification.
@param payload Notification payload received via `UIApplicationDelegate`.
@param action Name of the action that was taken.
*/
+ (void)logPushNotificationOpen:(NSDictionary *)payload action:(NSString *)action;
/*!
@abstract
@@ -381,6 +403,21 @@ FBSDK_EXTERN NSString *const FBSDKAppEventParameterValueNo;
*/
+ (void)activateApp;
/*
* Push Notifications Registration
*/
/*!
@abstract
Sets a device token to register the current application installation for push notifications.
@discussion
Sets a device token from `NSData` representation that you get from `UIApplicationDelegate.-application:didRegisterForRemoteNotificationsWithDeviceToken:`.
@param deviceToken Device token data.
*/
+ (void)setPushNotificationsDeviceToken:(NSData *)deviceToken;
/*
* Control over event batching/flushing
*/
@@ -147,6 +147,9 @@ NSString *const FBSDKAppEventParameterDialogOutcome = @"fb_dialog_
NSString *const FBSDKAppEventParameterDialogErrorMessage = @"fb_dialog_outcome_error_message";
NSString *const FBSDKAppEventParameterDialogMode = @"fb_dialog_mode";
NSString *const FBSDKAppEventParameterDialogShareContentType = @"fb_dialog_share_content_type";
NSString *const FBSDKAppEventParameterLogTime = @"_logTime";
NSString *const FBSDKAppEventParameterEventName = @"_eventName";
NSString *const FBSDKAppEventParameterImplicitlyLogged = @"_implicitlyLogged";
// Event parameter values internal to this file
NSString *const FBSDKAppEventsDialogOutcomeValue_Completed = @"Completed";
@@ -172,6 +175,19 @@ NSString *const FBSDKAppEventsLoggingResultNotification = @"com.facebook.sdk:FBS
NSString *const FBSDKAppEventsOverrideAppIDBundleKey = @"FacebookLoggingOverrideAppID";
//
// Push Notifications
// Activities Endpoint Parameter
static NSString *const FBSDKActivitesParameterPushDeviceToken = @"device_token";
// Event Name
static NSString *const FBSDKAppEventNamePushOpened = @"fb_mobile_push_opened";
// Event Parameter
static NSString *const FBSDKAppEventParameterPushCampaign = @"fb_push_campaign";
static NSString *const FBSDKAppEventParameterPushAction = @"fb_push_action";
// Payload Keys
static NSString *const FBSDKAppEventsPushPayloadKey = @"fb_push_payload";
static NSString *const FBSDKAppEventsPushPayloadCampaignKey = @"campaign";
#define NUM_LOG_EVENTS_TO_TRY_TO_FLUSH_AFTER 100
#define FLUSH_PERIOD_IN_SECONDS 15
#define APP_SUPPORTS_ATTRIBUTION_ID_RECHECK_PERIOD 60 * 60 * 24
@@ -183,6 +199,9 @@ static NSString *g_overrideAppID = nil;
@property (nonatomic, readwrite) FBSDKAppEventsFlushBehavior flushBehavior;
//for testing only.
@property (nonatomic, assign) BOOL disableTimer;
@property (nonatomic, copy) NSString *pushNotificationsDeviceTokenString;
@end
@implementation FBSDKAppEvents
@@ -344,6 +363,35 @@ static NSString *g_overrideAppID = nil;
}
}
/*
* Push Notifications Logging
*/
+ (void)logPushNotificationOpen:(NSDictionary *)payload
{
[self logPushNotificationOpen:payload action:nil];
}
+ (void)logPushNotificationOpen:(NSDictionary *)payload action:(NSString *)action
{
NSDictionary *facebookPayload = payload[FBSDKAppEventsPushPayloadKey];
if (!facebookPayload) {
return;
}
NSString *campaign = facebookPayload[FBSDKAppEventsPushPayloadCampaignKey];
if (campaign.length == 0) {
[FBSDKLogger singleShotLogEntry:FBSDKLoggingBehaviorDeveloperErrors
logEntry:@"Malformed payload specified for logging a push notification open."];
return;
}
NSMutableDictionary *parameters = [NSMutableDictionary dictionaryWithObject:campaign forKey:FBSDKAppEventParameterPushCampaign];
if (action) {
parameters[FBSDKAppEventParameterPushAction] = action;
}
[self logEvent:FBSDKAppEventNamePushOpened parameters:parameters];
}
+ (void)activateApp
{
[FBSDKAppEventsUtility ensureOnMainThread:NSStringFromSelector(_cmd) className:NSStringFromClass(self)];
@@ -360,6 +408,11 @@ static NSString *g_overrideAppID = nil;
[FBSDKTimeSpentData restore:YES];
}
+ (void)setPushNotificationsDeviceToken:(NSData *)deviceToken
{
[FBSDKAppEvents singleton].pushNotificationsDeviceTokenString = [FBSDKInternalUtility hexadecimalStringFromData:deviceToken];
}
+ (FBSDKAppEventsFlushBehavior)flushBehavior
{
return [FBSDKAppEvents singleton].flushBehavior;
@@ -532,11 +585,13 @@ static NSString *g_overrideAppID = nil;
}
NSMutableDictionary *eventDictionary = [NSMutableDictionary dictionaryWithDictionary:parameters];
eventDictionary[@"_eventName"] = eventName;
eventDictionary[@"_logTime"] = @([FBSDKAppEventsUtility unixTimeNow]);
eventDictionary[FBSDKAppEventParameterEventName] = eventName;
if (!eventDictionary[FBSDKAppEventParameterLogTime]) {
eventDictionary[FBSDKAppEventParameterLogTime] = @([FBSDKAppEventsUtility unixTimeNow]);
}
[FBSDKInternalUtility dictionary:eventDictionary setObject:valueToSum forKey:@"_valueToSum"];
if (isImplicitlyLogged) {
eventDictionary[@"_implicitlyLogged"] = @"1";
eventDictionary[FBSDKAppEventParameterImplicitlyLogged] = @"1";
}
NSString *currentViewControllerName;
@@ -650,6 +705,9 @@ static NSString *g_overrideAppID = nil;
if (appEventsState.numSkipped > 0) {
postParameters[@"num_skipped_events"] = [NSString stringWithFormat:@"%lu", (unsigned long)appEventsState.numSkipped];
}
if (self.pushNotificationsDeviceTokenString) {
postParameters[FBSDKActivitesParameterPushDeviceToken] = self.pushNotificationsDeviceTokenString;
}
NSString *loggingEntry = nil;
if ([[FBSDKSettings loggingBehavior] containsObject:FBSDKLoggingBehaviorAppEvents]) {
@@ -27,6 +27,7 @@
#import "FBSDKGraphRequest+Internal.h"
#import "FBSDKGraphRequestConnection.h"
#import "FBSDKInternalUtility.h"
#import "FBSDKLogger.h"
#import "FBSDKSettings+Internal.h"
#import "FBSDKUtility.h"
@@ -41,17 +42,6 @@ static NSString *const kIPadKey = @"ipad";
static NSString *const kShouldFallbackKey = @"should_fallback";
static NSString *const kAppLinksKey = @"app_links";
static void FBSDKAppLinkResolverBoltsClassFromString(Class *clazz, NSString *className)
{
*clazz = NSClassFromString(className);
if (*clazz == nil) {
NSString *message = [NSString stringWithFormat:@"Unable to load class %@. Did you link Bolts.framework?", className];
@throw [NSException exceptionWithName:NSInternalInconsistencyException
reason:message
userInfo:nil];
}
}
@interface FBSDKAppLinkResolver ()
@property (nonatomic, strong) NSMutableDictionary *cachedLinks;
@@ -68,10 +58,11 @@ static Class g_BFTaskClass;
+ (void)initialize
{
if (self == [FBSDKAppLinkResolver class]) {
FBSDKAppLinkResolverBoltsClassFromString(&g_BFTaskCompletionSourceClass, @"BFTaskCompletionSource");
FBSDKAppLinkResolverBoltsClassFromString(&g_BFAppLinkTargetClass, @"BFAppLinkTarget");
FBSDKAppLinkResolverBoltsClassFromString(&g_BFAppLinkClass, @"BFAppLink");
FBSDKAppLinkResolverBoltsClassFromString(&g_BFTaskClass, @"BFTask");
g_BFTaskCompletionSourceClass = [FBSDKInternalUtility
resolveBoltsClassWithName:@"BFTaskCompletionSource"];
g_BFAppLinkTargetClass = [FBSDKInternalUtility resolveBoltsClassWithName:@"BFAppLinkTarget"];
g_BFTaskClass = [FBSDKInternalUtility resolveBoltsClassWithName:@"BFTask"];
g_BFAppLinkClass = [FBSDKInternalUtility resolveBoltsClassWithName:@"BFAppLink"];
}
}
@@ -28,6 +28,14 @@
*/
typedef void (^FBSDKDeferredAppLinkHandler)(NSURL *url, NSError *error);
/*!
@abstract Describes the callback for fetchOrganicDeferredAppLink.
@param url the url representing the deferred App Link
*/
typedef void (^FBSDKDeferredAppInviteHandler)(NSURL *url);
/*!
@abstract Class containing App Links related utility methods.
*/
@@ -52,4 +60,41 @@ typedef void (^FBSDKDeferredAppLinkHandler)(NSURL *url, NSError *error);
*/
+ (void)fetchDeferredAppLink:(FBSDKDeferredAppLinkHandler)handler;
/*!
@abstract Call this method from the main thread to fetch deferred deeplink for App Invites
Handler is called with deeplink url, if found, nil otherwise.
@param handler Handler to be called when we fetch deeplink url.
@return YES if async fetch process was started, NO if it failed to start. Note it returns NO
for versions < iOS 9.
@discussion Call this method from the main thread to fetch deferred deeplink if you use App Invites.
This may require a network round trip. If successful, this will call the handler provided, with
deferred deeplink that was clicked by the user. If there is a error/timeout, handler will be called
with nil.
This method only works on iOS 9+ and returns NO otherwise.
This method should only be called from a location that occurs after any launching URL has
been processed (e.g., you should call this method from your application delegate's
didFinishLaunchingWithOptions:).
*/
+ (BOOL)fetchDeferredAppInvite:(FBSDKDeferredAppInviteHandler)handler;
/*
@abstract Call this method to fetch promotion code from the url, if it's present. This function
requires Bolts framework.
Note: This throws an exception if Bolts.framework is not linked. Add '[BFURL class]' in intialize method
of your AppDelegate.
@param url App Link url that was passed to the app.
@return Promotion code string.
@discussion Call this method to fetch App Invite Promotion Code from applink if present.
This can be used to fetch the promotion code that was associated with the invite when it
was created. This method should be called with the url from the openURL method.
*/
+ (NSString*)appInvitePromotionCodeFromURL:(NSURL*)url;
@end
@@ -18,8 +18,12 @@
#import "FBSDKAppLinkUtility.h"
#import <Bolts/BFURL.h>
#import "FBSDKAppEventsUtility.h"
#import "FBSDKGraphRequest.h"
#import "FBSDKInternalUtility.h"
#import "FBSDKOrganicDeeplinkHelper.h"
#import "FBSDKSettings.h"
#import "FBSDKUtility.h"
@@ -77,4 +81,34 @@ static NSString *const FBSDKDeferredAppLinkEvent = @"DEFERRED_APP_LINK";
}];
}
+ (BOOL)fetchDeferredAppInvite:(FBSDKDeferredAppInviteHandler)handler
{
NSAssert([NSThread isMainThread], @"FBSDKAppLink fetchOrganicDeferredAppLink: must be invoked from main thread.");
NSAssert(handler, @"FBSDKAppLink fetchOrganicDeferredAppLink: must be invoked with valid handler.");
FBSDKOrganicDeeplinkHelper *deeplinkHelper = [[FBSDKOrganicDeeplinkHelper alloc] init];
return [deeplinkHelper fetchOrganicDeeplink:handler];
}
+ (NSString*)appInvitePromotionCodeFromURL:(NSURL*)url;
{
BFURL *parsedUrl = [[FBSDKInternalUtility resolveBoltsClassWithName:@"BFURL"] URLWithURL:url];
NSDictionary *extras = [parsedUrl appLinkExtras];
if (extras) {
NSString *deeplinkContextString = extras[@"deeplink_context"];
// Parse deeplinkContext and extract promo code
if ([deeplinkContextString length] > 0) {
NSError *error = nil;
NSDictionary *deeplinkContextData = [FBSDKInternalUtility objectForJSONString:deeplinkContextString error:&error];
if (!error && [deeplinkContextData isKindOfClass:[NSDictionary class]]) {
return deeplinkContextData[@"promo_code"];
}
}
}
return nil;
}
@end
@@ -39,6 +39,7 @@
#import "FBSDKBridgeAPIResponse.h"
#import "FBSDKContainerViewController.h"
#import "FBSDKProfile+Internal.h"
#import "FBSDKOrganicDeeplinkHelper.h"
#endif
NSString *const FBSDKApplicationDidBecomeActiveNotification = @"com.facebook.sdk.FBSDKApplicationDidBecomeActiveNotification";
@@ -51,6 +52,7 @@ static NSString *const FBSDKAppLinkInboundEvent = @"fb_al_inbound";
FBSDKBridgeAPIRequest *_pendingRequest;
FBSDKBridgeAPICallbackBlock _pendingRequestCompletionBlock;
id<FBSDKURLOpening> _pendingURLOpen;
FBSDKDeferredAppInviteHandler _organicDeeplinkHandler;
#endif
BOOL _expectingBackground;
UIViewController *_safariViewController;
@@ -82,6 +84,8 @@ static NSString *const FBSDKAppLinkInboundEvent = @"fb_al_inbound";
// Register on UIApplicationDidEnterBackgroundNotification events to reset source application data when app backgrounds.
[FBSDKTimeSpentData registerAutoResetSourceApplication];
[FBSDKInternalUtility validateFacebookReservedURLSchemes];
// Remove the observer
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
@@ -131,7 +135,34 @@ static NSString *const FBSDKAppLinkInboundEvent = @"fb_al_inbound";
userInfo:nil];
}
[FBSDKTimeSpentData setSourceApplication:sourceApplication openURL:url];
#if !TARGET_OS_TV
if (_organicDeeplinkHandler) {
NSDictionary *params = [FBSDKUtility dictionaryWithQueryString:url.query];
if([params[@"fbsdk_deeplink"] isEqualToString: @"1"]) {
NSURL *sanitizedUrl = nil;
if(![params[@"fbsdk_deeplink_exception"] isEqualToString:@"1"]) {
NSMutableDictionary *sanitizedParams = [NSMutableDictionary dictionaryWithDictionary:params];
[sanitizedParams removeObjectForKey:@"fbsdk_deeplink"];
sanitizedUrl = [FBSDKInternalUtility URLWithScheme:url.scheme
host:url.host
path:url.path
queryParameters:sanitizedParams
error:nil];
}
dispatch_async(dispatch_get_main_queue(), ^{
// Callback handler for organic deeplinking.
_organicDeeplinkHandler(sanitizedUrl);
_organicDeeplinkHandler = nil;
});
return YES;
}
}
// if they completed a SFVC flow, dimiss it.
[_safariViewController.presentingViewController dismissViewControllerAnimated:YES completion: nil];
_safariViewController = nil;
@@ -39,7 +39,10 @@
#import <FBSDKCoreKit/FBSDKMutableCopying.h>
#import <FBSDKCoreKit/FBSDKProfile.h>
#import <FBSDKCoreKit/FBSDKProfilePictureView.h>
#else
#import <FBSDKCoreKit/FBSDKDeviceButton.h>
#import <FBSDKCoreKit/FBSDKDeviceViewControllerBase.h>
#endif
#define FBSDK_VERSION_STRING @"4.10.1"
#define FBSDK_TARGET_PLATFORM_VERSION @"v2.5"
#define FBSDK_VERSION_STRING @"4.11.0"
#define FBSDK_TARGET_PLATFORM_VERSION @"v2.6"
@@ -123,6 +123,14 @@ FBSDK_EXTERN NSString *const FBSDKProfileChangeNewKey;
*/
+ (void)enableUpdatesOnAccessTokenChange:(BOOL)enable;
/*!
@abstract Loads the current profile and passes it to the completion block.
@param completion The block to be executed once the profile is loaded
@discussion If the profile is already loaded, this method will call the completion block synchronously, otherwise it
will begin a graph request to update `currentProfile` and then call the completion block when finished.
*/
+ (void)loadCurrentProfileWithCompletion:(void(^)(FBSDKProfile *profile, NSError *error))completion;
/*!
@abstract A convenience method for returning a complete `NSURL` for retrieving the user's profile image.
@param mode The picture mode
@@ -122,6 +122,11 @@ static FBSDKProfile *g_currentProfile;
}
}
+ (void)loadCurrentProfileWithCompletion:(void (^)(FBSDKProfile *, NSError *))completion
{
[self loadProfileWithToken:[FBSDKAccessToken currentAccessToken] completion:completion];
}
#pragma mark - NSCopying
- (instancetype)copyWithZone:(NSZone *)zone
@@ -205,9 +210,8 @@ static FBSDKProfile *g_currentProfile;
#pragma mark - Private
+ (void)observeChangeAccessTokenChange:(NSNotification *)notification
+ (void)loadProfileWithToken:(FBSDKAccessToken *)token completion:(void (^)(FBSDKProfile *, NSError *))completion
{
FBSDKAccessToken *token = notification.userInfo[FBSDKAccessTokenChangeNewKey];
static FBSDKGraphRequestConnection *executingRequestConnection = nil;
BOOL isStale = [[NSDate date] timeIntervalSinceDate:g_currentProfile.refreshDate] > FBSDKPROFILE_STALE_IN_SECONDS;
@@ -223,6 +227,9 @@ static FBSDKProfile *g_currentProfile;
executingRequestConnection = [request startWithCompletionHandler:^(FBSDKGraphRequestConnection *connection, id result, NSError *error) {
if (expectedCurrentProfile != g_currentProfile) {
// current profile has already changed since request was started. Let's not overwrite.
if (completion != NULL) {
completion(nil, nil);
}
return;
}
FBSDKProfile *profile = nil;
@@ -236,10 +243,21 @@ static FBSDKProfile *g_currentProfile;
refreshDate:[NSDate date]];
}
[[self class] setCurrentProfile:profile];
if (completion != NULL) {
completion(profile, error);
}
}];
} else if (completion != NULL) {
completion(g_currentProfile, nil);
}
}
+ (void)observeChangeAccessTokenChange:(NSNotification *)notification
{
FBSDKAccessToken *token = notification.userInfo[FBSDKAccessTokenChangeNewKey];
[self loadProfileWithToken:token completion:NULL];
}
@end
@implementation FBSDKProfile(Internal)
@@ -144,6 +144,7 @@ FBSDK_EXTERN NSString *const FBSDKAppEventNameFBSDKLikeControlImpression;
FBSDK_EXTERN NSString *const FBSDKAppEventNameFBSDKLikeControlNetworkUnavailable;
FBSDK_EXTERN NSString *const FBSDKAppEventParameterDialogErrorMessage;
FBSDK_EXTERN NSString *const FBSDKAppEventParameterLogTime;
@interface FBSDKAppEvents (Internal)
@@ -207,30 +207,55 @@
[[NSNotificationCenter defaultCenter] postNotificationName:FBSDKAppEventsLoggingResultNotification object:error];
}
+ (BOOL)matchString:(NSString *)string
firstCharacterSet:(NSCharacterSet *)firstCharacterSet
restOfStringCharacterSet:(NSCharacterSet *)restOfStringCharacterSet
{
if (string.length == 0) {
return NO;
}
for (NSUInteger i = 0; i < string.length; i++) {
const unichar c = [string characterAtIndex:i];
if (i == 0) {
if (![firstCharacterSet characterIsMember:c]) {
return NO;
}
} else {
if (![restOfStringCharacterSet characterIsMember:c]) {
return NO;
}
}
}
return YES;
}
+ (BOOL)regexValidateIdentifier:(NSString *)identifier
{
static NSRegularExpression *regex;
static NSCharacterSet *firstCharacterSet;
static NSCharacterSet *restOfStringCharacterSet;
static dispatch_once_t onceToken;
static NSMutableSet *cachedIdentifiers;
dispatch_once(&onceToken, ^{
NSString *regexString = @"^[0-9a-zA-Z_]+[0-9a-zA-Z _-]*$";
regex = [NSRegularExpression regularExpressionWithPattern:regexString
options:0
error:NULL];
NSMutableCharacterSet *mutableSet = [NSMutableCharacterSet alphanumericCharacterSet];
[mutableSet addCharactersInString:@"_"];
firstCharacterSet = [mutableSet copy];
[mutableSet addCharactersInString:@"- "];
restOfStringCharacterSet = [mutableSet copy];
cachedIdentifiers = [[NSMutableSet alloc] init];
});
@synchronized(self) {
if (![cachedIdentifiers containsObject:identifier]) {
NSUInteger numMatches = [regex numberOfMatchesInString:identifier options:0 range:NSMakeRange(0, identifier.length)];
if (numMatches > 0) {
if ([self matchString:identifier
firstCharacterSet:firstCharacterSet
restOfStringCharacterSet:restOfStringCharacterSet]) {
[cachedIdentifiers addObject:identifier];
} else {
return NO;
}
}
}
return YES;
}
@@ -22,6 +22,8 @@
#import "FBSDKAppEventsUtility.h"
#import "FBSDKInternalUtility.h"
#import "FBSDKLogger.h"
#import "FBSDKServerConfiguration.h"
#import "FBSDKServerConfigurationManager.h"
#import "FBSDKSettings.h"
@@ -30,13 +32,15 @@ NSString *const FBSDKTimeSpentFilename
static NSString *const FBSDKTimeSpentPersistKeySessionSecondsSpent = @"secondsSpentInCurrentSession";
static NSString *const FBSDKTimeSpentPersistKeySessionNumInterruptions = @"numInterruptions";
static NSString *const FBSDKTimeSpentPersistKeyLastSuspendTime = @"lastSuspendTime";
static NSString *const FBSDKTimeSpentPersistKeySessionID = @"sessionID";
static NSString *const FBSDKAppEventNameActivatedApp = @"fb_mobile_activate_app";
static NSString *const FBSDKAppEventNameDeactivatedApp = @"fb_mobile_deactivate_app";
static NSString *const FBSDKAppEventParameterNameSessionInterruptions = @"fb_mobile_app_interruptions";
static NSString *const FBSDKAppEventParameterNameTimeBetweenSessions = @"fb_mobile_time_between_sessions";
static NSString *const FBSDKAppEventParameterNameSessionID = @"_session_id";
static const int NUM_SECONDS_IDLE_TO_BE_NEW_SESSION = 60;
static const int SECS_PER_MIN = 60;
static const int SECS_PER_HOUR = 60 * SECS_PER_MIN;
static const int SECS_PER_DAY = 24 * SECS_PER_HOUR;
@@ -79,12 +83,6 @@ static const long INACTIVE_SECONDS_QUANTA[] =
* with the duration of the previous session as the 'value' of this event, along with the number of
* interruptions from that previous session as an event parameter.
*/
@interface FBSDKTimeSpentData()
@property (nonatomic) NSInteger numSecondsIdleToBeNewSession;
@end
@implementation FBSDKTimeSpentData
{
BOOL _isCurrentlyLoaded;
@@ -94,6 +92,8 @@ static const long INACTIVE_SECONDS_QUANTA[] =
long _timeSinceLastSuspend;
int _numInterruptionsInCurrentSession;
long _lastRestoreTime;
long _lastSuspendTime;
NSString *_sessionID;
}
//
@@ -113,15 +113,6 @@ static const long INACTIVE_SECONDS_QUANTA[] =
//
// Internal methods
//
- (instancetype)init
{
if ((self = [super init])) {
_numSecondsIdleToBeNewSession = NUM_SECONDS_IDLE_TO_BE_NEW_SESSION;
}
return self;
}
+ (FBSDKTimeSpentData *)singleton
{
static dispatch_once_t pred;
@@ -159,7 +150,8 @@ static const long INACTIVE_SECONDS_QUANTA[] =
@{
FBSDKTimeSpentPersistKeySessionSecondsSpent : @(_secondsSpentInCurrentSession),
FBSDKTimeSpentPersistKeySessionNumInterruptions : @(_numInterruptionsInCurrentSession),
FBSDKTimeSpentPersistKeyLastSuspendTime : @(now)
FBSDKTimeSpentPersistKeyLastSuspendTime : @(now),
FBSDKTimeSpentPersistKeySessionID : _sessionID,
};
NSString *content = [FBSDKInternalUtility JSONStringForObject:timeSpentData error:NULL invalidObjectHandler:NULL];
@@ -200,8 +192,10 @@ static const long INACTIVE_SECONDS_QUANTA[] =
if (!content) {
// Nothing persisted, so this is the first launch.
_sessionID = [[NSUUID UUID] UUIDString];
_secondsSpentInCurrentSession = 0;
_numInterruptionsInCurrentSession = 0;
_lastSuspendTime = 0;
// We want to log the app activation event on the first launch, but not the deactivate event
_shouldLogActivateEvent = YES;
@@ -211,12 +205,13 @@ static const long INACTIVE_SECONDS_QUANTA[] =
NSDictionary *results = [FBSDKInternalUtility objectForJSONString:content error:NULL];
long lastActiveTime = [[results objectForKey:FBSDKTimeSpentPersistKeyLastSuspendTime] longValue];
_lastSuspendTime = [[results objectForKey:FBSDKTimeSpentPersistKeyLastSuspendTime] longValue];
_timeSinceLastSuspend = now - lastActiveTime;
_timeSinceLastSuspend = now - _lastSuspendTime;
_secondsSpentInCurrentSession = [[results objectForKey:FBSDKTimeSpentPersistKeySessionSecondsSpent] intValue];
_sessionID = results[FBSDKTimeSpentPersistKeySessionID];
_numInterruptionsInCurrentSession = [[results objectForKey:FBSDKTimeSpentPersistKeySessionNumInterruptions] intValue];
_shouldLogActivateEvent = (_timeSinceLastSuspend > _numSecondsIdleToBeNewSession);
_shouldLogActivateEvent = (_timeSinceLastSuspend > [FBSDKServerConfigurationManager cachedServerConfiguration].sessionTimoutInterval);
// Other than the first launch, we always log the last session's deactivate with this session's activate.
_shouldLogDeactivateEvent = _shouldLogActivateEvent;
@@ -233,38 +228,52 @@ static const long INACTIVE_SECONDS_QUANTA[] =
_isCurrentlyLoaded = YES;
if (calledFromActivateApp) {
if (_shouldLogActivateEvent) {
[FBSDKAppEvents logEvent:FBSDKAppEventNameActivatedApp
parameters:@{
FBSDKAppEventParameterLaunchSource: [[self class] getSourceApplication]
}];
}
// It's important to log deactivate first to reset sessionID
if (_shouldLogDeactivateEvent) {
int quantaIndex = 0;
while (_timeSinceLastSuspend > INACTIVE_SECONDS_QUANTA[quantaIndex]) {
quantaIndex++;
}
[FBSDKAppEvents logEvent:FBSDKAppEventNameDeactivatedApp
valueToSum:_secondsSpentInCurrentSession
parameters:
@{ FBSDKAppEventParameterNameSessionInterruptions : @(_numInterruptionsInCurrentSession),
FBSDKAppEventParameterNameTimeBetweenSessions : [NSString stringWithFormat:@"session_quanta_%d", quantaIndex],
FBSDKAppEventParameterLaunchSource: [[self class] getSourceApplication],
}
];
parameters:[self appEventsParametersForDeactivate]];
// We've logged the session stats, now reset.
_secondsSpentInCurrentSession = 0;
_numInterruptionsInCurrentSession = 0;
_sessionID = [[NSUUID UUID] UUIDString];
}
if (_shouldLogActivateEvent) {
[FBSDKAppEvents logEvent:FBSDKAppEventNameActivatedApp
parameters:[self appEventsParametersForActivate]];
}
}
}
}
- (NSDictionary *)appEventsParametersForActivate
{
return @{
FBSDKAppEventParameterLaunchSource: [[self class] getSourceApplication],
FBSDKAppEventParameterNameSessionID: _sessionID,
};
}
- (NSDictionary *)appEventsParametersForDeactivate
{
int quantaIndex = 0;
while (_timeSinceLastSuspend > INACTIVE_SECONDS_QUANTA[quantaIndex]) {
quantaIndex++;
}
NSMutableDictionary *params = [@{ FBSDKAppEventParameterNameSessionInterruptions : @(_numInterruptionsInCurrentSession),
FBSDKAppEventParameterNameTimeBetweenSessions : [NSString stringWithFormat:@"session_quanta_%d", quantaIndex],
FBSDKAppEventParameterLaunchSource: [[self class] getSourceApplication],
FBSDKAppEventParameterNameSessionID : _sessionID ?: @"",
} mutableCopy];
if (_lastSuspendTime) {
params[FBSDKAppEventParameterLogTime] = @(_lastSuspendTime);
}
return [params copy];
}
+ (void)setSourceApplication:(NSString *)sourceApplication openURL:(NSURL *)url
{
[self setSourceApplication:sourceApplication
@@ -0,0 +1,25 @@
// Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
//
// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,
// copy, modify, and distribute this software in source code or binary form for use
// in connection with the web services and APIs provided by Facebook.
//
// As with any software that integrates with the Facebook platform, your use of
// this software is subject to the Facebook Developer Principles and Policies
// [http://developers.facebook.com/policy/]. This copyright notice shall be
// included in all copies or substantial portions of the software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#import <Foundation/Foundation.h>
#import <FBSDKCoreKit/FBSDKAppLinkUtility.h>
@interface FBSDKOrganicDeeplinkHelper: NSObject
- (bool)fetchOrganicDeeplink:(FBSDKDeferredAppInviteHandler)handler;
@end
@@ -0,0 +1,151 @@
// Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
//
// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,
// copy, modify, and distribute this software in source code or binary form for use
// in connection with the web services and APIs provided by Facebook.
//
// As with any software that integrates with the Facebook platform, your use of
// this software is subject to the Facebook Developer Principles and Policies
// [http://developers.facebook.com/policy/]. This copyright notice shall be
// included in all copies or substantial portions of the software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#import "FBSDKOrganicDeeplinkHelper.h"
#import <Foundation/Foundation.h>
#import <SafariServices/SafariServices.h>
#import <UIKit/UIKit.h>
#import "FBSDKApplicationDelegate+Internal.h"
#import "FBSDKDynamicFrameworkLoader.h"
#import "FBSDKInternalUtility.h"
#import "FBSDKSettings.h"
@interface FBSDKOrganicDeeplinkHelper () <
SFSafariViewControllerDelegate
>
@end
@implementation FBSDKOrganicDeeplinkHelper {
UIWindow *_safariWindow;
UIViewController *_safariViewController;
FBSDKDeferredAppInviteHandler _handler;
}
- (bool)fetchOrganicDeeplink:(FBSDKDeferredAppInviteHandler) handler
{
_handler = handler;
// trying to dynamically load SFSafariViewController class
// so for the cases when it is available we can send users through Safari View Controller flow
// in cases it is not available regular flow will be selected
Class SFSafariViewControllerClass = fbsdkdfl_SFSafariViewControllerClass();
if(!SFSafariViewControllerClass) {
return NO;
}
_safariWindow = [[UIWindow alloc] initWithFrame:[[[[UIApplication sharedApplication] delegate] window] bounds]];
_safariWindow.windowLevel = UIWindowLevelNormal - 1;
_safariWindow.rootViewController = [[UIViewController alloc] init];;
[_safariWindow setHidden:NO];
_safariViewController = [[SFSafariViewControllerClass alloc] initWithURL: [self constructDeeplinkRetrievalUrl]];
dispatch_async(dispatch_get_main_queue(), ^{
[FBSDKApplicationDelegate sharedInstance].organicDeeplinkHandler = handler;
[self presentSafariViewController];
// Dispatch a fallback handler call, if we get no response within 10 seconds.
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(10.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
if([FBSDKApplicationDelegate sharedInstance].organicDeeplinkHandler)
{
[self cleanUpSafariViewController];
[FBSDKApplicationDelegate sharedInstance].organicDeeplinkHandler = nil;
_handler(nil);
}
});
});
return YES;
}
- (void)presentSafariViewController
{
_safariViewController.view.userInteractionEnabled = NO;
_safariViewController.view.alpha = 0;
[_safariWindow.rootViewController addChildViewController:_safariViewController];
[_safariWindow.rootViewController.view addSubview:_safariViewController.view];
[_safariViewController performSelector:@selector(setDelegate:) withObject:self];
[_safariViewController didMoveToParentViewController:_safariWindow.rootViewController];
_safariViewController.view.frame = CGRectZero;
return;
}
- (void)cleanUpSafariViewController
{
if(_safariViewController)
{
[_safariViewController performSelector:@selector(setDelegate:) withObject:nil];
[_safariViewController willMoveToParentViewController:nil];
[_safariViewController.view removeFromSuperview];
[_safariViewController removeFromParentViewController];
_safariViewController = nil;
_safariWindow.rootViewController = nil;
_safariWindow = nil;
}
return;
}
- (NSURL*)constructDeeplinkRetrievalUrl
{
NSString *appID = [FBSDKSettings appID];
UIDevice* device = [UIDevice currentDevice];
NSString* deviceName = @"default";
switch (device.userInterfaceIdiom) {
case UIUserInterfaceIdiomPad:
deviceName = @"ipad";
break;
case UIUserInterfaceIdiomPhone:
deviceName = @"iphone";
break;
case UIUserInterfaceIdiomTV:
deviceName = @"tvos";
break;
#if __IPHONE_9_3
case UIUserInterfaceIdiomCarPlay:
#endif
case UIUserInterfaceIdiomUnspecified:
deviceName = @"unspecified";
break;
}
NSMutableDictionary *parameters = [[NSMutableDictionary alloc] init];
parameters[@"application_id"] = appID;
parameters[@"device"] = deviceName;
return [FBSDKInternalUtility facebookURLWithHostPrefix:@"m"
path:@"/deferreddeeplink/retrieve/"
queryParameters:parameters
defaultVersion: @""
error:nil];
}
#pragma mark - SFSafariViewControllerDelegate
- (void)safariViewController:(SFSafariViewController *)controller didCompleteInitialLoad:(BOOL)didLoadSuccessfully
{
// Mark request as complete, Safari would redirect to url with correct deeplink or default uri.
[self cleanUpSafariViewController];
}
@end
@@ -46,6 +46,8 @@ typedef void(^FBSDKBridgeAPICallbackBlock)(FBSDKBridgeAPIResponse *response);
handler:(void(^)(BOOL))handler;
- (void)openURL:(NSURL *)url sender:(id<FBSDKURLOpening>)sender handler:(void(^)(BOOL))handler;
@property (nonatomic, copy) FBSDKDeferredAppInviteHandler organicDeeplinkHandler;
#endif
@property (nonatomic, readonly, getter=isActive) BOOL active;
@@ -38,6 +38,11 @@
#import "UI/FBSDKUIUtility.h"
#import "UI/FBSDKViewImpressionTracker.h"
#import "WebDialog/FBSDKWebDialog.h"
#else
#import "Device/FBSDKDeviceButton+Internal.h"
#import "Device/FBSDKDeviceDialogView.h"
#import "Device/FBSDKDeviceViewControllerBase+Internal.h"
#import "Device/FBSDKModalFormPresentationController.h"
#endif
#import "AppEvents/FBSDKAppEvents+Internal.h"
@@ -20,7 +20,9 @@
#import <UIKit/UIKit.h>
#define FBSDK_CANOPENURL_FACEBOOK @"fbauth2"
#define FBSDK_CANOPENURL_FBAPI @"fbapi"
#define FBSDK_CANOPENURL_MESSENGER @"fb-messenger-api"
#define FBSDK_CANOPENURL_SHARE_EXTENSION @"fbshareextension"
typedef NS_ENUM(int32_t, FBSDKUIKitVersion)
{
@@ -281,11 +283,22 @@ setJSONStringForObject:(id)object
*/
+ (void)validateAppID;
/**
Validates that the client access token is non-nil, otherwise - throws an NSException otherwise.
Returns the composed client access token.
*/
+ (NSString *)validateRequiredClientAccessToken;
/*!
@abstract validates that the right URL schemes are registered, throws an NSException if not.
*/
+ (void)validateURLSchemes;
/*!
@abstract validates that Facebook reserved URL schemes are not registered, throws an NSException if they are.
*/
+ (void)validateFacebookReservedURLSchemes;
/*!
@abstract Attempts to find the first UIViewController in the view's responder chain. Returns nil if not found.
*/
@@ -301,6 +314,11 @@ setJSONStringForObject:(id)object
*/
+ (UIViewController *)topMostViewController;
/*!
@abstract Converts NSData to a hexadecimal UTF8 String.
*/
+ (NSString *)hexadecimalStringFromData:(NSData *)data;
/*
@abstract Checks if the permission is a publish permission.
*/
@@ -333,4 +351,5 @@ setJSONStringForObject:(id)object
#define FB_BASE_URL @"facebook.com"
+ (Class)resolveBoltsClassWithName:(NSString *)className;
@end
@@ -587,6 +587,16 @@ static NSMapTable *_transientObjects;
}
}
+ (NSString *)validateRequiredClientAccessToken {
if (![FBSDKSettings clientToken]) {
NSString *reason = @"ClientToken is required to be set for this operation. "
@"Set the FacebookClientToken in the Info.plist or call [FBSDKSettings setClientToken:]. "
@"You can find your client token in your App Settings -> Advanced.";
@throw [NSException exceptionWithName:@"InvalidOperationException" reason:reason userInfo:nil];
}
return [NSString stringWithFormat:@"%@|%@", [FBSDKSettings appID], [FBSDKSettings clientToken]];
}
+ (void)validateURLSchemes
{
[self validateAppID];
@@ -597,6 +607,16 @@ static NSMapTable *_transientObjects;
}
}
+ (void)validateFacebookReservedURLSchemes
{
for (NSString * fbUrlScheme in @[FBSDK_CANOPENURL_FACEBOOK, FBSDK_CANOPENURL_MESSENGER, FBSDK_CANOPENURL_FBAPI, FBSDK_CANOPENURL_SHARE_EXTENSION]) {
if ([self isRegisteredURLScheme:fbUrlScheme]) {
NSString *reason = [NSString stringWithFormat:@"%@ is registered as a URL scheme. Please move the entry from CFBundleURLSchemes in your Info.plist to LSApplicationQueriesSchemes. If you are trying to resolve \"canOpenURL: failed\" warnings, those only indicate that the Facebook app is not installed on your device or simulator and can be ignored.", fbUrlScheme];
@throw [NSException exceptionWithName:@"InvalidOperationException" reason:reason userInfo:nil];
}
}
}
+ (UIViewController *)topMostViewController
{
@@ -607,6 +627,20 @@ static NSMapTable *_transientObjects;
return topController;
}
+ (NSString *)hexadecimalStringFromData:(NSData *)data
{
NSUInteger dataLength = data.length;
if (dataLength == 0) {
return nil;
}
const unsigned char *dataBuffer = data.bytes;
NSMutableString *hexString = [NSMutableString stringWithCapacity:(dataLength * 2)];
for (int i = 0; i < dataLength; ++i) {
[hexString appendFormat:@"%02x", dataBuffer[i]];
}
return [hexString copy];
}
+ (BOOL)isRegisteredURLScheme:(NSString *)urlScheme {
static dispatch_once_t fetchBundleOnce;
@@ -692,4 +726,17 @@ static NSMapTable *_transientObjects;
return YES;
}
+ (Class)resolveBoltsClassWithName:(NSString *)className;
{
Class clazz = NSClassFromString(className);
if (clazz == nil) {
NSString *message = [NSString stringWithFormat:@"Unable to load class %@. Did you link Bolts.framework?", className];
@throw [NSException exceptionWithName:NSInternalInconsistencyException
reason:message
userInfo:nil];
}
return clazz;
}
@end
@@ -26,6 +26,7 @@
+ (NSInteger)integerValue:(id)object;
+ (id)objectValue:(id)object;
+ (NSString *)stringValue:(id)object;
+ (NSTimeInterval)timeIntervalValue:(id)object;
+ (NSUInteger)unsignedIntegerValue:(id)object;
+ (NSURL *)URLValue:(id)object;
@@ -76,6 +76,17 @@
}
}
+ (NSTimeInterval)timeIntervalValue:(id)object
{
if ([object isKindOfClass:[NSNumber class]]) {
return [(NSNumber *)object doubleValue];
} else if ([object isKindOfClass:[NSString class]]) {
return [(NSString *)object doubleValue];
} else {
return 0;
}
}
+ (NSUInteger)unsignedIntegerValue:(id)object
{
if ([object isKindOfClass:[NSNumber class]]) {
@@ -18,8 +18,7 @@
#import "FBSDKErrorConfiguration.h"
#import <FBSDKCoreKit/FBSDKCoreKit+Internal.h>
#import "FBSDKCoreKit+Internal.h"
#import "FBSDKErrorRecoveryConfiguration.h"
static NSString *const kErrorCategoryOther = @"other";
@@ -50,6 +50,7 @@ implicitPurchaseLoggingEnabled:(BOOL)implicitPurchaseLoggingEnabled
dialogFlows:(NSDictionary *)dialogFlows
timestamp:(NSDate *)timestamp
errorConfiguration:(FBSDKErrorConfiguration *)errorConfiguration
sessionTimeoutInterval:(NSTimeInterval) sessionTimeoutInterval
defaults:(BOOL)defaults
NS_DESIGNATED_INITIALIZER;
@@ -66,6 +67,7 @@ NS_DESIGNATED_INITIALIZER;
@property (nonatomic, assign, readonly, getter=isSystemAuthenticationEnabled) BOOL systemAuthenticationEnabled;
@property (nonatomic, copy, readonly) NSString *loginTooltipText;
@property (nonatomic, copy, readonly) NSDate *timestamp;
@property (nonatomic, assign) NSTimeInterval sessionTimoutInterval;
- (FBSDKDialogConfiguration *)dialogConfigurationForDialogName:(NSString *)dialogName;
- (BOOL)useNativeDialogForDialogName:(NSString *)dialogName;
@@ -36,6 +36,7 @@
#define FBSDK_SERVER_CONFIGURATION_SYSTEM_AUTHENTICATION_ENABLED_KEY @"systemAuthenticationEnabled"
#define FBSDK_SERVER_CONFIGURATION_NATIVE_AUTH_FLOW_ENABLED_KEY @"nativeAuthFlowEnabled"
#define FBSDK_SERVER_CONFIGURATION_TIMESTAMP_KEY @"timestamp"
#define FBSDK_SERVER_CONFIGURATION_SESSION_TIMEOUT_INTERVAL @"sessionTimeoutInterval"
#pragma mark - Dialog Names
@@ -82,6 +83,7 @@ implicitPurchaseLoggingEnabled:(BOOL)implicitPurchaseLoggingEnabled
dialogFlows:(NSDictionary *)dialogFlows
timestamp:(NSDate *)timestamp
errorConfiguration:(FBSDKErrorConfiguration *)errorConfiguration
sessionTimeoutInterval:(NSTimeInterval) sessionTimeoutInterval
defaults:(BOOL)defaults
{
if ((self = [super init])) {
@@ -99,6 +101,7 @@ implicitPurchaseLoggingEnabled:(BOOL)implicitPurchaseLoggingEnabled
_dialogFlows = [dialogFlows copy];
_timestamp = [timestamp copy];
_errorConfiguration = [errorConfiguration copy];
_sessionTimoutInterval = sessionTimeoutInterval;
_defaults = defaults;
}
return self;
@@ -173,6 +176,7 @@ implicitPurchaseLoggingEnabled:(BOOL)implicitPurchaseLoggingEnabled
NSDictionary *dialogFlows = [decoder decodeObjectOfClasses:dialogFlowsClasses
forKey:FBSDK_SERVER_CONFIGURATION_DIALOG_FLOWS_KEY];
FBSDKErrorConfiguration *errorConfiguration = [decoder decodeObjectOfClass:[FBSDKErrorConfiguration class] forKey:FBSDK_SERVER_CONFIGURATION_ERROR_CONFIGS_KEY];
NSTimeInterval sessionTimeoutInterval = [decoder decodeDoubleForKey:FBSDK_SERVER_CONFIGURATION_SESSION_TIMEOUT_INTERVAL];
return [self initWithAppID:appID
appName:appName
loginTooltipEnabled:loginTooltipEnabled
@@ -187,6 +191,7 @@ implicitPurchaseLoggingEnabled:implicitPurchaseLoggingEnabbled
dialogFlows:dialogFlows
timestamp:timestamp
errorConfiguration:errorConfiguration
sessionTimeoutInterval:sessionTimeoutInterval
defaults:NO];
}
@@ -207,6 +212,7 @@ implicitPurchaseLoggingEnabled:implicitPurchaseLoggingEnabbled
[encoder encodeBool:_nativeAuthFlowEnabled forKey:FBSDK_SERVER_CONFIGURATION_NATIVE_AUTH_FLOW_ENABLED_KEY];
[encoder encodeBool:_systemAuthenticationEnabled forKey:FBSDK_SERVER_CONFIGURATION_SYSTEM_AUTHENTICATION_ENABLED_KEY];
[encoder encodeObject:_timestamp forKey:FBSDK_SERVER_CONFIGURATION_TIMESTAMP_KEY];
[encoder encodeDouble:_sessionTimoutInterval forKey:FBSDK_SERVER_CONFIGURATION_SESSION_TIMEOUT_INTERVAL];
}
#pragma mark - NSCopying
@@ -28,4 +28,6 @@
+ (FBSDKGraphRequest *)requestToLoadServerConfiguration:(NSString *)appID;
+ (void)clearCache;
@end
@@ -28,6 +28,7 @@
#import "FBSDKTypeUtility.h"
// one hour
#define DEFAULT_SESSION_TIMEOUT_INTERVAL 60
#define FBSDK_SERVER_CONFIGURATION_MANAGER_CACHE_TIMEOUT (60 * 60)
#define FBSDK_SERVER_CONFIGURATION_USER_DEFAULTS_KEY @"com.facebook.sdk:serverConfiguration%@"
@@ -43,6 +44,7 @@
#define FBSDK_SERVER_CONFIGURATION_LOGIN_TOOLTIP_TEXT_FIELD @"gdpv4_nux_content"
#define FBSDK_SERVER_CONFIGURATION_NATIVE_PROXY_AUTH_FLOW_ENABLED_FIELD @"ios_supports_native_proxy_auth_flow"
#define FBSDK_SERVER_CONFIGURATION_SYSTEM_AUTHENTICATION_ENABLED_FIELD @"ios_supports_system_auth"
#define FBSDK_SERVER_CONFIGURATION_SESSION_TIMEOUT_FIELD @"app_events_session_timeout"
@implementation FBSDKServerConfigurationManager
@@ -69,6 +71,17 @@ typedef NS_OPTIONS(NSUInteger, FBSDKServerConfigurationManagerAppEventsFeatures)
}
}
+ (void)clearCache
{
_serverConfiguration = nil;
_serverConfigurationError = nil;
_serverConfigurationErrorTimestamp = nil;
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSString *defaultsKey = [NSString stringWithFormat:FBSDK_SERVER_CONFIGURATION_USER_DEFAULTS_KEY, [FBSDKSettings appID]];
[defaults removeObjectForKey:defaultsKey];
[defaults synchronize];
}
+ (FBSDKServerConfiguration *)cachedServerConfiguration
{
NSString *appID = [FBSDKSettings appID];
@@ -167,6 +180,7 @@ typedef NS_OPTIONS(NSUInteger, FBSDKServerConfigurationManagerAppEventsFeatures)
NSDictionary *dialogFlows = [FBSDKTypeUtility dictionaryValue:resultDictionary[FBSDK_SERVER_CONFIGURATION_DIALOG_FLOWS_FIELD]];
FBSDKErrorConfiguration *errorConfiguration = [[FBSDKErrorConfiguration alloc] initWithDictionary:nil];
[errorConfiguration parseArray:resultDictionary[FBSDK_SERVER_CONFIGURATION_ERROR_CONFIGURATION_FIELD]];
NSTimeInterval sessionTimeoutInterval = [FBSDKTypeUtility timeIntervalValue:resultDictionary[FBSDK_SERVER_CONFIGURATION_SESSION_TIMEOUT_FIELD]] ?: DEFAULT_SESSION_TIMEOUT_INTERVAL;
FBSDKServerConfiguration *serverConfiguration = [[FBSDKServerConfiguration alloc] initWithAppID:appID
appName:appName
loginTooltipEnabled:loginTooltipEnabled
@@ -181,6 +195,7 @@ typedef NS_OPTIONS(NSUInteger, FBSDKServerConfigurationManagerAppEventsFeatures)
dialogFlows:dialogFlows
timestamp:[NSDate date]
errorConfiguration:errorConfiguration
sessionTimeoutInterval:sessionTimeoutInterval
defaults:NO];
[self _didProcessConfigurationFromNetwork:serverConfiguration appID:appID error:nil];
}
@@ -204,6 +219,7 @@ typedef NS_OPTIONS(NSUInteger, FBSDKServerConfigurationManagerAppEventsFeatures)
FBSDK_SERVER_CONFIGURATION_LOGIN_TOOLTIP_TEXT_FIELD,
FBSDK_SERVER_CONFIGURATION_NATIVE_PROXY_AUTH_FLOW_ENABLED_FIELD,
FBSDK_SERVER_CONFIGURATION_SYSTEM_AUTHENTICATION_ENABLED_FIELD,
FBSDK_SERVER_CONFIGURATION_SESSION_TIMEOUT_FIELD,
];
NSDictionary *parameters = @{ @"fields": [fields componentsJoinedByString:@","] };
FBSDKGraphRequest *request = [[FBSDKGraphRequest alloc] initWithGraphPath:appID
@@ -251,6 +267,7 @@ typedef NS_OPTIONS(NSUInteger, FBSDKServerConfigurationManagerAppEventsFeatures)
dialogFlows:dialogFlows
timestamp:nil
errorConfiguration:nil
sessionTimeoutInterval:DEFAULT_SESSION_TIMEOUT_INTERVAL
defaults:YES];
}
return _defaultServerConfiguration;