- Add Facebook SDK
- Add PNUser Login
This commit is contained in:
1 parent
f2885301b9
commit
a6dcf672bb
370 files changed
+44655
-2705
No files matched your search
@@ -0,0 +1,166 @@
|
||||
// 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/FBSDKCopying.h>
|
||||
#import <FBSDKCoreKit/FBSDKGraphRequestConnection.h>
|
||||
#import <FBSDKCoreKit/FBSDKMacros.h>
|
||||
|
||||
/*!
|
||||
@abstract Notification indicating that the `currentAccessToken` has changed.
|
||||
@discussion the userInfo dictionary of the notification will contain keys
|
||||
`FBSDKAccessTokenChangeOldKey` and
|
||||
`FBSDKAccessTokenChangeNewKey`.
|
||||
*/
|
||||
FBSDK_EXTERN NSString *const FBSDKAccessTokenDidChangeNotification;
|
||||
|
||||
/*!
|
||||
@abstract A key in the notification's userInfo that will be set
|
||||
if and only if the user ID changed between the old and new tokens.
|
||||
@discussion Token refreshes can occur automatically with the SDK
|
||||
which do not change the user. If you're only interested in user
|
||||
changes (such as logging out), you should check for the existence
|
||||
of this key. The value is a NSNumber with a boolValue.
|
||||
|
||||
On a fresh start of the app where the SDK reads in the cached value
|
||||
of an access token, this key will also exist since the access token
|
||||
is moving from a null state (no user) to a non-null state (user).
|
||||
*/
|
||||
FBSDK_EXTERN NSString *const FBSDKAccessTokenDidChangeUserID;
|
||||
|
||||
/*
|
||||
@abstract key in notification's userInfo object for getting the old token.
|
||||
@discussion If there was no old token, the key will not be present.
|
||||
*/
|
||||
FBSDK_EXTERN NSString *const FBSDKAccessTokenChangeOldKey;
|
||||
|
||||
/*
|
||||
@abstract key in notification's userInfo object for getting the new token.
|
||||
@discussion If there is no new token, the key will not be present.
|
||||
*/
|
||||
FBSDK_EXTERN NSString *const FBSDKAccessTokenChangeNewKey;
|
||||
|
||||
|
||||
/*!
|
||||
@class FBSDKAccessToken
|
||||
@abstract Represents an immutable access token for using Facebook services.
|
||||
*/
|
||||
@interface FBSDKAccessToken : NSObject<FBSDKCopying, NSSecureCoding>
|
||||
|
||||
/*!
|
||||
@abstract Returns the app ID.
|
||||
*/
|
||||
@property (readonly, copy, nonatomic) NSString *appID;
|
||||
|
||||
/*!
|
||||
@abstract Returns the known declined permissions.
|
||||
*/
|
||||
@property (readonly, copy, nonatomic) NSSet *declinedPermissions;
|
||||
|
||||
/*!
|
||||
@abstract Returns the expiration date.
|
||||
*/
|
||||
@property (readonly, copy, nonatomic) NSDate *expirationDate;
|
||||
|
||||
/*!
|
||||
@abstract Returns the known granted permissions.
|
||||
*/
|
||||
@property (readonly, copy, nonatomic) NSSet *permissions;
|
||||
|
||||
/*!
|
||||
@abstract Returns the date the token was last refreshed.
|
||||
*/
|
||||
@property (readonly, copy, nonatomic) NSDate *refreshDate;
|
||||
|
||||
/*!
|
||||
@abstract Returns the opaque token string.
|
||||
*/
|
||||
@property (readonly, copy, nonatomic) NSString *tokenString;
|
||||
|
||||
/*!
|
||||
@abstract Returns the user ID.
|
||||
*/
|
||||
@property (readonly, copy, nonatomic) NSString *userID;
|
||||
|
||||
- (instancetype)init NS_UNAVAILABLE;
|
||||
+ (instancetype)new NS_UNAVAILABLE;
|
||||
|
||||
/*!
|
||||
@abstract Initializes a new instance.
|
||||
@param tokenString the opaque token string.
|
||||
@param permissions the granted permissions. Note this is converted to NSSet and is only
|
||||
an NSArray for the convenience of literal syntax.
|
||||
@param declinedPermissions the declined permissions. Note this is converted to NSSet and is only
|
||||
an NSArray for the convenience of literal syntax.
|
||||
@param appID the app ID.
|
||||
@param userID the user ID.
|
||||
@param expirationDate the optional expiration date (defaults to distantFuture).
|
||||
@param refreshDate the optional date the token was last refreshed (defaults to today).
|
||||
@discussion This initializer should only be used for advanced apps that
|
||||
manage tokens explicitly. Typical login flows only need to use `FBSDKLoginManager`
|
||||
along with `+currentAccessToken`.
|
||||
*/
|
||||
- (instancetype)initWithTokenString:(NSString *)tokenString
|
||||
permissions:(NSArray *)permissions
|
||||
declinedPermissions:(NSArray *)declinedPermissions
|
||||
appID:(NSString *)appID
|
||||
userID:(NSString *)userID
|
||||
expirationDate:(NSDate *)expirationDate
|
||||
refreshDate:(NSDate *)refreshDate
|
||||
NS_DESIGNATED_INITIALIZER;
|
||||
|
||||
/*!
|
||||
@abstract Convenience getter to determine if a permission has been granted
|
||||
@param permission The permission to check.
|
||||
*/
|
||||
- (BOOL)hasGranted:(NSString *)permission;
|
||||
|
||||
/*!
|
||||
@abstract Compares the receiver to another FBSDKAccessToken
|
||||
@param token The other token
|
||||
@return YES if the receiver's values are equal to the other token's values; otherwise NO
|
||||
*/
|
||||
- (BOOL)isEqualToAccessToken:(FBSDKAccessToken *)token;
|
||||
|
||||
/*!
|
||||
@abstract Returns the "global" access token that represents the currently logged in user.
|
||||
@discussion The `currentAccessToken` is a convenient representation of the token of the
|
||||
current user and is used by other SDK components (like `FBSDKLoginManager`).
|
||||
*/
|
||||
+ (FBSDKAccessToken *)currentAccessToken;
|
||||
|
||||
/*!
|
||||
@abstract Sets the "global" access token that represents the currently logged in user.
|
||||
@param token The access token to set.
|
||||
@discussion This will broadcast a notification and save the token to the app keychain.
|
||||
*/
|
||||
+ (void)setCurrentAccessToken:(FBSDKAccessToken *)token;
|
||||
|
||||
/*!
|
||||
@abstract Refresh the current access token's permission state and extend the token's expiration date,
|
||||
if possible.
|
||||
@param completionHandler an optional callback handler that can surface any errors related to permission refreshing.
|
||||
@discussion On a successful refresh, the currentAccessToken will be updated so you typically only need to
|
||||
observe the `FBSDKAccessTokenDidChangeNotification` notification.
|
||||
|
||||
If a token is already expired, it cannot be refreshed.
|
||||
*/
|
||||
+ (void)refreshCurrentAccessToken:(FBSDKGraphRequestHandler)completionHandler;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,200 @@
|
||||
// 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 "FBSDKAccessToken.h"
|
||||
|
||||
#import "FBSDKGraphRequestPiggybackManager.h"
|
||||
#import "FBSDKInternalUtility.h"
|
||||
#import "FBSDKMath.h"
|
||||
#import "FBSDKSettings+Internal.h"
|
||||
|
||||
NSString *const FBSDKAccessTokenDidChangeNotification = @"com.facebook.sdk.FBSDKAccessTokenData.FBSDKAccessTokenDidChangeNotification";
|
||||
NSString *const FBSDKAccessTokenDidChangeUserID = @"FBSDKAccessTokenDidChangeUserID";
|
||||
NSString *const FBSDKAccessTokenChangeNewKey = @"FBSDKAccessToken";
|
||||
NSString *const FBSDKAccessTokenChangeOldKey = @"FBSDKAccessTokenOld";
|
||||
|
||||
static FBSDKAccessToken *g_currentAccessToken;
|
||||
|
||||
#define FBSDK_ACCESSTOKEN_TOKENSTRING_KEY @"tokenString"
|
||||
#define FBSDK_ACCESSTOKEN_PERMISSIONS_KEY @"permissions"
|
||||
#define FBSDK_ACCESSTOKEN_DECLINEDPERMISSIONS_KEY @"declinedPermissions"
|
||||
#define FBSDK_ACCESSTOKEN_APPID_KEY @"appID"
|
||||
#define FBSDK_ACCESSTOKEN_USERID_KEY @"userID"
|
||||
#define FBSDK_ACCESSTOKEN_REFRESHDATE_KEY @"refreshDate"
|
||||
#define FBSDK_ACCESSTOKEN_EXPIRATIONDATE_KEY @"expirationDate"
|
||||
|
||||
@implementation FBSDKAccessToken
|
||||
|
||||
- (instancetype)init NS_UNAVAILABLE
|
||||
{
|
||||
assert(0);
|
||||
}
|
||||
|
||||
- (instancetype)initWithTokenString:(NSString *)tokenString
|
||||
permissions:(NSArray *)permissions
|
||||
declinedPermissions:(NSArray *)declinedPermissions
|
||||
appID:(NSString *)appID
|
||||
userID:(NSString *)userID
|
||||
expirationDate:(NSDate *)expirationDate
|
||||
refreshDate:(NSDate *)refreshDate
|
||||
{
|
||||
if ((self = [super init])) {
|
||||
_tokenString = [tokenString copy];
|
||||
_permissions = [NSSet setWithArray:permissions];
|
||||
_declinedPermissions = [NSSet setWithArray:declinedPermissions];
|
||||
_appID = [appID copy];
|
||||
_userID = [userID copy];
|
||||
_expirationDate = [expirationDate copy] ?: [NSDate distantFuture];
|
||||
_refreshDate = [refreshDate copy] ?: [NSDate date];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (BOOL)hasGranted:(NSString *)permission
|
||||
{
|
||||
return [self.permissions containsObject:permission];
|
||||
}
|
||||
|
||||
+ (FBSDKAccessToken *)currentAccessToken
|
||||
{
|
||||
return g_currentAccessToken;
|
||||
}
|
||||
|
||||
+ (void)setCurrentAccessToken:(FBSDKAccessToken *)token
|
||||
{
|
||||
if (token != g_currentAccessToken) {
|
||||
NSMutableDictionary *userInfo = [NSMutableDictionary dictionary];
|
||||
[FBSDKInternalUtility dictionary:userInfo setObject:token forKey:FBSDKAccessTokenChangeNewKey];
|
||||
[FBSDKInternalUtility dictionary:userInfo setObject:g_currentAccessToken forKey:FBSDKAccessTokenChangeOldKey];
|
||||
if (![g_currentAccessToken.userID isEqualToString:token.userID]) {
|
||||
userInfo[FBSDKAccessTokenDidChangeUserID] = @YES;
|
||||
}
|
||||
|
||||
g_currentAccessToken = token;
|
||||
|
||||
// Only need to keep current session in web view for the case when token is current
|
||||
// When token is abandoned cookies must to be cleaned up immediatelly
|
||||
if (token == nil) {
|
||||
[FBSDKInternalUtility deleteFacebookCookies];
|
||||
}
|
||||
|
||||
[[FBSDKSettings accessTokenCache] cacheAccessToken:token];
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:FBSDKAccessTokenDidChangeNotification
|
||||
object:[self class]
|
||||
userInfo:userInfo];
|
||||
}
|
||||
}
|
||||
|
||||
+ (void)refreshCurrentAccessToken:(FBSDKGraphRequestHandler)completionHandler
|
||||
{
|
||||
if ([FBSDKAccessToken currentAccessToken]) {
|
||||
FBSDKGraphRequestConnection *connection = [[FBSDKGraphRequestConnection alloc] init];
|
||||
[FBSDKGraphRequestPiggybackManager addRefreshPiggyback:connection permissionHandler:completionHandler];
|
||||
[connection start];
|
||||
} else {
|
||||
if (completionHandler) {
|
||||
completionHandler(nil, nil, [FBSDKError errorWithCode:FBSDKAccessTokenRequiredErrorCode message:@"No current access token to refresh"]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Equality
|
||||
|
||||
- (NSUInteger)hash
|
||||
{
|
||||
NSUInteger subhashes[] = {
|
||||
[self.tokenString hash],
|
||||
[self.permissions hash],
|
||||
[self.declinedPermissions hash],
|
||||
[self.appID hash],
|
||||
[self.userID hash],
|
||||
[self.refreshDate hash],
|
||||
[self.expirationDate hash]
|
||||
};
|
||||
return [FBSDKMath hashWithIntegerArray:subhashes count:sizeof(subhashes) / sizeof(subhashes[0])];
|
||||
}
|
||||
|
||||
- (BOOL)isEqual:(id)object
|
||||
{
|
||||
if (self == object) {
|
||||
return YES;
|
||||
}
|
||||
if (![object isKindOfClass:[FBSDKAccessToken class]]) {
|
||||
return NO;
|
||||
}
|
||||
return [self isEqualToAccessToken:(FBSDKAccessToken *)object];
|
||||
}
|
||||
|
||||
- (BOOL)isEqualToAccessToken:(FBSDKAccessToken *)token
|
||||
{
|
||||
return (token &&
|
||||
[FBSDKInternalUtility object:self.tokenString isEqualToObject:token.tokenString] &&
|
||||
[FBSDKInternalUtility object:self.permissions isEqualToObject:token.permissions] &&
|
||||
[FBSDKInternalUtility object:self.declinedPermissions isEqualToObject:token.declinedPermissions] &&
|
||||
[FBSDKInternalUtility object:self.appID isEqualToObject:token.appID] &&
|
||||
[FBSDKInternalUtility object:self.userID isEqualToObject:token.userID] &&
|
||||
[FBSDKInternalUtility object:self.refreshDate isEqualToObject:token.refreshDate] &&
|
||||
[FBSDKInternalUtility object:self.expirationDate isEqualToObject:token.expirationDate] );
|
||||
}
|
||||
|
||||
#pragma mark - NSCopying
|
||||
|
||||
- (id)copyWithZone:(NSZone *)zone
|
||||
{
|
||||
// we're immutable.
|
||||
return self;
|
||||
}
|
||||
|
||||
#pragma mark NSCoding
|
||||
|
||||
+ (BOOL)supportsSecureCoding
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (id)initWithCoder:(NSCoder *)decoder
|
||||
{
|
||||
NSString *appID = [decoder decodeObjectOfClass:[NSString class] forKey:FBSDK_ACCESSTOKEN_APPID_KEY];
|
||||
NSSet *declinedPermissions = [decoder decodeObjectOfClass:[NSSet class] forKey:FBSDK_ACCESSTOKEN_DECLINEDPERMISSIONS_KEY];
|
||||
NSSet *permissions = [decoder decodeObjectOfClass:[NSSet class] forKey:FBSDK_ACCESSTOKEN_PERMISSIONS_KEY];
|
||||
NSString *tokenString = [decoder decodeObjectOfClass:[NSString class] forKey:FBSDK_ACCESSTOKEN_TOKENSTRING_KEY];
|
||||
NSString *userID = [decoder decodeObjectOfClass:[NSString class] forKey:FBSDK_ACCESSTOKEN_USERID_KEY];
|
||||
NSDate *refreshDate = [decoder decodeObjectOfClass:[NSDate class] forKey:FBSDK_ACCESSTOKEN_REFRESHDATE_KEY];
|
||||
NSDate *expirationDate = [decoder decodeObjectOfClass:[NSDate class] forKey:FBSDK_ACCESSTOKEN_EXPIRATIONDATE_KEY];
|
||||
|
||||
return [self initWithTokenString:tokenString
|
||||
permissions:[permissions allObjects]
|
||||
declinedPermissions:[declinedPermissions allObjects]
|
||||
appID:appID
|
||||
userID:userID
|
||||
expirationDate:expirationDate
|
||||
refreshDate:refreshDate];
|
||||
}
|
||||
|
||||
- (void)encodeWithCoder:(NSCoder *)encoder
|
||||
{
|
||||
[encoder encodeObject:self.appID forKey:FBSDK_ACCESSTOKEN_APPID_KEY];
|
||||
[encoder encodeObject:self.declinedPermissions forKey:FBSDK_ACCESSTOKEN_DECLINEDPERMISSIONS_KEY];
|
||||
[encoder encodeObject:self.permissions forKey:FBSDK_ACCESSTOKEN_PERMISSIONS_KEY];
|
||||
[encoder encodeObject:self.tokenString forKey:FBSDK_ACCESSTOKEN_TOKENSTRING_KEY];
|
||||
[encoder encodeObject:self.userID forKey:FBSDK_ACCESSTOKEN_USERID_KEY];
|
||||
[encoder encodeObject:self.expirationDate forKey:FBSDK_ACCESSTOKEN_EXPIRATIONDATE_KEY];
|
||||
[encoder encodeObject:self.refreshDate forKey:FBSDK_ACCESSTOKEN_REFRESHDATE_KEY];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,462 @@
|
||||
// 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 "FBSDKMacros.h"
|
||||
|
||||
@class FBSDKAccessToken;
|
||||
@class FBSDKGraphRequest;
|
||||
|
||||
/*! @abstract NSNotificationCenter name indicating a result of a failed log flush attempt. The posted object will be an NSError instance. */
|
||||
FBSDK_EXTERN NSString *const FBSDKAppEventsLoggingResultNotification;
|
||||
|
||||
/*! @abstract optional plist key ("FacebookLoggingOverrideAppID") for setting `loggingOverrideAppID` */
|
||||
FBSDK_EXTERN NSString *const FBSDKAppEventsOverrideAppIDBundleKey;
|
||||
|
||||
/*!
|
||||
|
||||
@typedef NS_ENUM (NSUInteger, FBSDKAppEventsFlushBehavior)
|
||||
|
||||
@abstract Specifies when `FBSDKAppEvents` sends log events to the server.
|
||||
|
||||
*/
|
||||
typedef NS_ENUM(NSUInteger, FBSDKAppEventsFlushBehavior)
|
||||
{
|
||||
|
||||
/*! Flush automatically: periodically (once a minute or every 100 logged events) and always at app reactivation. */
|
||||
FBSDKAppEventsFlushBehaviorAuto = 0,
|
||||
|
||||
/*! Only flush when the `flush` method is called. When an app is moved to background/terminated, the
|
||||
events are persisted and re-established at activation, but they will only be written with an
|
||||
explicit call to `flush`. */
|
||||
FBSDKAppEventsFlushBehaviorExplicitOnly,
|
||||
|
||||
};
|
||||
|
||||
/*!
|
||||
@methodgroup Predefined event names for logging events common to many apps. Logging occurs through the `logEvent` family of methods on `FBSDKAppEvents`.
|
||||
Common event parameters are provided in the `FBSDKAppEventsParameterNames*` constants.
|
||||
*/
|
||||
|
||||
/*! Log this event when the user has achieved a level in the app. */
|
||||
FBSDK_EXTERN NSString *const FBSDKAppEventNameAchievedLevel;
|
||||
|
||||
/*! Log this event when the user has entered their payment info. */
|
||||
FBSDK_EXTERN NSString *const FBSDKAppEventNameAddedPaymentInfo;
|
||||
|
||||
/*! Log this event when the user has added an item to their cart. The valueToSum passed to logEvent should be the item's price. */
|
||||
FBSDK_EXTERN NSString *const FBSDKAppEventNameAddedToCart;
|
||||
|
||||
/*! Log this event when the user has added an item to their wishlist. The valueToSum passed to logEvent should be the item's price. */
|
||||
FBSDK_EXTERN NSString *const FBSDKAppEventNameAddedToWishlist;
|
||||
|
||||
/*! Log this event when a user has completed registration with the app. */
|
||||
FBSDK_EXTERN NSString *const FBSDKAppEventNameCompletedRegistration;
|
||||
|
||||
/*! Log this event when the user has completed a tutorial in the app. */
|
||||
FBSDK_EXTERN NSString *const FBSDKAppEventNameCompletedTutorial;
|
||||
|
||||
/*! Log this event when the user has entered the checkout process. The valueToSum passed to logEvent should be the total price in the cart. */
|
||||
FBSDK_EXTERN NSString *const FBSDKAppEventNameInitiatedCheckout;
|
||||
|
||||
/*! Log this event when the user has rated an item in the app. The valueToSum passed to logEvent should be the numeric rating. */
|
||||
FBSDK_EXTERN NSString *const FBSDKAppEventNameRated;
|
||||
|
||||
/*! Log this event when a user has performed a search within the app. */
|
||||
FBSDK_EXTERN NSString *const FBSDKAppEventNameSearched;
|
||||
|
||||
/*! Log this event when the user has spent app credits. The valueToSum passed to logEvent should be the number of credits spent. */
|
||||
FBSDK_EXTERN NSString *const FBSDKAppEventNameSpentCredits;
|
||||
|
||||
/*! Log this event when the user has unlocked an achievement in the app. */
|
||||
FBSDK_EXTERN NSString *const FBSDKAppEventNameUnlockedAchievement;
|
||||
|
||||
/*! Log this event when a user has viewed a form of content in the app. */
|
||||
FBSDK_EXTERN NSString *const FBSDKAppEventNameViewedContent;
|
||||
|
||||
/*!
|
||||
@methodgroup Predefined event name parameters for common additional information to accompany events logged through the `logEvent` family
|
||||
of methods on `FBSDKAppEvents`. Common event names are provided in the `FBAppEventName*` constants.
|
||||
*/
|
||||
|
||||
/*! Parameter key used to specify an ID for the specific piece of content being logged about. Could be an EAN, article identifier, etc., depending on the nature of the app. */
|
||||
FBSDK_EXTERN NSString *const FBSDKAppEventParameterNameContentID;
|
||||
|
||||
/*! Parameter key used to specify a generic content type/family for the logged event, e.g. "music", "photo", "video". Options to use will vary based upon what the app is all about. */
|
||||
FBSDK_EXTERN NSString *const FBSDKAppEventParameterNameContentType;
|
||||
|
||||
/*! Parameter key used to specify currency used with logged event. E.g. "USD", "EUR", "GBP". See ISO-4217 for specific values. One reference for these is <http://en.wikipedia.org/wiki/ISO_4217>. */
|
||||
FBSDK_EXTERN NSString *const FBSDKAppEventParameterNameCurrency;
|
||||
|
||||
/*! Parameter key used to specify a description appropriate to the event being logged. E.g., the name of the achievement unlocked in the `FBAppEventNameAchievementUnlocked` event. */
|
||||
FBSDK_EXTERN NSString *const FBSDKAppEventParameterNameDescription;
|
||||
|
||||
/*! Parameter key used to specify the level achieved in a `FBAppEventNameAchieved` event. */
|
||||
FBSDK_EXTERN NSString *const FBSDKAppEventParameterNameLevel;
|
||||
|
||||
/*! Parameter key used to specify the maximum rating available for the `FBAppEventNameRate` event. E.g., "5" or "10". */
|
||||
FBSDK_EXTERN NSString *const FBSDKAppEventParameterNameMaxRatingValue;
|
||||
|
||||
/*! Parameter key used to specify how many items are being processed for an `FBAppEventNameInitiatedCheckout` or `FBAppEventNamePurchased` event. */
|
||||
FBSDK_EXTERN NSString *const FBSDKAppEventParameterNameNumItems;
|
||||
|
||||
/*! Parameter key used to specify whether payment info is available for the `FBAppEventNameInitiatedCheckout` event. `FBSDKAppEventParameterValueYes` and `FBSDKAppEventParameterValueNo` are good canonical values to use for this parameter. */
|
||||
FBSDK_EXTERN NSString *const FBSDKAppEventParameterNamePaymentInfoAvailable;
|
||||
|
||||
/*! Parameter key used to specify method user has used to register for the app, e.g., "Facebook", "email", "Twitter", etc */
|
||||
FBSDK_EXTERN NSString *const FBSDKAppEventParameterNameRegistrationMethod;
|
||||
|
||||
/*! Parameter key used to specify the string provided by the user for a search operation. */
|
||||
FBSDK_EXTERN NSString *const FBSDKAppEventParameterNameSearchString;
|
||||
|
||||
/*! Parameter key used to specify whether the activity being logged about was successful or not. `FBSDKAppEventParameterValueYes` and `FBSDKAppEventParameterValueNo` are good canonical values to use for this parameter. */
|
||||
FBSDK_EXTERN NSString *const FBSDKAppEventParameterNameSuccess;
|
||||
|
||||
/*
|
||||
@methodgroup Predefined values to assign to event parameters that accompany events logged through the `logEvent` family
|
||||
of methods on `FBSDKAppEvents`. Common event parameters are provided in the `FBSDKAppEventParameterName*` constants.
|
||||
*/
|
||||
|
||||
/*! Yes-valued parameter value to be used with parameter keys that need a Yes/No value */
|
||||
FBSDK_EXTERN NSString *const FBSDKAppEventParameterValueYes;
|
||||
|
||||
/*! No-valued parameter value to be used with parameter keys that need a Yes/No value */
|
||||
FBSDK_EXTERN NSString *const FBSDKAppEventParameterValueNo;
|
||||
|
||||
|
||||
/*!
|
||||
|
||||
@class FBSDKAppEvents
|
||||
|
||||
@abstract
|
||||
Client-side event logging for specialized application analytics available through Facebook App Insights
|
||||
and for use with Facebook Ads conversion tracking and optimization.
|
||||
|
||||
@discussion
|
||||
The `FBSDKAppEvents` static class has a few related roles:
|
||||
|
||||
+ Logging predefined and application-defined events to Facebook App Insights with a
|
||||
numeric value to sum across a large number of events, and an optional set of key/value
|
||||
parameters that define "segments" for this event (e.g., 'purchaserStatus' : 'frequent', or
|
||||
'gamerLevel' : 'intermediate')
|
||||
|
||||
+ Logging events to later be used for ads optimization around lifetime value.
|
||||
|
||||
+ Methods that control the way in which events are flushed out to the Facebook servers.
|
||||
|
||||
Here are some important characteristics of the logging mechanism provided by `FBSDKAppEvents`:
|
||||
|
||||
+ Events are not sent immediately when logged. They're cached and flushed out to the Facebook servers
|
||||
in a number of situations:
|
||||
- when an event count threshold is passed (currently 100 logged events).
|
||||
- when a time threshold is passed (currently 15 seconds).
|
||||
- when an app has gone to background and is then brought back to the foreground.
|
||||
|
||||
+ Events will be accumulated when the app is in a disconnected state, and sent when the connection is
|
||||
restored and one of the above 'flush' conditions are met.
|
||||
|
||||
+ The `FBSDKAppEvents` class is thread-safe in that events may be logged from any of the app's threads.
|
||||
|
||||
+ The developer can set the `flushBehavior` on `FBSDKAppEvents` to force the flushing of events to only
|
||||
occur on an explicit call to the `flush` method.
|
||||
|
||||
+ The developer can turn on console debug output for event logging and flushing to the server by using
|
||||
the `FBSDKLoggingBehaviorAppEvents` value in `[FBSettings setLoggingBehavior:]`.
|
||||
|
||||
Some things to note when logging events:
|
||||
|
||||
+ There is a limit on the number of unique event names an app can use, on the order of 1000.
|
||||
+ There is a limit to the number of unique parameter names in the provided parameters that can
|
||||
be used per event, on the order of 25. This is not just for an individual call, but for all
|
||||
invocations for that eventName.
|
||||
+ Event names and parameter names (the keys in the NSDictionary) must be between 2 and 40 characters, and
|
||||
must consist of alphanumeric characters, _, -, or spaces.
|
||||
+ The length of each parameter value can be no more than on the order of 100 characters.
|
||||
|
||||
*/
|
||||
@interface FBSDKAppEvents : NSObject
|
||||
|
||||
/*
|
||||
* Basic event logging
|
||||
*/
|
||||
|
||||
/*!
|
||||
|
||||
@abstract
|
||||
Log an event with just an eventName.
|
||||
|
||||
@param eventName The name of the event to record. Limitations on number of events and name length
|
||||
are given in the `FBSDKAppEvents` documentation.
|
||||
|
||||
*/
|
||||
+ (void)logEvent:(NSString *)eventName;
|
||||
|
||||
/*!
|
||||
|
||||
@abstract
|
||||
Log an event with an eventName and a numeric value to be aggregated with other events of this name.
|
||||
|
||||
@param eventName The name of the event to record. Limitations on number of events and name length
|
||||
are given in the `FBSDKAppEvents` documentation. Common event names are provided in `FBAppEventName*` constants.
|
||||
|
||||
@param valueToSum Amount to be aggregated into all events of this eventName, and App Insights will report
|
||||
the cumulative and average value of this amount.
|
||||
*/
|
||||
+ (void)logEvent:(NSString *)eventName
|
||||
valueToSum:(double)valueToSum;
|
||||
|
||||
|
||||
/*!
|
||||
|
||||
@abstract
|
||||
Log an event with an eventName and a set of key/value pairs in the parameters dictionary.
|
||||
Parameter limitations are described above.
|
||||
|
||||
@param eventName The name of the event to record. Limitations on number of events and name construction
|
||||
are given in the `FBSDKAppEvents` documentation. Common event names are provided in `FBAppEventName*` constants.
|
||||
|
||||
@param parameters Arbitrary parameter dictionary of characteristics. The keys to this dictionary must
|
||||
be NSString's, and the values are expected to be NSString or NSNumber. Limitations on the number of
|
||||
parameters and name construction are given in the `FBSDKAppEvents` documentation. Commonly used parameter names
|
||||
are provided in `FBSDKAppEventParameterName*` constants.
|
||||
*/
|
||||
+ (void)logEvent:(NSString *)eventName
|
||||
parameters:(NSDictionary *)parameters;
|
||||
|
||||
/*!
|
||||
|
||||
@abstract
|
||||
Log an event with an eventName, a numeric value to be aggregated with other events of this name,
|
||||
and a set of key/value pairs in the parameters dictionary.
|
||||
|
||||
@param eventName The name of the event to record. Limitations on number of events and name construction
|
||||
are given in the `FBSDKAppEvents` documentation. Common event names are provided in `FBAppEventName*` constants.
|
||||
|
||||
@param valueToSum Amount to be aggregated into all events of this eventName, and App Insights will report
|
||||
the cumulative and average value of this amount.
|
||||
|
||||
@param parameters Arbitrary parameter dictionary of characteristics. The keys to this dictionary must
|
||||
be NSString's, and the values are expected to be NSString or NSNumber. Limitations on the number of
|
||||
parameters and name construction are given in the `FBSDKAppEvents` documentation. Commonly used parameter names
|
||||
are provided in `FBSDKAppEventParameterName*` constants.
|
||||
|
||||
*/
|
||||
+ (void)logEvent:(NSString *)eventName
|
||||
valueToSum:(double)valueToSum
|
||||
parameters:(NSDictionary *)parameters;
|
||||
|
||||
|
||||
/*!
|
||||
|
||||
@abstract
|
||||
Log an event with an eventName, a numeric value to be aggregated with other events of this name,
|
||||
and a set of key/value pairs in the parameters dictionary. Providing session lets the developer
|
||||
target a particular <FBSession>. If nil is provided, then `[FBSession activeSession]` will be used.
|
||||
|
||||
@param eventName The name of the event to record. Limitations on number of events and name construction
|
||||
are given in the `FBSDKAppEvents` documentation. Common event names are provided in `FBAppEventName*` constants.
|
||||
|
||||
@param valueToSum Amount to be aggregated into all events of this eventName, and App Insights will report
|
||||
the cumulative and average value of this amount. Note that this is an NSNumber, and a value of `nil` denotes
|
||||
that this event doesn't have a value associated with it for summation.
|
||||
|
||||
@param parameters Arbitrary parameter dictionary of characteristics. The keys to this dictionary must
|
||||
be NSString's, and the values are expected to be NSString or NSNumber. Limitations on the number of
|
||||
parameters and name construction are given in the `FBSDKAppEvents` documentation. Commonly used parameter names
|
||||
are provided in `FBSDKAppEventParameterName*` constants.
|
||||
|
||||
@param accessToken The optional access token to log the event as.
|
||||
*/
|
||||
+ (void)logEvent:(NSString *)eventName
|
||||
valueToSum:(NSNumber *)valueToSum
|
||||
parameters:(NSDictionary *)parameters
|
||||
accessToken:(FBSDKAccessToken *)accessToken;
|
||||
|
||||
/*
|
||||
* Purchase logging
|
||||
*/
|
||||
|
||||
/*!
|
||||
|
||||
@abstract
|
||||
Log a purchase of the specified amount, in the specified currency.
|
||||
|
||||
@param purchaseAmount Purchase amount to be logged, as expressed in the specified currency. This value
|
||||
will be rounded to the thousandths place (e.g., 12.34567 becomes 12.346).
|
||||
|
||||
@param currency Currency, is denoted as, e.g. "USD", "EUR", "GBP". See ISO-4217 for
|
||||
specific values. One reference for these is <http://en.wikipedia.org/wiki/ISO_4217>.
|
||||
|
||||
@discussion This event immediately triggers a flush of the `FBSDKAppEvents` event queue, unless the `flushBehavior` is set
|
||||
to `FBSDKAppEventsFlushBehaviorExplicitOnly`.
|
||||
|
||||
*/
|
||||
+ (void)logPurchase:(double)purchaseAmount
|
||||
currency:(NSString *)currency;
|
||||
|
||||
/*!
|
||||
|
||||
@abstract
|
||||
Log a purchase of the specified amount, in the specified currency, also providing a set of
|
||||
additional characteristics describing the purchase.
|
||||
|
||||
@param purchaseAmount Purchase amount to be logged, as expressed in the specified currency.This value
|
||||
will be rounded to the thousandths place (e.g., 12.34567 becomes 12.346).
|
||||
|
||||
@param currency Currency, is denoted as, e.g. "USD", "EUR", "GBP". See ISO-4217 for
|
||||
specific values. One reference for these is <http://en.wikipedia.org/wiki/ISO_4217>.
|
||||
|
||||
@param parameters Arbitrary parameter dictionary of characteristics. The keys to this dictionary must
|
||||
be NSString's, and the values are expected to be NSString or NSNumber. Limitations on the number of
|
||||
parameters and name construction are given in the `FBSDKAppEvents` documentation. Commonly used parameter names
|
||||
are provided in `FBSDKAppEventParameterName*` constants.
|
||||
|
||||
@discussion This event immediately triggers a flush of the `FBSDKAppEvents` event queue, unless the `flushBehavior` is set
|
||||
to `FBSDKAppEventsFlushBehaviorExplicitOnly`.
|
||||
|
||||
*/
|
||||
+ (void)logPurchase:(double)purchaseAmount
|
||||
currency:(NSString *)currency
|
||||
parameters:(NSDictionary *)parameters;
|
||||
|
||||
/*!
|
||||
|
||||
@abstract
|
||||
Log a purchase of the specified amount, in the specified currency, also providing a set of
|
||||
additional characteristics describing the purchase, as well as an <FBSession> to log to.
|
||||
|
||||
@param purchaseAmount Purchase amount to be logged, as expressed in the specified currency.This value
|
||||
will be rounded to the thousandths place (e.g., 12.34567 becomes 12.346).
|
||||
|
||||
@param currency Currency, is denoted as, e.g. "USD", "EUR", "GBP". See ISO-4217 for
|
||||
specific values. One reference for these is <http://en.wikipedia.org/wiki/ISO_4217>.
|
||||
|
||||
@param parameters Arbitrary parameter dictionary of characteristics. The keys to this dictionary must
|
||||
be NSString's, and the values are expected to be NSString or NSNumber. Limitations on the number of
|
||||
parameters and name construction are given in the `FBSDKAppEvents` documentation. Commonly used parameter names
|
||||
are provided in `FBSDKAppEventParameterName*` constants.
|
||||
|
||||
@param accessToken The optional access token to log the event as.
|
||||
|
||||
@discussion This event immediately triggers a flush of the `FBSDKAppEvents` event queue, unless the `flushBehavior` is set
|
||||
to `FBSDKAppEventsFlushBehaviorExplicitOnly`.
|
||||
|
||||
*/
|
||||
+ (void)logPurchase:(double)purchaseAmount
|
||||
currency:(NSString *)currency
|
||||
parameters:(NSDictionary *)parameters
|
||||
accessToken:(FBSDKAccessToken *)accessToken;
|
||||
|
||||
/*!
|
||||
|
||||
@abstract
|
||||
Notifies the events system that the app has launched and, when appropriate, logs an "activated app" event. Should typically be placed in the
|
||||
app delegates' `applicationDidBecomeActive:` method.
|
||||
|
||||
This method also takes care of logging the event indicating the first time this app has been launched, which, among other things, is used to
|
||||
track user acquisition and app install ads conversions.
|
||||
|
||||
@discussion
|
||||
`activateApp` will not log an event on every app launch, since launches happen every time the app is backgrounded and then foregrounded.
|
||||
"activated app" events will be logged when the app has not been active for more than 60 seconds. This method also causes a "deactivated app"
|
||||
event to be logged when sessions are "completed", and these events are logged with the session length, with an indication of how much
|
||||
time has elapsed between sessions, and with the number of background/foreground interruptions that session had. This data
|
||||
is all visible in your app's App Events Insights.
|
||||
*/
|
||||
+ (void)activateApp;
|
||||
|
||||
/*
|
||||
* Control over event batching/flushing
|
||||
*/
|
||||
|
||||
/*!
|
||||
|
||||
@abstract
|
||||
Get the current event flushing behavior specifying when events are sent back to Facebook servers.
|
||||
*/
|
||||
+ (FBSDKAppEventsFlushBehavior)flushBehavior;
|
||||
|
||||
/*!
|
||||
|
||||
@abstract
|
||||
Set the current event flushing behavior specifying when events are sent back to Facebook servers.
|
||||
|
||||
@param flushBehavior The desired `FBSDKAppEventsFlushBehavior` to be used.
|
||||
*/
|
||||
+ (void)setFlushBehavior:(FBSDKAppEventsFlushBehavior)flushBehavior;
|
||||
|
||||
/*!
|
||||
@abstract
|
||||
Set the 'override' App ID for App Event logging.
|
||||
|
||||
@discussion
|
||||
In some cases, apps want to use one Facebook App ID for login and social presence and another
|
||||
for App Event logging. (An example is if multiple apps from the same company share an app ID for login, but
|
||||
want distinct logging.) By default, this value is `nil`, and defers to the `FBSDKAppEventsOverrideAppIDBundleKey`
|
||||
plist value. If that's not set, it defaults to `[FBSDKSettings appID]`.
|
||||
|
||||
This should be set before any other calls are made to `FBSDKAppEvents`. Thus, you should set it in your application
|
||||
delegate's `application:didFinishLaunchingWithOptions:` delegate.
|
||||
|
||||
@param appID The Facebook App ID to be used for App Event logging.
|
||||
*/
|
||||
+ (void)setLoggingOverrideAppID:(NSString *)appID;
|
||||
|
||||
/*!
|
||||
@abstract
|
||||
Get the 'override' App ID for App Event logging.
|
||||
|
||||
@see setLoggingOverrideAppID:
|
||||
|
||||
*/
|
||||
+ (NSString *)loggingOverrideAppID;
|
||||
|
||||
|
||||
/*!
|
||||
@abstract
|
||||
Explicitly kick off flushing of events to Facebook. This is an asynchronous method, but it does initiate an immediate
|
||||
kick off. Server failures will be reported through the NotificationCenter with notification ID `FBSDKAppEventsLoggingResultNotification`.
|
||||
*/
|
||||
+ (void)flush;
|
||||
|
||||
/*!
|
||||
@abstract
|
||||
Creates a request representing the Graph API call to retrieve a Custom Audience "third party ID" for the app's Facebook user.
|
||||
Callers will send this ID back to their own servers, collect up a set to create a Facebook Custom Audience with,
|
||||
and then use the resultant Custom Audience to target ads.
|
||||
|
||||
@param accessToken The access token to use to establish the user's identity for users logged into Facebook through this app.
|
||||
If `nil`, then the `[FBSDKAccessToken currentAccessToken]` is used.
|
||||
|
||||
@discussion
|
||||
The JSON in the request's response will include an "custom_audience_third_party_id" key/value pair, with the value being the ID retrieved.
|
||||
This ID is an encrypted encoding of the Facebook user's ID and the invoking Facebook app ID.
|
||||
Multiple calls with the same user will return different IDs, thus these IDs cannot be used to correlate behavior
|
||||
across devices or applications, and are only meaningful when sent back to Facebook for creating Custom Audiences.
|
||||
|
||||
The ID retrieved represents the Facebook user identified in the following way: if the specified access token is valid,
|
||||
the ID will represent the user associated with that token; otherwise the ID will represent the user logged into the
|
||||
native Facebook app on the device. If there is no native Facebook app, no one is logged into it, or the user has opted out
|
||||
at the iOS level from ad tracking, then a `nil` ID will be returned.
|
||||
|
||||
This method returns `nil` if either the user has opted-out (via iOS) from Ad Tracking, the app itself has limited event usage
|
||||
via the `[FBSDKSettings limitEventAndDataUsage]` flag, or a specific Facebook user cannot be identified.
|
||||
*/
|
||||
+ (FBSDKGraphRequest *)requestForCustomAudienceThirdPartyIDWithAccessToken:(FBSDKAccessToken *)accessToken;
|
||||
@end
|
||||
@@ -0,0 +1,832 @@
|
||||
// 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 "FBSDKAppEvents.h"
|
||||
#import "FBSDKAppEvents+Internal.h"
|
||||
|
||||
#import <UIKit/UIApplication.h>
|
||||
|
||||
#import "FBSDKAccessToken.h"
|
||||
#import "FBSDKAppEventsState.h"
|
||||
#import "FBSDKAppEventsStateManager.h"
|
||||
#import "FBSDKAppEventsUtility.h"
|
||||
#import "FBSDKConstants.h"
|
||||
#import "FBSDKError.h"
|
||||
#import "FBSDKGraphRequest+Internal.h"
|
||||
#import "FBSDKInternalUtility.h"
|
||||
#import "FBSDKLogger.h"
|
||||
#import "FBSDKPaymentObserver.h"
|
||||
#import "FBSDKServerConfiguration.h"
|
||||
#import "FBSDKServerConfigurationManager.h"
|
||||
#import "FBSDKSettings.h"
|
||||
#import "FBSDKTimeSpentData.h"
|
||||
#import "FBSDKUtility.h"
|
||||
|
||||
//
|
||||
// Public event names
|
||||
//
|
||||
|
||||
// General purpose
|
||||
NSString *const FBSDKAppEventNameCompletedRegistration = @"fb_mobile_complete_registration";
|
||||
NSString *const FBSDKAppEventNameViewedContent = @"fb_mobile_content_view";
|
||||
NSString *const FBSDKAppEventNameSearched = @"fb_mobile_search";
|
||||
NSString *const FBSDKAppEventNameRated = @"fb_mobile_rate";
|
||||
NSString *const FBSDKAppEventNameCompletedTutorial = @"fb_mobile_tutorial_completion";
|
||||
NSString *const FBSDKAppEventParameterLaunchSource = @"fb_mobile_launch_source";
|
||||
|
||||
// Ecommerce related
|
||||
NSString *const FBSDKAppEventNameAddedToCart = @"fb_mobile_add_to_cart";
|
||||
NSString *const FBSDKAppEventNameAddedToWishlist = @"fb_mobile_add_to_wishlist";
|
||||
NSString *const FBSDKAppEventNameInitiatedCheckout = @"fb_mobile_initiated_checkout";
|
||||
NSString *const FBSDKAppEventNameAddedPaymentInfo = @"fb_mobile_add_payment_info";
|
||||
|
||||
// Gaming related
|
||||
NSString *const FBSDKAppEventNameAchievedLevel = @"fb_mobile_level_achieved";
|
||||
NSString *const FBSDKAppEventNameUnlockedAchievement = @"fb_mobile_achievement_unlocked";
|
||||
NSString *const FBSDKAppEventNameSpentCredits = @"fb_mobile_spent_credits";
|
||||
|
||||
//
|
||||
// Public event parameter names
|
||||
//
|
||||
|
||||
NSString *const FBSDKAppEventParameterNameCurrency = @"fb_currency";
|
||||
NSString *const FBSDKAppEventParameterNameRegistrationMethod = @"fb_registration_method";
|
||||
NSString *const FBSDKAppEventParameterNameContentType = @"fb_content_type";
|
||||
NSString *const FBSDKAppEventParameterNameContentID = @"fb_content_id";
|
||||
NSString *const FBSDKAppEventParameterNameSearchString = @"fb_search_string";
|
||||
NSString *const FBSDKAppEventParameterNameSuccess = @"fb_success";
|
||||
NSString *const FBSDKAppEventParameterNameMaxRatingValue = @"fb_max_rating_value";
|
||||
NSString *const FBSDKAppEventParameterNamePaymentInfoAvailable = @"fb_payment_info_available";
|
||||
NSString *const FBSDKAppEventParameterNameNumItems = @"fb_num_items";
|
||||
NSString *const FBSDKAppEventParameterNameLevel = @"fb_level";
|
||||
NSString *const FBSDKAppEventParameterNameDescription = @"fb_description";
|
||||
|
||||
//
|
||||
// Public event parameter values
|
||||
//
|
||||
|
||||
NSString *const FBSDKAppEventParameterValueNo = @"0";
|
||||
NSString *const FBSDKAppEventParameterValueYes = @"1";
|
||||
|
||||
//
|
||||
// Event names internal to this file
|
||||
//
|
||||
NSString *const FBSDKAppEventNamePurchased = @"fb_mobile_purchase";
|
||||
|
||||
NSString *const FBSDKAppEventNameLoginViewUsage = @"fb_login_view_usage";
|
||||
NSString *const FBSDKAppEventNameShareSheetLaunch = @"fb_share_sheet_launch";
|
||||
NSString *const FBSDKAppEventNameShareSheetDismiss = @"fb_share_sheet_dismiss";
|
||||
NSString *const FBSDKAppEventNamePermissionsUILaunch = @"fb_permissions_ui_launch";
|
||||
NSString *const FBSDKAppEventNamePermissionsUIDismiss = @"fb_permissions_ui_dismiss";
|
||||
NSString *const FBSDKAppEventNameFBDialogsPresentShareDialog = @"fb_dialogs_present_share";
|
||||
NSString *const FBSDKAppEventNameFBDialogsPresentShareDialogPhoto = @"fb_dialogs_present_share_photo";
|
||||
NSString *const FBSDKAppEventNameFBDialogsPresentShareDialogOG = @"fb_dialogs_present_share_og";
|
||||
NSString *const FBSDKAppEventNameFBDialogsPresentLikeDialogOG = @"fb_dialogs_present_like_og";
|
||||
NSString *const FBSDKAppEventNameFBDialogsPresentMessageDialog = @"fb_dialogs_present_message";
|
||||
NSString *const FBSDKAppEventNameFBDialogsPresentMessageDialogPhoto = @"fb_dialogs_present_message_photo";
|
||||
NSString *const FBSDKAppEventNameFBDialogsPresentMessageDialogOG = @"fb_dialogs_present_message_og";
|
||||
|
||||
NSString *const FBSDKAppEventNameFBDialogsNativeLoginDialogStart = @"fb_dialogs_native_login_dialog_start";
|
||||
NSString *const FBSDKAppEventsNativeLoginDialogStartTime = @"fb_native_login_dialog_start_time";
|
||||
|
||||
NSString *const FBSDKAppEventNameFBDialogsNativeLoginDialogEnd = @"fb_dialogs_native_login_dialog_end";
|
||||
NSString *const FBSDKAppEventsNativeLoginDialogEndTime = @"fb_native_login_dialog_end_time";
|
||||
|
||||
NSString *const FBSDKAppEventNameFBDialogsWebLoginCompleted = @"fb_dialogs_web_login_dialog_complete";
|
||||
NSString *const FBSDKAppEventsWebLoginE2E = @"fb_web_login_e2e";
|
||||
|
||||
NSString *const FBSDKAppEventNameFBSessionAuthStart = @"fb_mobile_login_start";
|
||||
NSString *const FBSDKAppEventNameFBSessionAuthEnd = @"fb_mobile_login_complete";
|
||||
NSString *const FBSDKAppEventNameFBSessionAuthMethodStart = @"fb_mobile_login_method_start";
|
||||
NSString *const FBSDKAppEventNameFBSessionAuthMethodEnd = @"fb_mobile_login_method_complete";
|
||||
|
||||
NSString *const FBSDKAppEventNameFBSDKLikeButtonImpression = @"fb_like_button_impression";
|
||||
NSString *const FBSDKAppEventNameFBSDKLoginButtonImpression = @"fb_login_button_impression";
|
||||
NSString *const FBSDKAppEventNameFBSDKSendButtonImpression = @"fb_send_button_impression";
|
||||
NSString *const FBSDKAppEventNameFBSDKShareButtonImpression = @"fb_share_button_impression";
|
||||
|
||||
NSString *const FBSDKAppEventNameFBSDKLikeButtonDidTap = @"fb_like_button_did_tap";
|
||||
NSString *const FBSDKAppEventNameFBSDKLoginButtonDidTap = @"fb_login_button_did_tap";
|
||||
NSString *const FBSDKAppEventNameFBSDKSendButtonDidTap = @"fb_send_button_did_tap";
|
||||
NSString *const FBSDKAppEventNameFBSDKShareButtonDidTap = @"fb_share_button_did_tap";
|
||||
|
||||
NSString *const FBSDKAppEventNameFBSDKLikeControlDidDisable = @"fb_like_control_did_disable";
|
||||
NSString *const FBSDKAppEventNameFBSDKLikeControlDidLike = @"fb_like_control_did_like";
|
||||
NSString *const FBSDKAppEventNameFBSDKLikeControlDidPresentDialog = @"fb_like_control_did_present_dialog";
|
||||
NSString *const FBSDKAppEventNameFBSDKLikeControlDidTap = @"fb_like_control_did_tap";
|
||||
NSString *const FBSDKAppEventNameFBSDKLikeControlDidUnlike = @"fb_like_control_did_unlike";
|
||||
NSString *const FBSDKAppEventNameFBSDKLikeControlError = @"fb_like_control_error";
|
||||
NSString *const FBSDKAppEventNameFBSDKLikeControlImpression = @"fb_like_control_impression";
|
||||
NSString *const FBSDKAppEventNameFBSDKLikeControlNetworkUnavailable = @"fb_like_control_network_unavailable";
|
||||
|
||||
NSString *const FBSDLAppEventNameFBSDKEventShareDialogResult = @"fb_dialog_share_result";
|
||||
NSString *const FBSDKAppEventNameFBSDKEventMessengerShareDialogResult = @"fb_messenger_dialog_share_result";
|
||||
NSString *const FBSDKAppEventNameFBSDKEventAppInviteShareDialogResult = @"fb_app_invite_dialog_share_result";
|
||||
|
||||
NSString *const FBSDKAppEventNameFBSDKEventShareDialogShow = @"fb_dialog_share_show";
|
||||
NSString *const FBSDKAppEventNameFBSDKEventMessengerShareDialogShow = @"fb_messenger_dialog_share_show";
|
||||
NSString *const FBSDKAppEventNameFBSDKEventAppInviteShareDialogShow = @"fb_app_invite_share_show";
|
||||
|
||||
// Event Parameters internal to this file
|
||||
NSString *const FBSDKAppEventParameterDialogOutcome = @"fb_dialog_outcome";
|
||||
NSString *const FBSDKAppEventParameterDialogErrorMessage = @"fb_dialog_outcome_error_message";
|
||||
NSString *const FBSDKAppEventParameterDialogMode = @"fb_dialog_mode";
|
||||
NSString *const FBSDKAppEventParameterDialogShareContentType = @"fb_dialog_share_content_type";
|
||||
|
||||
// Event parameter values internal to this file
|
||||
NSString *const FBSDKAppEventsDialogOutcomeValue_Completed = @"Completed";
|
||||
NSString *const FBSDKAppEventsDialogOutcomeValue_Cancelled = @"Cancelled";
|
||||
NSString *const FBSDKAppEventsDialogOutcomeValue_Failed = @"Failed";
|
||||
|
||||
NSString *const FBSDKAppEventsDialogShareModeAutomatic = @"Automatic";
|
||||
NSString *const FBSDKAppEventsDialogShareModeBrowser = @"Browser";
|
||||
NSString *const FBSDKAppEventsDialogShareModeNative = @"Native";
|
||||
NSString *const FBSDKAppEventsDialogShareModeShareSheet = @"ShareSheet";
|
||||
NSString *const FBSDKAppEventsDialogShareModeWeb = @"Web";
|
||||
NSString *const FBSDKAppEventsDialogShareModeFeedBrowser = @"FeedBrowser";
|
||||
NSString *const FBSDKAppEventsDialogShareModeFeedWeb = @"FeedWeb";
|
||||
NSString *const FBSDKAppEventsDialogShareModeUnknown = @"Unknown";
|
||||
|
||||
NSString *const FBSDKAppEventsDialogShareContentTypeOpenGraph = @"OpenGraph";
|
||||
NSString *const FBSDKAppEventsDialogShareContentTypeStatus = @"Status";
|
||||
NSString *const FBSDKAppEventsDialogShareContentTypePhoto = @"Photo";
|
||||
NSString *const FBSDKAppEventsDialogShareContentTypeVideo = @"Video";
|
||||
NSString *const FBSDKAppEventsDialogShareContentTypeUnknown = @"Unknown";
|
||||
|
||||
NSString *const FBSDKAppEventsLoggingResultNotification = @"com.facebook.sdk:FBSDKAppEventsLoggingResultNotification";
|
||||
|
||||
NSString *const FBSDKAppEventsOverrideAppIDBundleKey = @"FacebookLoggingOverrideAppID";
|
||||
|
||||
#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
|
||||
|
||||
static NSString *g_overrideAppID = nil;
|
||||
|
||||
@interface FBSDKAppEvents ()
|
||||
|
||||
@property (nonatomic, readwrite) FBSDKAppEventsFlushBehavior flushBehavior;
|
||||
//for testing only.
|
||||
@property (nonatomic, assign) BOOL disableTimer;
|
||||
@end
|
||||
|
||||
@implementation FBSDKAppEvents
|
||||
{
|
||||
BOOL _explicitEventsLoggedYet;
|
||||
NSTimer *_flushTimer;
|
||||
NSTimer *_attributionIDRecheckTimer;
|
||||
FBSDKServerConfiguration *_serverConfiguration;
|
||||
FBSDKAppEventsState *_appEventsState;
|
||||
}
|
||||
|
||||
#pragma mark - Object Lifecycle
|
||||
|
||||
+ (void)initialize
|
||||
{
|
||||
if (self == [FBSDKAppEvents class]) {
|
||||
g_overrideAppID = [[[NSBundle mainBundle] objectForInfoDictionaryKey:FBSDKAppEventsOverrideAppIDBundleKey] copy];
|
||||
}
|
||||
}
|
||||
|
||||
- (FBSDKAppEvents *)init
|
||||
{
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_flushBehavior = FBSDKAppEventsFlushBehaviorAuto;
|
||||
_flushTimer = [NSTimer timerWithTimeInterval:FLUSH_PERIOD_IN_SECONDS
|
||||
target:self
|
||||
selector:@selector(flushTimerFired:)
|
||||
userInfo:nil
|
||||
repeats:YES];
|
||||
_attributionIDRecheckTimer = [NSTimer timerWithTimeInterval:APP_SUPPORTS_ATTRIBUTION_ID_RECHECK_PERIOD
|
||||
target:self
|
||||
selector:@selector(appSettingsFetchStateResetTimerFired:)
|
||||
userInfo:nil
|
||||
repeats:YES];
|
||||
[[NSRunLoop mainRunLoop] addTimer:_flushTimer forMode:NSDefaultRunLoopMode];
|
||||
[[NSRunLoop mainRunLoop] addTimer:_attributionIDRecheckTimer forMode:NSDefaultRunLoopMode];
|
||||
[[NSNotificationCenter defaultCenter]
|
||||
addObserver:self
|
||||
selector:@selector(applicationMovingFromActiveStateOrTerminating)
|
||||
name:UIApplicationWillResignActiveNotification
|
||||
object:NULL];
|
||||
|
||||
[[NSNotificationCenter defaultCenter]
|
||||
addObserver:self
|
||||
selector:@selector(applicationMovingFromActiveStateOrTerminating)
|
||||
name:UIApplicationWillTerminateNotification
|
||||
object:NULL];
|
||||
|
||||
[[NSNotificationCenter defaultCenter]
|
||||
addObserver:self
|
||||
selector:@selector(applicationDidBecomeActive)
|
||||
name:UIApplicationDidBecomeActiveNotification
|
||||
object:NULL];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||
// technically these timers retain self so there's a cycle but
|
||||
// we're a singleton anyway.
|
||||
[_flushTimer invalidate];
|
||||
[_attributionIDRecheckTimer invalidate];
|
||||
}
|
||||
|
||||
#pragma mark - Public Methods
|
||||
|
||||
+ (void)logEvent:(NSString *)eventName
|
||||
{
|
||||
[FBSDKAppEvents logEvent:eventName
|
||||
parameters:nil];
|
||||
}
|
||||
|
||||
+ (void)logEvent:(NSString *)eventName
|
||||
valueToSum:(double)valueToSum
|
||||
{
|
||||
[FBSDKAppEvents logEvent:eventName
|
||||
valueToSum:valueToSum
|
||||
parameters:nil];
|
||||
}
|
||||
|
||||
+ (void)logEvent:(NSString *)eventName
|
||||
parameters:(NSDictionary *)parameters
|
||||
{
|
||||
[FBSDKAppEvents logEvent:eventName
|
||||
valueToSum:nil
|
||||
parameters:parameters
|
||||
accessToken:nil];
|
||||
}
|
||||
|
||||
+ (void)logEvent:(NSString *)eventName
|
||||
valueToSum:(double)valueToSum
|
||||
parameters:(NSDictionary *)parameters
|
||||
{
|
||||
[FBSDKAppEvents logEvent:eventName
|
||||
valueToSum:[NSNumber numberWithDouble:valueToSum]
|
||||
parameters:parameters
|
||||
accessToken:nil];
|
||||
}
|
||||
|
||||
+ (void)logEvent:(NSString *)eventName
|
||||
valueToSum:(NSNumber *)valueToSum
|
||||
parameters:(NSDictionary *)parameters
|
||||
accessToken:(FBSDKAccessToken *)accessToken
|
||||
{
|
||||
[[FBSDKAppEvents singleton] instanceLogEvent:eventName
|
||||
valueToSum:valueToSum
|
||||
parameters:parameters
|
||||
isImplicitlyLogged:NO
|
||||
accessToken:accessToken];
|
||||
}
|
||||
|
||||
+ (void)logPurchase:(double)purchaseAmount
|
||||
currency:(NSString *)currency
|
||||
{
|
||||
[FBSDKAppEvents logPurchase:purchaseAmount
|
||||
currency:currency
|
||||
parameters:nil];
|
||||
}
|
||||
|
||||
+ (void)logPurchase:(double)purchaseAmount
|
||||
currency:(NSString *)currency
|
||||
parameters:(NSDictionary *)parameters
|
||||
{
|
||||
[FBSDKAppEvents logPurchase:purchaseAmount
|
||||
currency:currency
|
||||
parameters:parameters
|
||||
accessToken:nil];
|
||||
}
|
||||
|
||||
+ (void)logPurchase:(double)purchaseAmount
|
||||
currency:(NSString *)currency
|
||||
parameters:(NSDictionary *)parameters
|
||||
accessToken:(FBSDKAccessToken *)accessToken
|
||||
{
|
||||
|
||||
// A purchase event is just a regular logged event with a given event name
|
||||
// and treating the currency value as going into the parameters dictionary.
|
||||
NSDictionary *newParameters;
|
||||
if (!parameters) {
|
||||
newParameters = @{ FBSDKAppEventParameterNameCurrency : currency };
|
||||
} else {
|
||||
newParameters = [NSMutableDictionary dictionaryWithDictionary:parameters];
|
||||
[newParameters setValue:currency forKey:FBSDKAppEventParameterNameCurrency];
|
||||
}
|
||||
|
||||
[FBSDKAppEvents logEvent:FBSDKAppEventNamePurchased
|
||||
valueToSum:[NSNumber numberWithDouble:purchaseAmount]
|
||||
parameters:newParameters
|
||||
accessToken:accessToken];
|
||||
|
||||
// Unless the behavior is set to only allow explicit flushing, we go ahead and flush, since purchase events
|
||||
// are relatively rare and relatively high value and worth getting across on wire right away.
|
||||
if ([FBSDKAppEvents flushBehavior] != FBSDKAppEventsFlushBehaviorExplicitOnly) {
|
||||
[[FBSDKAppEvents singleton] flushForReason:FBSDKAppEventsFlushReasonEagerlyFlushingEvent];
|
||||
}
|
||||
}
|
||||
|
||||
+ (void)activateApp
|
||||
{
|
||||
[FBSDKAppEventsUtility ensureOnMainThread:NSStringFromSelector(_cmd) className:NSStringFromClass(self)];
|
||||
|
||||
// Fetch app settings and register for transaction notifications only if app supports implicit purchase
|
||||
// events
|
||||
FBSDKAppEvents *instance = [FBSDKAppEvents singleton];
|
||||
[instance publishInstall];
|
||||
[instance fetchServerConfiguration:NULL];
|
||||
|
||||
// Restore time spent data, indicating that we're being called from "activateApp", which will,
|
||||
// when appropriate, result in logging an "activated app" and "deactivated app" (for the
|
||||
// previous session) App Event.
|
||||
[FBSDKTimeSpentData restore:YES];
|
||||
}
|
||||
|
||||
+ (FBSDKAppEventsFlushBehavior)flushBehavior
|
||||
{
|
||||
return [FBSDKAppEvents singleton].flushBehavior;
|
||||
}
|
||||
|
||||
+ (void)setFlushBehavior:(FBSDKAppEventsFlushBehavior)flushBehavior
|
||||
{
|
||||
[FBSDKAppEvents singleton].flushBehavior = flushBehavior;
|
||||
}
|
||||
|
||||
+ (NSString *)loggingOverrideAppID
|
||||
{
|
||||
return g_overrideAppID;
|
||||
}
|
||||
|
||||
+ (void)setLoggingOverrideAppID:(NSString *)appID
|
||||
{
|
||||
if (![g_overrideAppID isEqualToString:appID]) {
|
||||
FBSDKConditionalLog(![FBSDKAppEvents singleton]->_explicitEventsLoggedYet,
|
||||
FBSDKLoggingBehaviorDeveloperErrors,
|
||||
@"[FBSDKAppEvents setLoggingOverrideAppID:] should only be called prior to any events being logged.");
|
||||
g_overrideAppID = appID;
|
||||
}
|
||||
}
|
||||
|
||||
+ (void)flush
|
||||
{
|
||||
[[FBSDKAppEvents singleton] flushForReason:FBSDKAppEventsFlushReasonExplicit];
|
||||
}
|
||||
|
||||
#pragma mark - Internal Methods
|
||||
|
||||
+ (void)logImplicitEvent:(NSString *)eventName
|
||||
valueToSum:(NSNumber *)valueToSum
|
||||
parameters:(NSDictionary *)parameters
|
||||
accessToken:(FBSDKAccessToken *)accessToken
|
||||
{
|
||||
[[FBSDKAppEvents singleton] instanceLogEvent:eventName
|
||||
valueToSum:valueToSum
|
||||
parameters:parameters
|
||||
isImplicitlyLogged:YES
|
||||
accessToken:accessToken];
|
||||
}
|
||||
|
||||
+ (FBSDKAppEvents *)singleton
|
||||
{
|
||||
static dispatch_once_t pred;
|
||||
static FBSDKAppEvents *shared = nil;
|
||||
|
||||
dispatch_once(&pred, ^{
|
||||
shared = [[FBSDKAppEvents alloc] init];
|
||||
});
|
||||
return shared;
|
||||
}
|
||||
|
||||
- (void)flushForReason:(FBSDKAppEventsFlushReason)flushReason
|
||||
{
|
||||
// Always flush asynchronously, even on main thread, for two reasons:
|
||||
// - most consistent code path for all threads.
|
||||
// - allow locks being held by caller to be released prior to actual flushing work being done.
|
||||
@synchronized (self) {
|
||||
if (!_appEventsState) {
|
||||
return;
|
||||
}
|
||||
FBSDKAppEventsState *copy = [_appEventsState copy];
|
||||
_appEventsState = [[FBSDKAppEventsState alloc] initWithToken:copy.tokenString
|
||||
appID:copy.appID];
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[self flushOnMainQueue:copy forReason:flushReason];
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Private Methods
|
||||
- (NSString *)appID
|
||||
{
|
||||
return [FBSDKAppEvents loggingOverrideAppID] ?: [FBSDKSettings appID];
|
||||
}
|
||||
|
||||
- (void)publishInstall
|
||||
{
|
||||
NSString *appID = [self appID];
|
||||
NSString *lastAttributionPingString = [NSString stringWithFormat:@"com.facebook.sdk:lastAttributionPing%@", appID];
|
||||
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
|
||||
if ([defaults objectForKey:lastAttributionPingString]) {
|
||||
return;
|
||||
}
|
||||
[self fetchServerConfiguration:^{
|
||||
NSDictionary *params = [FBSDKAppEventsUtility activityParametersDictionaryForEvent:@"MOBILE_APP_INSTALL"
|
||||
implicitEventsOnly:NO
|
||||
shouldAccessAdvertisingID:_serverConfiguration.isAdvertisingIDEnabled];
|
||||
NSString *path = [NSString stringWithFormat:@"%@/activities", appID];
|
||||
FBSDKGraphRequest *request = [[FBSDKGraphRequest alloc] initWithGraphPath:path
|
||||
parameters:params
|
||||
tokenString:nil
|
||||
HTTPMethod:@"POST"
|
||||
flags:FBSDKGraphRequestFlagDoNotInvalidateTokenOnError | FBSDKGraphRequestFlagDisableErrorRecovery];
|
||||
[request startWithCompletionHandler:^(FBSDKGraphRequestConnection *connection, id result, NSError *error) {
|
||||
if (!error) {
|
||||
[defaults setObject:[NSDate date] forKey:lastAttributionPingString];
|
||||
NSString *lastInstallResponseKey = [NSString stringWithFormat:@"com.facebook.sdk:lastInstallResponse%@", appID];
|
||||
[defaults setObject:result forKey:lastInstallResponseKey];
|
||||
[defaults synchronize];
|
||||
}
|
||||
}];
|
||||
}];
|
||||
}
|
||||
|
||||
// app events can use a server configuration up to 24 hours old to minimize network traffic.
|
||||
- (void)fetchServerConfiguration:(void (^)(void))callback
|
||||
{
|
||||
if (_serverConfiguration == nil) {
|
||||
[FBSDKServerConfigurationManager loadServerConfigurationWithCompletionBlock:^(FBSDKServerConfiguration *serverConfiguration, NSError *error) {
|
||||
_serverConfiguration = serverConfiguration;
|
||||
|
||||
if (_serverConfiguration.implicitPurchaseLoggingEnabled) {
|
||||
[FBSDKPaymentObserver startObservingTransactions];
|
||||
} else {
|
||||
[FBSDKPaymentObserver stopObservingTransactions];
|
||||
}
|
||||
if (callback) {
|
||||
callback();
|
||||
}
|
||||
}];
|
||||
return;
|
||||
}
|
||||
if (callback) {
|
||||
callback();
|
||||
}
|
||||
}
|
||||
|
||||
- (void)instanceLogEvent:(NSString *)eventName
|
||||
valueToSum:(NSNumber *)valueToSum
|
||||
parameters:(NSDictionary *)parameters
|
||||
isImplicitlyLogged:(BOOL)isImplicitlyLogged
|
||||
accessToken:(FBSDKAccessToken *)accessToken
|
||||
{
|
||||
if (isImplicitlyLogged && _serverConfiguration && !_serverConfiguration.isImplicitLoggingSupported) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isImplicitlyLogged && !_explicitEventsLoggedYet) {
|
||||
_explicitEventsLoggedYet = YES;
|
||||
}
|
||||
|
||||
__block BOOL failed = NO;
|
||||
|
||||
if (![FBSDKAppEventsUtility validateIdentifier:eventName]) {
|
||||
failed = YES;
|
||||
}
|
||||
|
||||
// Make sure parameter dictionary is well formed. Log and exit if not.
|
||||
[parameters enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
|
||||
if (![key isKindOfClass:[NSString class]]) {
|
||||
[FBSDKAppEventsUtility logAndNotify:[NSString stringWithFormat:@"The keys in the parameters must be NSStrings, '%@' is not.", key]];
|
||||
failed = YES;
|
||||
}
|
||||
if (![FBSDKAppEventsUtility validateIdentifier:key]) {
|
||||
failed = YES;
|
||||
}
|
||||
if (![obj isKindOfClass:[NSString class]] && ![obj isKindOfClass:[NSNumber class]]) {
|
||||
[FBSDKAppEventsUtility logAndNotify:[NSString stringWithFormat:@"The values in the parameters dictionary must be NSStrings or NSNumbers, '%@' is not.", obj]];
|
||||
failed = YES;
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
if (failed) {
|
||||
return;
|
||||
}
|
||||
|
||||
NSMutableDictionary *eventDictionary = [NSMutableDictionary dictionaryWithDictionary:parameters];
|
||||
eventDictionary[@"_eventName"] = eventName;
|
||||
eventDictionary[@"_logTime"] = @([FBSDKAppEventsUtility unixTimeNow]);
|
||||
[FBSDKInternalUtility dictionary:eventDictionary setObject:valueToSum forKey:@"_valueToSum"];
|
||||
if (isImplicitlyLogged) {
|
||||
eventDictionary[@"_implicitlyLogged"] = @"1";
|
||||
}
|
||||
|
||||
NSString *currentViewControllerName;
|
||||
if ([NSThread isMainThread]) {
|
||||
// We only collect the view controller when on the main thread, as the behavior off
|
||||
// the main thread is unpredictable. Besides, UI state for off-main-thread computations
|
||||
// isn't really relevant anyhow.
|
||||
UIViewController *vc = [UIApplication sharedApplication].keyWindow.rootViewController.presentedViewController;
|
||||
if (vc) {
|
||||
currentViewControllerName = [[vc class] description];
|
||||
} else {
|
||||
currentViewControllerName = @"no_ui";
|
||||
}
|
||||
} else {
|
||||
currentViewControllerName = @"off_thread";
|
||||
}
|
||||
eventDictionary[@"_ui"] = currentViewControllerName;
|
||||
|
||||
NSString *tokenString = [FBSDKAppEventsUtility tokenStringToUseFor:accessToken];
|
||||
NSString *appID = [self appID];
|
||||
|
||||
@synchronized (self) {
|
||||
if (!_appEventsState) {
|
||||
_appEventsState = [[FBSDKAppEventsState alloc] initWithToken:tokenString appID:appID];
|
||||
} else if (![_appEventsState isCompatibleWithTokenString:tokenString appID:appID]) {
|
||||
if (self.flushBehavior == FBSDKAppEventsFlushBehaviorExplicitOnly) {
|
||||
[FBSDKAppEventsStateManager persistAppEventsData:_appEventsState];
|
||||
} else {
|
||||
[self flushForReason:FBSDKAppEventsFlushReasonSessionChange];
|
||||
}
|
||||
_appEventsState = [[FBSDKAppEventsState alloc] initWithToken:tokenString appID:appID];
|
||||
}
|
||||
|
||||
[_appEventsState addEvent:eventDictionary isImplicit:isImplicitlyLogged];
|
||||
if (!isImplicitlyLogged) {
|
||||
[FBSDKLogger singleShotLogEntry:FBSDKLoggingBehaviorAppEvents
|
||||
formatString:@"FBSDKAppEvents: Recording event @ %ld: %@",
|
||||
[FBSDKAppEventsUtility unixTimeNow],
|
||||
eventDictionary];
|
||||
}
|
||||
|
||||
[self checkPersistedEvents];
|
||||
|
||||
if (_appEventsState.events.count > NUM_LOG_EVENTS_TO_TRY_TO_FLUSH_AFTER &&
|
||||
self.flushBehavior != FBSDKAppEventsFlushBehaviorExplicitOnly) {
|
||||
[self flushForReason:FBSDKAppEventsFlushReasonEventThreshold];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// this fetches persisted event states.
|
||||
// for those matching the currently tracked events, add it.
|
||||
// otherwise, either flush (if not explicitonly behavior) or persist them back.
|
||||
- (void)checkPersistedEvents
|
||||
{
|
||||
NSArray *existingEventsStates = [FBSDKAppEventsStateManager retrievePersistedAppEventsStates];
|
||||
if (existingEventsStates.count == 0) {
|
||||
return;
|
||||
}
|
||||
FBSDKAppEventsState *matchingEventsPreviouslySaved = nil;
|
||||
// reduce lock time by creating a new FBSDKAppEventsState to collect matching persisted events.
|
||||
@synchronized(self) {
|
||||
if (_appEventsState) {
|
||||
matchingEventsPreviouslySaved = [[FBSDKAppEventsState alloc] initWithToken:_appEventsState.tokenString
|
||||
appID:_appEventsState.appID];
|
||||
}
|
||||
}
|
||||
for (FBSDKAppEventsState *saved in existingEventsStates) {
|
||||
if ([saved isCompatibleWithAppEventsState:matchingEventsPreviouslySaved]) {
|
||||
[matchingEventsPreviouslySaved addEventsFromAppEventState:saved];
|
||||
} else {
|
||||
if (self.flushBehavior == FBSDKAppEventsFlushBehaviorExplicitOnly) {
|
||||
[FBSDKAppEventsStateManager persistAppEventsData:saved];
|
||||
} else {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[self flushOnMainQueue:saved forReason:FBSDKAppEventsFlushReasonPersistedEvents];
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
if (matchingEventsPreviouslySaved.events.count > 0) {
|
||||
@synchronized(self) {
|
||||
if ([_appEventsState isCompatibleWithAppEventsState:matchingEventsPreviouslySaved]) {
|
||||
[_appEventsState addEventsFromAppEventState:matchingEventsPreviouslySaved];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)flushOnMainQueue:(FBSDKAppEventsState *)appEventsState
|
||||
forReason:(FBSDKAppEventsFlushReason)reason
|
||||
{
|
||||
if (appEventsState.events.count == 0) {
|
||||
return;
|
||||
}
|
||||
[FBSDKAppEventsUtility ensureOnMainThread:NSStringFromSelector(_cmd) className:NSStringFromClass([self class])];
|
||||
|
||||
[self fetchServerConfiguration:^(void) {
|
||||
NSString *JSONString = [appEventsState JSONStringForEvents:_serverConfiguration.implicitLoggingEnabled];
|
||||
NSData *encodedEvents = [JSONString dataUsingEncoding:NSUTF8StringEncoding];
|
||||
if (!encodedEvents) {
|
||||
[FBSDKLogger singleShotLogEntry:FBSDKLoggingBehaviorAppEvents
|
||||
logEntry:@"FBSDKAppEvents: Flushing skipped - no events after removing implicitly logged ones.\n"];
|
||||
return;
|
||||
}
|
||||
NSMutableDictionary *postParameters = [FBSDKAppEventsUtility
|
||||
activityParametersDictionaryForEvent:@"CUSTOM_APP_EVENTS"
|
||||
implicitEventsOnly:appEventsState.areAllEventsImplicit
|
||||
shouldAccessAdvertisingID:_serverConfiguration.advertisingIDEnabled];
|
||||
postParameters[@"custom_events_file"] = encodedEvents;
|
||||
if (appEventsState.numSkipped > 0) {
|
||||
postParameters[@"num_skipped_events"] = [NSString stringWithFormat:@"%lu", (unsigned long)appEventsState.numSkipped];
|
||||
}
|
||||
|
||||
NSString *loggingEntry = nil;
|
||||
if ([[FBSDKSettings loggingBehavior] containsObject:FBSDKLoggingBehaviorAppEvents]) {
|
||||
NSData *prettyJSONData = [NSJSONSerialization dataWithJSONObject:appEventsState.events
|
||||
options:NSJSONWritingPrettyPrinted
|
||||
error:NULL];
|
||||
NSString *prettyPrintedJsonEvents = [[NSString alloc] initWithData:prettyJSONData
|
||||
encoding:NSUTF8StringEncoding];
|
||||
// Remove this param -- just an encoding of the events which we pretty print later.
|
||||
NSMutableDictionary *paramsForPrinting = [postParameters mutableCopy];
|
||||
[paramsForPrinting removeObjectForKey:@"custom_events_file"];
|
||||
|
||||
loggingEntry = [NSString stringWithFormat:@"FBSDKAppEvents: Flushed @ %ld, %lu events due to '%@' - %@\nEvents: %@",
|
||||
[FBSDKAppEventsUtility unixTimeNow],
|
||||
(unsigned long)appEventsState.events.count,
|
||||
[FBSDKAppEventsUtility flushReasonToString:reason],
|
||||
paramsForPrinting,
|
||||
prettyPrintedJsonEvents];
|
||||
}
|
||||
|
||||
FBSDKGraphRequest *request = [[FBSDKGraphRequest alloc] initWithGraphPath:[NSString stringWithFormat:@"%@/activities", appEventsState.appID]
|
||||
parameters:postParameters
|
||||
tokenString:appEventsState.tokenString
|
||||
HTTPMethod:@"POST"
|
||||
flags:FBSDKGraphRequestFlagDoNotInvalidateTokenOnError | FBSDKGraphRequestFlagDisableErrorRecovery];
|
||||
|
||||
[request startWithCompletionHandler:^(FBSDKGraphRequestConnection *connection, id result, NSError *error) {
|
||||
[self handleActivitiesPostCompletion:error
|
||||
loggingEntry:loggingEntry
|
||||
appEventsState:(FBSDKAppEventsState *)appEventsState];
|
||||
}];
|
||||
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)handleActivitiesPostCompletion:(NSError *)error
|
||||
loggingEntry:(NSString *)loggingEntry
|
||||
appEventsState:(FBSDKAppEventsState *)appEventsState
|
||||
{
|
||||
typedef NS_ENUM(NSUInteger, FBSDKAppEventsFlushResult) {
|
||||
FlushResultSuccess,
|
||||
FlushResultServerError,
|
||||
FlushResultNoConnectivity
|
||||
};
|
||||
|
||||
[FBSDKAppEventsUtility ensureOnMainThread:NSStringFromSelector(_cmd) className:NSStringFromClass([self class])];
|
||||
|
||||
FBSDKAppEventsFlushResult flushResult = FlushResultSuccess;
|
||||
if (error) {
|
||||
NSInteger errorCode = [error.userInfo[FBSDKGraphRequestErrorHTTPStatusCodeKey] integerValue];
|
||||
|
||||
// We interpret a 400 coming back from FBRequestConnection as a server error due to improper data being
|
||||
// sent down. Otherwise we assume no connectivity, or another condition where we could treat it as no connectivity.
|
||||
flushResult = errorCode == 400 ? FlushResultServerError : FlushResultNoConnectivity;
|
||||
}
|
||||
|
||||
if (flushResult == FlushResultServerError) {
|
||||
// Only log events that developer can do something with (i.e., if parameters are incorrect).
|
||||
// as opposed to cases where the token is bad.
|
||||
if ([error.userInfo[FBSDKGraphRequestErrorCategoryKey] unsignedIntegerValue] == FBSDKGraphRequestErrorCategoryOther) {
|
||||
NSString *message = [NSString stringWithFormat:@"Failed to send AppEvents: %@", error];
|
||||
[FBSDKAppEventsUtility logAndNotify:message allowLogAsDeveloperError:!appEventsState.areAllEventsImplicit];
|
||||
}
|
||||
} else if (flushResult == FlushResultNoConnectivity) {
|
||||
@synchronized(self) {
|
||||
if ([appEventsState isCompatibleWithAppEventsState:_appEventsState]) {
|
||||
[_appEventsState addEventsFromAppEventState:appEventsState];
|
||||
} else {
|
||||
// flush failed due to connectivity. Persist to be tried again later.
|
||||
[FBSDKAppEventsStateManager persistAppEventsData:appEventsState];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NSString *resultString = @"<unknown>";
|
||||
switch (flushResult) {
|
||||
case FlushResultSuccess:
|
||||
resultString = @"Success";
|
||||
break;
|
||||
|
||||
case FlushResultNoConnectivity:
|
||||
resultString = @"No Connectivity";
|
||||
break;
|
||||
|
||||
case FlushResultServerError:
|
||||
resultString = [NSString stringWithFormat:@"Server Error - %@", [error description]];
|
||||
break;
|
||||
}
|
||||
|
||||
[FBSDKLogger singleShotLogEntry:FBSDKLoggingBehaviorAppEvents
|
||||
formatString:@"%@\nFlush Result : %@", loggingEntry, resultString];
|
||||
}
|
||||
|
||||
- (void)flushTimerFired:(id)arg
|
||||
{
|
||||
[FBSDKAppEventsUtility ensureOnMainThread:NSStringFromSelector(_cmd) className:NSStringFromClass([self class])];
|
||||
if (self.flushBehavior != FBSDKAppEventsFlushBehaviorExplicitOnly && !self.disableTimer) {
|
||||
[self flushForReason:FBSDKAppEventsFlushReasonTimer];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)appSettingsFetchStateResetTimerFired:(id)arg
|
||||
{
|
||||
_serverConfiguration = nil;
|
||||
}
|
||||
|
||||
- (void)applicationDidBecomeActive
|
||||
{
|
||||
[FBSDKAppEventsUtility ensureOnMainThread:NSStringFromSelector(_cmd) className:NSStringFromClass([self class])];
|
||||
|
||||
[self checkPersistedEvents];
|
||||
|
||||
// Restore time spent data, indicating that we're not being called from "activateApp".
|
||||
[FBSDKTimeSpentData restore:NO];
|
||||
}
|
||||
|
||||
- (void)applicationMovingFromActiveStateOrTerminating
|
||||
{
|
||||
// When moving from active state, we don't have time to wait for the result of a flush, so
|
||||
// just persist events to storage, and we'll process them at the next activation.
|
||||
FBSDKAppEventsState *copy = nil;
|
||||
@synchronized (self) {
|
||||
copy = [_appEventsState copy];
|
||||
_appEventsState = nil;
|
||||
}
|
||||
if (copy) {
|
||||
[FBSDKAppEventsStateManager persistAppEventsData:copy];
|
||||
}
|
||||
[FBSDKTimeSpentData suspend];
|
||||
}
|
||||
|
||||
#pragma mark - Custom Audience
|
||||
|
||||
+ (FBSDKGraphRequest *)requestForCustomAudienceThirdPartyIDWithAccessToken:(FBSDKAccessToken *)accessToken
|
||||
{
|
||||
accessToken = accessToken ?: [FBSDKAccessToken currentAccessToken];
|
||||
// Rules for how we use the attribution ID / advertiser ID for an 'custom_audience_third_party_id' Graph API request
|
||||
// 1) if the OS tells us that the user has Limited Ad Tracking, then just don't send, and return a nil in the token.
|
||||
// 2) if the app has set 'limitEventAndDataUsage', this effectively implies that app-initiated ad targeting shouldn't happen,
|
||||
// so use that data here to return nil as well.
|
||||
// 3) if we have a user session token, then no need to send attribution ID / advertiser ID back as the udid parameter
|
||||
// 4) otherwise, send back the udid parameter.
|
||||
|
||||
if ([FBSDKAppEventsUtility advertisingTrackingStatus] == FBSDKAdvertisingTrackingDisallowed || [FBSDKSettings limitEventAndDataUsage]) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
NSString *tokenString = [FBSDKAppEventsUtility tokenStringToUseFor:accessToken];
|
||||
NSString *udid = nil;
|
||||
if (!accessToken) {
|
||||
// We don't have a logged in user, so we need some form of udid representation. Prefer advertiser ID if
|
||||
// available, and back off to attribution ID if not. Note that this function only makes sense to be
|
||||
// called in the context of advertising.
|
||||
udid = [FBSDKAppEventsUtility advertiserID];
|
||||
if (!udid) {
|
||||
udid = [FBSDKAppEventsUtility attributionID];
|
||||
}
|
||||
|
||||
if (!udid) {
|
||||
// No udid, and no user token. No point in making the request.
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
|
||||
NSDictionary *parameters = nil;
|
||||
if (udid) {
|
||||
parameters = @{ @"udid" : udid };
|
||||
}
|
||||
|
||||
NSString *graphPath = [NSString stringWithFormat:@"%@/custom_audience_third_party_id", [[self singleton] appID]];
|
||||
FBSDKGraphRequest *request = [[FBSDKGraphRequest alloc] initWithGraphPath:graphPath
|
||||
parameters:parameters
|
||||
tokenString:tokenString
|
||||
HTTPMethod:nil
|
||||
flags:FBSDKGraphRequestFlagDoNotInvalidateTokenOnError | FBSDKGraphRequestFlagDisableErrorRecovery];
|
||||
|
||||
return request;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,82 @@
|
||||
// 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>
|
||||
|
||||
@class BFTask;
|
||||
|
||||
// Check if Bolts.framework is available for import
|
||||
#if __has_include(<Bolts/BFAppLinkResolving.h>)
|
||||
// Import it if it's available
|
||||
# import <Bolts/BFAppLinkResolving.h>
|
||||
#else
|
||||
// Otherwise - redeclare BFAppLinkResolving protocol to resolve the problem of missing symbols
|
||||
// Please note: Bolts.framework is still required for AppLink resolving to work,
|
||||
// but this allows FBSDKCoreKit to weakly link Bolts.framework as well as this enables clang modulemaps to work.
|
||||
|
||||
/*!
|
||||
Implement this protocol to provide an alternate strategy for resolving
|
||||
App Links that may include pre-fetching, caching, or querying for App Link
|
||||
data from an index provided by a service provider.
|
||||
*/
|
||||
@protocol BFAppLinkResolving <NSObject>
|
||||
|
||||
/*!
|
||||
Asynchronously resolves App Link data for a given URL.
|
||||
|
||||
@param url The URL to resolve into an App Link.
|
||||
@returns A BFTask that will return a BFAppLink for the given URL.
|
||||
*/
|
||||
- (BFTask *)appLinkFromURLInBackground:(NSURL *)url;
|
||||
|
||||
@end
|
||||
|
||||
#endif
|
||||
|
||||
/*!
|
||||
@class FBSDKAppLinkResolver
|
||||
|
||||
@abstract
|
||||
Provides an implementation of the BFAppLinkResolving protocol that uses the Facebook App Link
|
||||
Index API to resolve App Links given a URL. It also provides an additional helper method that can resolve
|
||||
multiple App Links in a single call.
|
||||
|
||||
@discussion
|
||||
Usage of this type requires a client token. See `[FBSDKSettings setClientToken:]` and linking
|
||||
Bolts.framework
|
||||
*/
|
||||
@interface FBSDKAppLinkResolver : NSObject<BFAppLinkResolving>
|
||||
|
||||
/*!
|
||||
@abstract Asynchronously resolves App Link data for multiple URLs.
|
||||
|
||||
@param urls An array of NSURLs to resolve into App Links.
|
||||
@returns A BFTask that will return dictionary mapping input NSURLs to their
|
||||
corresponding BFAppLink.
|
||||
|
||||
@discussion
|
||||
You should set the client token before making this call. See `[FBSDKSettings setClientToken:]`
|
||||
*/
|
||||
- (BFTask *)appLinksFromURLsInBackground:(NSArray *)urls;
|
||||
|
||||
/*!
|
||||
@abstract Allocates and initializes a new instance of FBSDKAppLinkResolver.
|
||||
*/
|
||||
+ (instancetype)resolver;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,195 @@
|
||||
// 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 "FBSDKAppLinkResolver.h"
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
#import <Bolts/BFAppLink.h>
|
||||
#import <Bolts/BFAppLinkTarget.h>
|
||||
#import <Bolts/BFTask.h>
|
||||
#import <Bolts/BFTaskCompletionSource.h>
|
||||
|
||||
#import "FBSDKGraphRequest+Internal.h"
|
||||
#import "FBSDKGraphRequestConnection.h"
|
||||
#import "FBSDKLogger.h"
|
||||
#import "FBSDKSettings+Internal.h"
|
||||
#import "FBSDKUtility.h"
|
||||
|
||||
static NSString *const kURLKey = @"url";
|
||||
static NSString *const kIOSAppStoreIdKey = @"app_store_id";
|
||||
static NSString *const kIOSAppNameKey = @"app_name";
|
||||
static NSString *const kWebKey = @"web";
|
||||
static NSString *const kIOSKey = @"ios";
|
||||
static NSString *const kIPhoneKey = @"iphone";
|
||||
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;
|
||||
@property (nonatomic, assign) UIUserInterfaceIdiom userInterfaceIdiom;
|
||||
@end
|
||||
|
||||
@implementation FBSDKAppLinkResolver
|
||||
|
||||
static Class g_BFTaskCompletionSourceClass;
|
||||
static Class g_BFAppLinkTargetClass;
|
||||
static Class g_BFAppLinkClass;
|
||||
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");
|
||||
}
|
||||
}
|
||||
|
||||
- (id)initWithUserInterfaceIdiom:(UIUserInterfaceIdiom)userInterfaceIdiom
|
||||
{
|
||||
if (self = [super init]) {
|
||||
self.cachedLinks = [NSMutableDictionary dictionary];
|
||||
self.userInterfaceIdiom = userInterfaceIdiom;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (BFTask *)appLinksFromURLsInBackground:(NSArray *)urls
|
||||
{
|
||||
if (![FBSDKSettings clientToken] && ![FBSDKAccessToken currentAccessToken]) {
|
||||
[FBSDKLogger singleShotLogEntry:FBSDKLoggingBehaviorDeveloperErrors
|
||||
logEntry:@"A user access token or clientToken is required to use FBAppLinkResolver"];
|
||||
}
|
||||
NSMutableDictionary *appLinks = [NSMutableDictionary dictionary];
|
||||
NSMutableArray *toFind = [NSMutableArray array];
|
||||
NSMutableArray *toFindStrings = [NSMutableArray array];
|
||||
|
||||
@synchronized (self.cachedLinks) {
|
||||
for (NSURL *url in urls) {
|
||||
if (self.cachedLinks[url]) {
|
||||
appLinks[url] = self.cachedLinks[url];
|
||||
} else {
|
||||
[toFind addObject:url];
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||
[toFindStrings addObject:[url.absoluteString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
|
||||
#pragma clang diagnostic pop
|
||||
}
|
||||
}
|
||||
}
|
||||
if (toFind.count == 0) {
|
||||
// All of the URLs have already been found.
|
||||
return [g_BFTaskClass taskWithResult:appLinks];
|
||||
}
|
||||
NSMutableArray *fields = [NSMutableArray arrayWithObject:kIOSKey];
|
||||
|
||||
NSString *idiomSpecificField = nil;
|
||||
|
||||
switch (self.userInterfaceIdiom) {
|
||||
case UIUserInterfaceIdiomPad:
|
||||
idiomSpecificField = kIPadKey;
|
||||
break;
|
||||
case UIUserInterfaceIdiomPhone:
|
||||
idiomSpecificField = kIPhoneKey;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (idiomSpecificField) {
|
||||
[fields addObject:idiomSpecificField];
|
||||
}
|
||||
NSString *path = [NSString stringWithFormat:@"?fields=%@.fields(%@)&ids=%@",
|
||||
kAppLinksKey,
|
||||
[fields componentsJoinedByString:@","],
|
||||
[toFindStrings componentsJoinedByString:@","]];
|
||||
FBSDKGraphRequest *request = [[FBSDKGraphRequest alloc] initWithGraphPath:path
|
||||
parameters:nil
|
||||
flags:FBSDKGraphRequestFlagDoNotInvalidateTokenOnError | FBSDKGraphRequestFlagDisableErrorRecovery];
|
||||
BFTaskCompletionSource *tcs = [g_BFTaskCompletionSourceClass taskCompletionSource];
|
||||
[request startWithCompletionHandler:^(FBSDKGraphRequestConnection *connection, id result, NSError *error) {
|
||||
if (error) {
|
||||
[tcs setError:error];
|
||||
return;
|
||||
}
|
||||
for (NSURL *url in toFind) {
|
||||
id nestedObject = [[result objectForKey:url.absoluteString] objectForKey:kAppLinksKey];
|
||||
NSMutableArray *rawTargets = [NSMutableArray array];
|
||||
if (idiomSpecificField) {
|
||||
[rawTargets addObjectsFromArray:[nestedObject objectForKey:idiomSpecificField]];
|
||||
}
|
||||
[rawTargets addObjectsFromArray:[nestedObject objectForKey:kIOSKey]];
|
||||
|
||||
NSMutableArray *targets = [NSMutableArray arrayWithCapacity:rawTargets.count];
|
||||
for (id rawTarget in rawTargets) {
|
||||
[targets addObject:[g_BFAppLinkTargetClass appLinkTargetWithURL:[NSURL URLWithString:[rawTarget objectForKey:kURLKey]]
|
||||
appStoreId:[rawTarget objectForKey:kIOSAppStoreIdKey]
|
||||
appName:[rawTarget objectForKey:kIOSAppNameKey]]];
|
||||
}
|
||||
|
||||
id webTarget = [nestedObject objectForKey:kWebKey];
|
||||
NSString *webFallbackString = [webTarget objectForKey:kURLKey];
|
||||
NSURL *fallbackUrl = webFallbackString ? [NSURL URLWithString:webFallbackString] : url;
|
||||
|
||||
NSNumber *shouldFallback = [webTarget objectForKey:kShouldFallbackKey];
|
||||
if (shouldFallback && !shouldFallback.boolValue) {
|
||||
fallbackUrl = nil;
|
||||
}
|
||||
|
||||
BFAppLink *link = [g_BFAppLinkClass appLinkWithSourceURL:url
|
||||
targets:targets
|
||||
webURL:fallbackUrl];
|
||||
@synchronized (self.cachedLinks) {
|
||||
self.cachedLinks[url] = link;
|
||||
}
|
||||
appLinks[url] = link;
|
||||
}
|
||||
[tcs setResult:appLinks];
|
||||
}];
|
||||
return tcs.task;
|
||||
}
|
||||
|
||||
- (BFTask *)appLinkFromURLInBackground:(NSURL *)url
|
||||
{
|
||||
// Implement in terms of appLinksFromURLsInBackground
|
||||
BFTask *resolveTask = [self appLinksFromURLsInBackground:@[url]];
|
||||
return [resolveTask continueWithSuccessBlock:^id(BFTask *task) {
|
||||
return task.result[url];
|
||||
}];
|
||||
}
|
||||
|
||||
+ (id)resolver
|
||||
{
|
||||
return [[self alloc] initWithUserInterfaceIdiom:UI_USER_INTERFACE_IDIOM()];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,55 @@
|
||||
// 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>
|
||||
|
||||
/*!
|
||||
@abstract Describes the callback for fetchDeferredAppLink.
|
||||
@param url the url representing the deferred App Link
|
||||
@param error the error during the request, if any
|
||||
|
||||
@discussion The url may also have a fb_click_time_utc query parameter that
|
||||
represents when the click occurred that caused the deferred App Link to be created.
|
||||
*/
|
||||
typedef void (^FBSDKDeferredAppLinkHandler)(NSURL *url, NSError *error);
|
||||
|
||||
/*!
|
||||
@abstract Class containing App Links related utility methods.
|
||||
*/
|
||||
@interface FBSDKAppLinkUtility : NSObject
|
||||
|
||||
/*!
|
||||
@abstract
|
||||
Call this method from the main thread to fetch deferred applink data if you use Mobile App
|
||||
Engagement Ads (https://developers.facebook.com/docs/ads-for-apps/mobile-app-ads-engagement).
|
||||
This may require a network round trip. If successful, the handler is invoked with the link
|
||||
data (this will only return a valid URL once, and future calls will result in a nil URL
|
||||
value in the callback).
|
||||
|
||||
@param handler the handler to be invoked if there is deferred App Link data
|
||||
|
||||
@discussion The handler may contain an NSError instance to capture any errors. In the
|
||||
common case where there simply was no app link data, the NSError instance will be nil.
|
||||
|
||||
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
|
||||
applicationDidBecomeActive:).
|
||||
*/
|
||||
+ (void)fetchDeferredAppLink:(FBSDKDeferredAppLinkHandler)handler;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,80 @@
|
||||
// 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 "FBSDKAppLinkUtility.h"
|
||||
|
||||
#import "FBSDKAppEventsUtility.h"
|
||||
#import "FBSDKGraphRequest.h"
|
||||
#import "FBSDKSettings.h"
|
||||
#import "FBSDKUtility.h"
|
||||
|
||||
static NSString *const FBSDKLastDeferredAppLink = @"com.facebook.sdk:lastDeferredAppLink%@";
|
||||
static NSString *const FBSDKDeferredAppLinkEvent = @"DEFERRED_APP_LINK";
|
||||
|
||||
@implementation FBSDKAppLinkUtility {}
|
||||
|
||||
+ (void)fetchDeferredAppLink:(FBSDKDeferredAppLinkHandler)handler
|
||||
{
|
||||
NSAssert([NSThread isMainThread], @"FBSDKAppLink fetchDeferredAppLink: must be invoked from main thread.");
|
||||
|
||||
NSString *appID = [FBSDKSettings appID];
|
||||
|
||||
// Deferred app links are only currently used for engagement ads, thus we consider the app to be an advertising one.
|
||||
// If this is considered for organic, non-ads scenarios, we'll need to retrieve the FBAppEventsUtility.shouldAccessAdvertisingID
|
||||
// before we make this call.
|
||||
NSMutableDictionary *deferredAppLinkParameters =
|
||||
[FBSDKAppEventsUtility activityParametersDictionaryForEvent:FBSDKDeferredAppLinkEvent
|
||||
implicitEventsOnly:NO
|
||||
shouldAccessAdvertisingID:YES];
|
||||
|
||||
FBSDKGraphRequest *deferredAppLinkRequest = [[FBSDKGraphRequest alloc] initWithGraphPath:[NSString stringWithFormat:@"%@/activities", appID, nil]
|
||||
parameters:deferredAppLinkParameters
|
||||
tokenString:nil
|
||||
version:nil
|
||||
HTTPMethod:@"POST"];
|
||||
|
||||
[deferredAppLinkRequest startWithCompletionHandler:^(FBSDKGraphRequestConnection *connection,
|
||||
id result,
|
||||
NSError *error) {
|
||||
NSURL *applinkURL = nil;
|
||||
if (!error) {
|
||||
NSString *appLinkString = result[@"applink_url"];
|
||||
if (appLinkString) {
|
||||
applinkURL = [NSURL URLWithString:appLinkString];
|
||||
|
||||
NSString *createTimeUtc = result[@"click_time"];
|
||||
if (createTimeUtc) {
|
||||
// append/translate the create_time_utc so it can be used by clients
|
||||
NSString *modifiedURLString = [[applinkURL absoluteString]
|
||||
stringByAppendingFormat:@"%@fb_click_time_utc=%@",
|
||||
([applinkURL query]) ? @"&" : @"?" ,
|
||||
createTimeUtc ];
|
||||
applinkURL = [NSURL URLWithString:modifiedURLString];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (handler) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
handler(applinkURL, error);
|
||||
});
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
@end
|
||||
+74
@@ -0,0 +1,74 @@
|
||||
// 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 <UIKit/UIKit.h>
|
||||
|
||||
/*!
|
||||
@class FBSDKApplicationDelegate
|
||||
|
||||
@abstract
|
||||
The FBSDKApplicationDelegate is designed to post process the results from Facebook Login
|
||||
or Facebook Dialogs (or any action that requires switching over to the native Facebook
|
||||
app or Safari).
|
||||
|
||||
@discussion
|
||||
The methods in this class are designed to mirror those in UIApplicationDelegate, and you
|
||||
should call them in the respective methods in your AppDelegate implementation.
|
||||
*/
|
||||
@interface FBSDKApplicationDelegate : NSObject
|
||||
|
||||
/*!
|
||||
@abstract Gets the singleton instance.
|
||||
*/
|
||||
+ (instancetype)sharedInstance;
|
||||
|
||||
/*!
|
||||
@abstract
|
||||
Call this method from the [UIApplicationDelegate application:openURL:sourceApplication:annotation:] method
|
||||
of the AppDelegate for your app. It should be invoked for the proper processing of responses during interaction
|
||||
with the native Facebook app or Safari as part of SSO authorization flow or Facebook dialogs.
|
||||
|
||||
@param application The application as passed to [UIApplicationDelegate application:openURL:sourceApplication:annotation:].
|
||||
|
||||
@param url The URL as passed to [UIApplicationDelegate application:openURL:sourceApplication:annotation:].
|
||||
|
||||
@param sourceApplication The sourceApplication as passed to [UIApplicationDelegate application:openURL:sourceApplication:annotation:].
|
||||
|
||||
@param annotation The annotation as passed to [UIApplicationDelegate application:openURL:sourceApplication:annotation:].
|
||||
|
||||
@return YES if the url was intended for the Facebook SDK, NO if not.
|
||||
*/
|
||||
- (BOOL)application:(UIApplication *)application
|
||||
openURL:(NSURL *)url
|
||||
sourceApplication:(NSString *)sourceApplication
|
||||
annotation:(id)annotation;
|
||||
|
||||
/*!
|
||||
@abstract
|
||||
Call this method from the [UIApplicationDelegate application:didFinishLaunchingWithOptions:] method
|
||||
of the AppDelegate for your app. It should be invoked for the proper use of the Facebook SDK.
|
||||
|
||||
@param application The application as passed to [UIApplicationDelegate application:didFinishLaunchingWithOptions:].
|
||||
|
||||
@param launchOptions The launchOptions as passed to [UIApplicationDelegate application:didFinishLaunchingWithOptions:].
|
||||
|
||||
@return YES if the url was intended for the Facebook SDK, NO if not.
|
||||
*/
|
||||
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions;
|
||||
|
||||
@end
|
||||
+449
@@ -0,0 +1,449 @@
|
||||
// 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 "FBSDKApplicationDelegate.h"
|
||||
#import "FBSDKApplicationDelegate+Internal.h"
|
||||
|
||||
#import <objc/runtime.h>
|
||||
|
||||
#import "FBSDKAppEvents+Internal.h"
|
||||
#import "FBSDKConstants.h"
|
||||
#import "FBSDKDynamicFrameworkLoader.h"
|
||||
#import "FBSDKError.h"
|
||||
#import "FBSDKInternalUtility.h"
|
||||
#import "FBSDKLogger.h"
|
||||
#import "FBSDKServerConfiguration.h"
|
||||
#import "FBSDKServerConfigurationManager.h"
|
||||
#import "FBSDKSettings+Internal.h"
|
||||
#import "FBSDKTimeSpentData.h"
|
||||
#import "FBSDKUtility.h"
|
||||
|
||||
#if !TARGET_OS_TV
|
||||
#import "FBSDKBoltsMeasurementEventListener.h"
|
||||
#import "FBSDKBridgeAPIRequest.h"
|
||||
#import "FBSDKBridgeAPIResponse.h"
|
||||
#import "FBSDKContainerViewController.h"
|
||||
#import "FBSDKProfile+Internal.h"
|
||||
#endif
|
||||
|
||||
NSString *const FBSDKApplicationDidBecomeActiveNotification = @"com.facebook.sdk.FBSDKApplicationDidBecomeActiveNotification";
|
||||
|
||||
static NSString *const FBSDKAppLinkInboundEvent = @"fb_al_inbound";
|
||||
|
||||
@implementation FBSDKApplicationDelegate
|
||||
{
|
||||
#if !TARGET_OS_TV
|
||||
FBSDKBridgeAPIRequest *_pendingRequest;
|
||||
FBSDKBridgeAPICallbackBlock _pendingRequestCompletionBlock;
|
||||
id<FBSDKURLOpening> _pendingURLOpen;
|
||||
#endif
|
||||
BOOL _expectingBackground;
|
||||
UIViewController *_safariViewController;
|
||||
}
|
||||
|
||||
#pragma mark - Class Methods
|
||||
|
||||
+ (void)load
|
||||
{
|
||||
// when the app becomes active by any means, kick off the initialization.
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(initializeWithLaunchData:)
|
||||
name:UIApplicationDidFinishLaunchingNotification
|
||||
object:nil];
|
||||
}
|
||||
|
||||
// Initialize SDK listeners
|
||||
// Don't call this function in any place else. It should only be called when the class is loaded.
|
||||
+ (void)initializeWithLaunchData:(NSNotification *)note
|
||||
{
|
||||
NSDictionary *launchData = note.userInfo;
|
||||
#if !TARGET_OS_TV
|
||||
// Register Listener for Bolts measurement events
|
||||
[FBSDKBoltsMeasurementEventListener defaultListener];
|
||||
#endif
|
||||
// Set the SourceApplication for time spent data. This is not going to update the value if the app has already launched.
|
||||
[FBSDKTimeSpentData setSourceApplication:launchData[UIApplicationLaunchOptionsSourceApplicationKey]
|
||||
openURL:launchData[UIApplicationLaunchOptionsURLKey]];
|
||||
// Register on UIApplicationDidEnterBackgroundNotification events to reset source application data when app backgrounds.
|
||||
[FBSDKTimeSpentData registerAutoResetSourceApplication];
|
||||
|
||||
// Remove the observer
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||
}
|
||||
|
||||
+ (instancetype)sharedInstance
|
||||
{
|
||||
static FBSDKApplicationDelegate *_sharedInstance;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
_sharedInstance = [[self alloc] _init];
|
||||
});
|
||||
return _sharedInstance;
|
||||
}
|
||||
|
||||
#pragma mark - Object Lifecycle
|
||||
|
||||
- (instancetype)_init
|
||||
{
|
||||
if ((self = [super init]) != nil) {
|
||||
NSNotificationCenter *defaultCenter = [NSNotificationCenter defaultCenter];
|
||||
[defaultCenter addObserver:self selector:@selector(applicationDidEnterBackground:) name:UIApplicationDidEnterBackgroundNotification object:nil];
|
||||
[defaultCenter addObserver:self selector:@selector(applicationDidBecomeActive:) name:UIApplicationDidBecomeActiveNotification object:nil];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (instancetype)init
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||
}
|
||||
|
||||
#pragma mark - UIApplicationDelegate
|
||||
|
||||
- (BOOL)application:(UIApplication *)application
|
||||
openURL:(NSURL *)url
|
||||
sourceApplication:(NSString *)sourceApplication
|
||||
annotation:(id)annotation
|
||||
{
|
||||
if (sourceApplication != nil && ![sourceApplication isKindOfClass:[NSString class]]) {
|
||||
@throw [NSException exceptionWithName:NSInvalidArgumentException
|
||||
reason:@"Expected 'sourceApplication' to be NSString. Please verify you are passing in 'sourceApplication' from your app delegate (not the UIApplication* parameter). If your app delegate implements iOS 9's application:openURL:options:, you should pass in options[UIApplicationOpenURLOptionsSourceApplicationKey]. "
|
||||
userInfo:nil];
|
||||
}
|
||||
[FBSDKTimeSpentData setSourceApplication:sourceApplication openURL:url];
|
||||
#if !TARGET_OS_TV
|
||||
// if they completed a SFVC flow, dimiss it.
|
||||
[_safariViewController.presentingViewController dismissViewControllerAnimated:YES completion: nil];
|
||||
_safariViewController = nil;
|
||||
|
||||
if (_pendingURLOpen) {
|
||||
id<FBSDKURLOpening> pendingURLOpen = _pendingURLOpen;
|
||||
|
||||
_pendingURLOpen = nil;
|
||||
|
||||
if ([pendingURLOpen application:application
|
||||
openURL:url
|
||||
sourceApplication:sourceApplication
|
||||
annotation:annotation]) {
|
||||
return YES;
|
||||
}
|
||||
}
|
||||
if ([self _handleBridgeAPIResponseURL:url sourceApplication:sourceApplication]) {
|
||||
return YES;
|
||||
}
|
||||
#endif
|
||||
[self _logIfAppLinkEvent:url];
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
|
||||
{
|
||||
FBSDKAccessToken *cachedToken = [[FBSDKSettings accessTokenCache] fetchAccessToken];
|
||||
[FBSDKAccessToken setCurrentAccessToken:cachedToken];
|
||||
|
||||
#if !TARGET_OS_TV
|
||||
FBSDKProfile *cachedProfile = [FBSDKProfile fetchCachedProfile];
|
||||
[FBSDKProfile setCurrentProfile:cachedProfile];
|
||||
|
||||
NSURL *launchedURL = launchOptions[UIApplicationLaunchOptionsURLKey];
|
||||
NSString *sourceApplication = launchOptions[UIApplicationLaunchOptionsSourceApplicationKey];
|
||||
|
||||
if (launchedURL &&
|
||||
sourceApplication) {
|
||||
Class loginManagerClass = NSClassFromString(@"FBSDKLoginManager");
|
||||
if (loginManagerClass) {
|
||||
id annotation = launchOptions[UIApplicationLaunchOptionsAnnotationKey];
|
||||
id<FBSDKURLOpening> loginManager = [[loginManagerClass alloc] init];
|
||||
return [loginManager application:application
|
||||
openURL:launchedURL
|
||||
sourceApplication:sourceApplication
|
||||
annotation:annotation];
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (void)applicationDidEnterBackground:(NSNotification *)notification
|
||||
{
|
||||
_active = NO;
|
||||
_expectingBackground = NO;
|
||||
}
|
||||
|
||||
- (void)applicationDidBecomeActive:(NSNotification *)notification
|
||||
{
|
||||
// _expectingBackground can be YES if the caller started doing work (like login)
|
||||
// within the app delegate's lifecycle like openURL, in which case there
|
||||
// might have been a "didBecomeActive" event pending that we want to ignore.
|
||||
if (!_expectingBackground && !_safariViewController) {
|
||||
_active = YES;
|
||||
#if !TARGET_OS_TV
|
||||
[_pendingURLOpen applicationDidBecomeActive:[notification object]];
|
||||
[self _cancelBridgeRequest];
|
||||
#endif
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:FBSDKApplicationDidBecomeActiveNotification object:self];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Internal Methods
|
||||
|
||||
#pragma mark -- (non-tvos)
|
||||
|
||||
#if !TARGET_OS_TV
|
||||
|
||||
- (void)openURL:(NSURL *)url sender:(id<FBSDKURLOpening>)sender handler:(void(^)(BOOL))handler
|
||||
{
|
||||
_expectingBackground = YES;
|
||||
_pendingURLOpen = sender;
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
// Dispatch openURL calls to prevent hangs if we're inside the current app delegate's openURL flow already
|
||||
BOOL opened = [[UIApplication sharedApplication] openURL:url];
|
||||
|
||||
if ([url.scheme hasPrefix:@"http"] && !opened) {
|
||||
NSOperatingSystemVersion iOS8Version = { .majorVersion = 8, .minorVersion = 0, .patchVersion = 0 };
|
||||
if (![FBSDKInternalUtility isOSRunTimeVersionAtLeast:iOS8Version]) {
|
||||
// Safari openURL calls can wrongly return NO on iOS 7 so manually overwrite that case to YES.
|
||||
// Otherwise we would rather trust in the actual result of openURL
|
||||
opened = YES;
|
||||
}
|
||||
}
|
||||
if (handler) {
|
||||
handler(opened);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
- (void)openBridgeAPIRequest:(FBSDKBridgeAPIRequest *)request
|
||||
useSafariViewController:(BOOL)useSafariViewController
|
||||
fromViewController:(UIViewController *)fromViewController
|
||||
completionBlock:(FBSDKBridgeAPICallbackBlock)completionBlock
|
||||
{
|
||||
if (!request) {
|
||||
return;
|
||||
}
|
||||
NSError *error;
|
||||
NSURL *requestURL = [request requestURL:&error];
|
||||
if (!requestURL) {
|
||||
FBSDKBridgeAPIResponse *response = [FBSDKBridgeAPIResponse bridgeAPIResponseWithRequest:request error:error];
|
||||
completionBlock(response);
|
||||
return;
|
||||
}
|
||||
_pendingRequest = request;
|
||||
_pendingRequestCompletionBlock = [completionBlock copy];
|
||||
void (^handler)(BOOL) = ^(BOOL openedURL) {
|
||||
if (!openedURL) {
|
||||
_pendingRequest = nil;
|
||||
_pendingRequestCompletionBlock = nil;
|
||||
NSError *openedURLError;
|
||||
if ([request.scheme hasPrefix:@"http"]) {
|
||||
openedURLError = [FBSDKError errorWithCode:FBSDKBrowswerUnavailableErrorCode
|
||||
message:@"the app switch failed because the browser is unavailable"];
|
||||
} else {
|
||||
openedURLError = [FBSDKError errorWithCode:FBSDKAppVersionUnsupportedErrorCode
|
||||
message:@"the app switch failed because the destination app is out of date"];
|
||||
}
|
||||
FBSDKBridgeAPIResponse *response = [FBSDKBridgeAPIResponse bridgeAPIResponseWithRequest:request
|
||||
error:openedURLError];
|
||||
completionBlock(response);
|
||||
return;
|
||||
}
|
||||
};
|
||||
if (useSafariViewController) {
|
||||
[self openURLWithSafariViewController:requestURL sender:nil fromViewController:fromViewController handler:handler];
|
||||
} else {
|
||||
[self openURL:requestURL sender:nil handler:handler];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)openURLWithSafariViewController:(NSURL *)url
|
||||
sender:(id<FBSDKURLOpening>)sender
|
||||
fromViewController:(UIViewController *)fromViewController
|
||||
handler:(void(^)(BOOL))handler
|
||||
{
|
||||
if (![url.scheme hasPrefix:@"http"]) {
|
||||
[self openURL:url sender:sender handler:handler];
|
||||
return;
|
||||
}
|
||||
|
||||
_expectingBackground = NO;
|
||||
_pendingURLOpen = sender;
|
||||
|
||||
// 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) {
|
||||
UIViewController *parent = fromViewController ?: [FBSDKInternalUtility topMostViewController];
|
||||
NSURLComponents *components = [NSURLComponents componentsWithURL:url resolvingAgainstBaseURL:NO];
|
||||
NSURLQueryItem *sfvcQueryItem = [[NSURLQueryItem alloc] initWithName:@"sfvc" value:@"1"];
|
||||
[components setQueryItems:[components.queryItems arrayByAddingObject:sfvcQueryItem]];
|
||||
url = components.URL;
|
||||
FBSDKContainerViewController *container = [[FBSDKContainerViewController alloc] init];
|
||||
container.delegate = self;
|
||||
if (parent.transitionCoordinator != nil) {
|
||||
// Wait until the transition is finished before presenting SafariVC to avoid a blank screen.
|
||||
[parent.transitionCoordinator animateAlongsideTransition:NULL completion:^(id<UIViewControllerTransitionCoordinatorContext> context) {
|
||||
// Note SFVC init must occur inside block to avoid blank screen.
|
||||
_safariViewController = [[SFSafariViewControllerClass alloc] initWithURL:url];
|
||||
[_safariViewController performSelector:@selector(setDelegate:) withObject:self];
|
||||
[container displayChildController:_safariViewController];
|
||||
[parent presentViewController:container animated:YES completion:nil];
|
||||
}];
|
||||
} else {
|
||||
_safariViewController = [[SFSafariViewControllerClass alloc] initWithURL:url];
|
||||
[_safariViewController performSelector:@selector(setDelegate:) withObject:self];
|
||||
[container displayChildController:_safariViewController];
|
||||
[parent presentViewController:container animated:YES completion:nil];
|
||||
}
|
||||
|
||||
// Assuming Safari View Controller always opens
|
||||
if (handler) {
|
||||
handler(YES);
|
||||
}
|
||||
} else {
|
||||
[self openURL:url sender:sender handler:handler];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark -- SFSafariViewControllerDelegate
|
||||
|
||||
// This means the user tapped "Done" which we should treat as a cancellation.
|
||||
- (void)safariViewControllerDidFinish:(UIViewController *)safariViewController
|
||||
{
|
||||
if (_pendingURLOpen) {
|
||||
id<FBSDKURLOpening> pendingURLOpen = _pendingURLOpen;
|
||||
|
||||
_pendingURLOpen = nil;
|
||||
|
||||
[pendingURLOpen application:nil
|
||||
openURL:nil
|
||||
sourceApplication:nil
|
||||
annotation:nil];
|
||||
|
||||
}
|
||||
[self _cancelBridgeRequest];
|
||||
_safariViewController = nil;
|
||||
}
|
||||
|
||||
#pragma mark -- FBSDKContainerViewControllerDelegate
|
||||
|
||||
- (void)viewControllerDidDisappear:(FBSDKContainerViewController *)viewController animated:(BOOL)animated
|
||||
{
|
||||
if (_safariViewController) {
|
||||
[FBSDKLogger singleShotLogEntry:FBSDKLoggingBehaviorDeveloperErrors
|
||||
logEntry:@"**ERROR**:\n The SFSafariViewController's parent view controller was dismissed.\n"
|
||||
"This can happen if you are triggering login from a UIAlertController. Instead, make sure your top most view "
|
||||
"controller will not be prematurely dismissed."];
|
||||
[self safariViewControllerDidFinish:_safariViewController];
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#pragma mark - Helper Methods
|
||||
|
||||
- (void)_logIfAppLinkEvent:(NSURL *)url
|
||||
{
|
||||
if (!url) {
|
||||
return;
|
||||
}
|
||||
NSDictionary *params = [FBSDKUtility dictionaryWithQueryString:url.query];
|
||||
NSString *applinkDataString = params[@"al_applink_data"];
|
||||
if (!applinkDataString) {
|
||||
return;
|
||||
}
|
||||
|
||||
NSDictionary * applinkData = [FBSDKInternalUtility objectForJSONString:applinkDataString error:NULL];
|
||||
if (!applinkData) {
|
||||
return;
|
||||
}
|
||||
|
||||
NSURL *targetURL = [NSURL URLWithString:applinkData[@"target_url"]];
|
||||
NSMutableDictionary *logData = [[NSMutableDictionary alloc] init];
|
||||
[FBSDKInternalUtility dictionary:logData setObject:[targetURL absoluteString] forKey:@"targetURL"];
|
||||
[FBSDKInternalUtility dictionary:logData setObject:[targetURL host] forKey:@"targetURLHost"];
|
||||
|
||||
NSDictionary *refererData = applinkData[@"referer_data"];
|
||||
if (refererData) {
|
||||
[FBSDKInternalUtility dictionary:logData setObject:refererData[@"target_url"] forKey:@"referralTargetURL"];
|
||||
[FBSDKInternalUtility dictionary:logData setObject:refererData[@"url"] forKey:@"referralURL"];
|
||||
[FBSDKInternalUtility dictionary:logData setObject:refererData[@"app_name"] forKey:@"referralAppName"];
|
||||
}
|
||||
[FBSDKInternalUtility dictionary:logData setObject:[url absoluteString] forKey:@"inputURL"];
|
||||
[FBSDKInternalUtility dictionary:logData setObject:[url scheme] forKey:@"inputURLScheme"];
|
||||
|
||||
[FBSDKAppEvents logImplicitEvent:FBSDKAppLinkInboundEvent
|
||||
valueToSum:nil
|
||||
parameters:logData
|
||||
accessToken:nil];
|
||||
}
|
||||
|
||||
#pragma mark -- (non-tvos)
|
||||
#if !TARGET_OS_TV
|
||||
- (BOOL)_handleBridgeAPIResponseURL:(NSURL *)responseURL sourceApplication:(NSString *)sourceApplication
|
||||
{
|
||||
FBSDKBridgeAPIRequest *request = _pendingRequest;
|
||||
FBSDKBridgeAPICallbackBlock completionBlock = _pendingRequestCompletionBlock;
|
||||
_pendingRequest = nil;
|
||||
_pendingRequestCompletionBlock = NULL;
|
||||
if (![responseURL.scheme isEqualToString:[FBSDKInternalUtility appURLScheme]]) {
|
||||
return NO;
|
||||
}
|
||||
if (![responseURL.host isEqualToString:@"bridge"]) {
|
||||
return NO;
|
||||
}
|
||||
if (!request) {
|
||||
return NO;
|
||||
}
|
||||
if (!completionBlock) {
|
||||
return YES;
|
||||
}
|
||||
NSError *error;
|
||||
FBSDKBridgeAPIResponse *response = [FBSDKBridgeAPIResponse bridgeAPIResponseWithRequest:request
|
||||
responseURL:responseURL
|
||||
sourceApplication:sourceApplication
|
||||
error:&error];
|
||||
if (response) {
|
||||
completionBlock(response);
|
||||
return YES;
|
||||
} else if (error) {
|
||||
completionBlock([FBSDKBridgeAPIResponse bridgeAPIResponseWithRequest:request error:error]);
|
||||
return YES;
|
||||
} else {
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)_cancelBridgeRequest
|
||||
{
|
||||
if (_pendingRequest && _pendingRequestCompletionBlock) {
|
||||
_pendingRequestCompletionBlock([FBSDKBridgeAPIResponse bridgeAPIResponseCancelledWithRequest:_pendingRequest]);
|
||||
}
|
||||
_pendingRequest = nil;
|
||||
_pendingRequestCompletionBlock = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,26 @@
|
||||
// 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 <UIKit/UIKit.h>
|
||||
|
||||
/*!
|
||||
@abstract A base class for common SDK buttons.
|
||||
*/
|
||||
@interface FBSDKButton : UIButton
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,457 @@
|
||||
// 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 "FBSDKButton.h"
|
||||
#import "FBSDKButton+Subclass.h"
|
||||
|
||||
#import "FBSDKAccessToken.h"
|
||||
#import "FBSDKAppEvents+Internal.h"
|
||||
#import "FBSDKAppEvents.h"
|
||||
#import "FBSDKApplicationDelegate+Internal.h"
|
||||
#import "FBSDKLogo.h"
|
||||
#import "FBSDKMath.h"
|
||||
#import "FBSDKUIUtility.h"
|
||||
#import "FBSDKViewImpressionTracker.h"
|
||||
|
||||
#define HEIGHT_TO_FONT_SIZE 0.47
|
||||
#define HEIGHT_TO_MARGIN 0.27
|
||||
#define HEIGHT_TO_PADDING 0.23
|
||||
#define HEIGHT_TO_TEXT_PADDING_CORRECTION 0.08
|
||||
|
||||
@implementation FBSDKButton
|
||||
{
|
||||
BOOL _skipIntrinsicContentSizing;
|
||||
BOOL _isExplicitlyDisabled;
|
||||
}
|
||||
|
||||
#pragma mark - Object Lifecycle
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame
|
||||
{
|
||||
if ((self = [super initWithFrame:frame])) {
|
||||
_skipIntrinsicContentSizing = YES;
|
||||
[self configureButton];
|
||||
_skipIntrinsicContentSizing = NO;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)awakeFromNib
|
||||
{
|
||||
[super awakeFromNib];
|
||||
_skipIntrinsicContentSizing = YES;
|
||||
[self configureButton];
|
||||
_skipIntrinsicContentSizing = NO;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||
}
|
||||
|
||||
#pragma mark - Properties
|
||||
|
||||
- (void)setEnabled:(BOOL)enabled
|
||||
{
|
||||
_isExplicitlyDisabled = !enabled;
|
||||
[self checkImplicitlyDisabled];
|
||||
}
|
||||
|
||||
#pragma mark - Layout
|
||||
|
||||
- (CGRect)imageRectForContentRect:(CGRect)contentRect
|
||||
{
|
||||
if ([self isHidden] || CGRectIsEmpty(self.bounds)) {
|
||||
return CGRectZero;
|
||||
}
|
||||
CGRect imageRect = UIEdgeInsetsInsetRect(contentRect, self.imageEdgeInsets);
|
||||
CGFloat margin = [self _marginForHeight:[self _heightForContentRect:contentRect]];
|
||||
imageRect = CGRectInset(imageRect, margin, margin);
|
||||
imageRect.size.width = CGRectGetHeight(imageRect);
|
||||
return imageRect;
|
||||
}
|
||||
|
||||
- (CGSize)intrinsicContentSize
|
||||
{
|
||||
if (_skipIntrinsicContentSizing) {
|
||||
return CGSizeZero;
|
||||
}
|
||||
_skipIntrinsicContentSizing = YES;
|
||||
CGSize size = [self sizeThatFits:CGSizeMake(CGFLOAT_MAX, CGFLOAT_MAX)];
|
||||
_skipIntrinsicContentSizing = NO;
|
||||
return size;
|
||||
}
|
||||
|
||||
- (void)layoutSubviews
|
||||
{
|
||||
// automatic impression tracking if the button conforms to FBSDKButtonImpressionTracking
|
||||
if ([self conformsToProtocol:@protocol(FBSDKButtonImpressionTracking)]) {
|
||||
NSString *eventName = [(id<FBSDKButtonImpressionTracking>)self impressionTrackingEventName];
|
||||
NSString *identifier = [(id<FBSDKButtonImpressionTracking>)self impressionTrackingIdentifier];
|
||||
NSDictionary *parameters = [(id<FBSDKButtonImpressionTracking>)self analyticsParameters];
|
||||
if (eventName && identifier) {
|
||||
FBSDKViewImpressionTracker *impressionTracker = [FBSDKViewImpressionTracker impressionTrackerWithEventName:eventName];
|
||||
[impressionTracker logImpressionWithIdentifier:identifier parameters:parameters];
|
||||
}
|
||||
}
|
||||
[super layoutSubviews];
|
||||
}
|
||||
|
||||
- (CGSize)sizeThatFits:(CGSize)size
|
||||
{
|
||||
if ([self isHidden]) {
|
||||
return CGSizeZero;
|
||||
}
|
||||
CGSize normalSize = [self sizeThatFits:size title:[self titleForState:UIControlStateNormal]];
|
||||
CGSize selectedSize = [self sizeThatFits:size title:[self titleForState:UIControlStateSelected]];
|
||||
return CGSizeMake(MAX(normalSize.width, selectedSize.width), MAX(normalSize.height, selectedSize.height));
|
||||
}
|
||||
|
||||
- (void)sizeToFit
|
||||
{
|
||||
CGRect bounds = self.bounds;
|
||||
bounds.size = [self sizeThatFits:CGSizeMake(CGFLOAT_MAX, CGFLOAT_MAX)];
|
||||
self.bounds = bounds;
|
||||
}
|
||||
|
||||
- (CGRect)titleRectForContentRect:(CGRect)contentRect
|
||||
{
|
||||
if ([self isHidden] || CGRectIsEmpty(self.bounds)) {
|
||||
return CGRectZero;
|
||||
}
|
||||
CGRect imageRect = [self imageRectForContentRect:contentRect];
|
||||
CGFloat height = [self _heightForContentRect:contentRect];
|
||||
CGFloat padding = [self _paddingForHeight:height];
|
||||
CGFloat titleX = CGRectGetMaxX(imageRect) + padding;
|
||||
CGRect titleRect = CGRectMake(titleX, 0.0, CGRectGetWidth(contentRect) - titleX, CGRectGetHeight(contentRect));
|
||||
|
||||
UIEdgeInsets titleEdgeInsets = UIEdgeInsetsZero;
|
||||
if (!self.layer.needsLayout) {
|
||||
UILabel *titleLabel = self.titleLabel;
|
||||
if (titleLabel.textAlignment == NSTextAlignmentCenter) {
|
||||
// if the text is centered, we need to adjust the frame for the titleLabel based on the size of the text in order
|
||||
// to keep the text centered in the button without adding extra blank space to the right when unnecessary
|
||||
// 1. the text fits centered within the button without colliding with the image (imagePaddingWidth)
|
||||
// 2. the text would run into the image, so adjust the insets to effectively left align it (textPaddingWidth)
|
||||
CGSize titleSize = FBSDKTextSize(titleLabel.text,
|
||||
titleLabel.font,
|
||||
titleRect.size,
|
||||
titleLabel.lineBreakMode);
|
||||
CGFloat titlePaddingWidth = (CGRectGetWidth(titleRect) - titleSize.width) / 2;
|
||||
CGFloat imagePaddingWidth = titleX / 2;
|
||||
CGFloat inset = MIN(titlePaddingWidth, imagePaddingWidth);
|
||||
titleEdgeInsets.left -= inset;
|
||||
titleEdgeInsets.right += inset;
|
||||
}
|
||||
}
|
||||
return UIEdgeInsetsInsetRect(titleRect, titleEdgeInsets);
|
||||
}
|
||||
|
||||
#pragma mark - Subclass Methods
|
||||
|
||||
- (void)logTapEventWithEventName:(NSString *)eventName parameters:(NSDictionary *)parameters
|
||||
{
|
||||
[FBSDKAppEvents logImplicitEvent:eventName
|
||||
valueToSum:nil
|
||||
parameters:parameters
|
||||
accessToken:[FBSDKAccessToken currentAccessToken]];
|
||||
}
|
||||
|
||||
- (void)checkImplicitlyDisabled
|
||||
{
|
||||
BOOL enabled = !_isExplicitlyDisabled && ![self isImplicitlyDisabled];
|
||||
BOOL currentEnabled = [self isEnabled];
|
||||
[super setEnabled:enabled];
|
||||
if (currentEnabled != enabled) {
|
||||
[self invalidateIntrinsicContentSize];
|
||||
[self setNeedsLayout];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)configureButton
|
||||
{
|
||||
[self configureWithIcon:[[self class] defaultIcon]
|
||||
title:nil
|
||||
backgroundColor:[[self class] defaultBackgroundColor]
|
||||
highlightedColor:[[self class] defaultHighlightedColor]];
|
||||
}
|
||||
|
||||
- (void)configureWithIcon:(FBSDKIcon *)icon
|
||||
title:(NSString *)title
|
||||
backgroundColor:(UIColor *)backgroundColor
|
||||
highlightedColor:(UIColor *)highlightedColor
|
||||
{
|
||||
[self _configureWithIcon:icon
|
||||
title:title
|
||||
backgroundColor:backgroundColor
|
||||
highlightedColor:highlightedColor
|
||||
selectedTitle:nil
|
||||
selectedIcon:nil
|
||||
selectedColor:nil
|
||||
selectedHighlightedColor:nil];
|
||||
}
|
||||
|
||||
- (void)configureWithIcon:(FBSDKIcon *)icon
|
||||
title:(NSString *)title
|
||||
backgroundColor:(UIColor *)backgroundColor
|
||||
highlightedColor:(UIColor *)highlightedColor
|
||||
selectedTitle:(NSString *)selectedTitle
|
||||
selectedIcon:(FBSDKIcon *)selectedIcon
|
||||
selectedColor:(UIColor *)selectedColor
|
||||
selectedHighlightedColor:(UIColor *)selectedHighlightedColor
|
||||
{
|
||||
if (!selectedColor) {
|
||||
selectedColor = [self defaultSelectedColor];
|
||||
}
|
||||
if (!selectedHighlightedColor) {
|
||||
selectedHighlightedColor = highlightedColor;
|
||||
}
|
||||
[self _configureWithIcon:icon
|
||||
title:title
|
||||
backgroundColor:backgroundColor
|
||||
highlightedColor:highlightedColor
|
||||
selectedTitle:selectedTitle
|
||||
selectedIcon:selectedIcon
|
||||
selectedColor:selectedColor
|
||||
selectedHighlightedColor:selectedHighlightedColor];
|
||||
}
|
||||
|
||||
- (UIColor *)defaultBackgroundColor
|
||||
{
|
||||
return [UIColor colorWithRed:65.0/255.0 green:93.0/255.0 blue:174.0/255.0 alpha:1.0];
|
||||
}
|
||||
|
||||
- (UIColor *)defaultDisabledColor
|
||||
{
|
||||
return [UIColor colorWithRed:189.0/255.0 green:193.0/255.0 blue:201.0/255.0 alpha:1.0];
|
||||
}
|
||||
|
||||
- (UIFont *)defaultFont
|
||||
{
|
||||
return [UIFont systemFontOfSize:14];
|
||||
}
|
||||
|
||||
- (UIColor *)defaultHighlightedColor
|
||||
{
|
||||
return [UIColor colorWithRed:47.0/255.0 green:71.0/255.0 blue:122.0/255.0 alpha:1.0];
|
||||
}
|
||||
|
||||
- (FBSDKIcon *)defaultIcon
|
||||
{
|
||||
return [[FBSDKLogo alloc] init];
|
||||
}
|
||||
|
||||
- (UIColor *)defaultSelectedColor
|
||||
{
|
||||
return [UIColor colorWithRed:124.0/255.0 green:143.0/255.0 blue:200.0/255.0 alpha:1.0];
|
||||
}
|
||||
|
||||
- (BOOL)isImplicitlyDisabled
|
||||
{
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (CGSize)sizeThatFits:(CGSize)size title:(NSString *)title
|
||||
{
|
||||
UIFont *font = self.titleLabel.font;
|
||||
CGFloat height = [self _heightForFont:font];
|
||||
|
||||
UIEdgeInsets contentEdgeInsets = self.contentEdgeInsets;
|
||||
|
||||
CGSize constrainedContentSize = FBSDKEdgeInsetsInsetSize(size, contentEdgeInsets);
|
||||
|
||||
CGSize titleSize = FBSDKTextSize(title, font, constrainedContentSize, self.titleLabel.lineBreakMode);
|
||||
|
||||
CGFloat padding = [self _paddingForHeight:height];
|
||||
CGFloat textPaddingCorrection = [self _textPaddingCorrectionForHeight:height];
|
||||
CGSize contentSize = CGSizeMake(height + padding + titleSize.width - textPaddingCorrection, height);
|
||||
return FBSDKEdgeInsetsOutsetSize(contentSize, contentEdgeInsets);
|
||||
}
|
||||
|
||||
#pragma mark - Helper Methods
|
||||
|
||||
- (void)_applicationDidBecomeActiveNotification:(NSNotification *)notification
|
||||
{
|
||||
[self checkImplicitlyDisabled];
|
||||
}
|
||||
|
||||
- (UIImage *)_backgroundImageWithColor:(UIColor *)color cornerRadius:(CGFloat)cornerRadius scale:(CGFloat)scale
|
||||
{
|
||||
CGFloat size = 1.0 + 2 * cornerRadius;
|
||||
UIGraphicsBeginImageContextWithOptions(CGSizeMake(size, size), NO, scale);
|
||||
CGContextRef context = UIGraphicsGetCurrentContext();
|
||||
CGContextSetFillColorWithColor(context, color.CGColor);
|
||||
CGMutablePathRef path = CGPathCreateMutable();
|
||||
CGPathMoveToPoint(path, NULL, cornerRadius + 1.0, 0.0);
|
||||
CGPathAddArcToPoint(path, NULL, size, 0.0, size, cornerRadius, cornerRadius);
|
||||
CGPathAddLineToPoint(path, NULL, size, cornerRadius + 1.0);
|
||||
CGPathAddArcToPoint(path, NULL, size, size, cornerRadius + 1.0, size, cornerRadius);
|
||||
CGPathAddLineToPoint(path, NULL, cornerRadius, size);
|
||||
CGPathAddArcToPoint(path, NULL, 0.0, size, 0.0, cornerRadius + 1.0, cornerRadius);
|
||||
CGPathAddLineToPoint(path, NULL, 0.0, cornerRadius);
|
||||
CGPathAddArcToPoint(path, NULL, 0.0, 0.0, cornerRadius, 0.0, cornerRadius);
|
||||
CGPathCloseSubpath(path);
|
||||
CGContextAddPath(context, path);
|
||||
CGPathRelease(path);
|
||||
CGContextFillPath(context);
|
||||
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
|
||||
UIGraphicsEndImageContext();
|
||||
#if TARGET_OS_TV
|
||||
return [image resizableImageWithCapInsets:UIEdgeInsetsMake(cornerRadius, cornerRadius, cornerRadius, cornerRadius)
|
||||
resizingMode:UIImageResizingModeStretch];
|
||||
#else
|
||||
return [image stretchableImageWithLeftCapWidth:cornerRadius topCapHeight:cornerRadius];
|
||||
#endif
|
||||
}
|
||||
|
||||
- (void)_configureWithIcon:(FBSDKIcon *)icon
|
||||
title:(NSString *)title
|
||||
backgroundColor:(UIColor *)backgroundColor
|
||||
highlightedColor:(UIColor *)highlightedColor
|
||||
selectedTitle:(NSString *)selectedTitle
|
||||
selectedIcon:(FBSDKIcon *)selectedIcon
|
||||
selectedColor:(UIColor *)selectedColor
|
||||
selectedHighlightedColor:(UIColor *)selectedHighlightedColor
|
||||
{
|
||||
[self checkImplicitlyDisabled];
|
||||
|
||||
if (!icon) {
|
||||
icon = [self defaultIcon];
|
||||
}
|
||||
if (!backgroundColor) {
|
||||
backgroundColor = [self defaultBackgroundColor];
|
||||
}
|
||||
if (!highlightedColor) {
|
||||
highlightedColor = [self defaultHighlightedColor];
|
||||
}
|
||||
|
||||
self.adjustsImageWhenDisabled = NO;
|
||||
self.adjustsImageWhenHighlighted = NO;
|
||||
self.contentHorizontalAlignment = UIControlContentHorizontalAlignmentFill;
|
||||
self.contentVerticalAlignment = UIControlContentVerticalAlignmentFill;
|
||||
self.tintColor = [UIColor whiteColor];
|
||||
|
||||
BOOL forceSizeToFit = CGRectIsEmpty(self.bounds);
|
||||
|
||||
CGFloat scale = [UIScreen mainScreen].scale;
|
||||
UIImage *backgroundImage;
|
||||
|
||||
backgroundImage = [self _backgroundImageWithColor:backgroundColor cornerRadius:3.0 scale:scale];
|
||||
[self setBackgroundImage:backgroundImage forState:UIControlStateNormal];
|
||||
#if TARGET_OS_TV
|
||||
[self setBackgroundImage:backgroundImage forState:UIControlStateFocused];
|
||||
#endif
|
||||
|
||||
backgroundImage = [self _backgroundImageWithColor:highlightedColor cornerRadius:3.0 scale:scale];
|
||||
[self setBackgroundImage:backgroundImage forState:UIControlStateHighlighted];
|
||||
|
||||
backgroundImage = [self _backgroundImageWithColor:[self defaultDisabledColor] cornerRadius:3.0 scale:scale];
|
||||
[self setBackgroundImage:backgroundImage forState:UIControlStateDisabled];
|
||||
|
||||
if (selectedColor) {
|
||||
backgroundImage = [self _backgroundImageWithColor:selectedColor cornerRadius:3.0 scale:scale];
|
||||
[self setBackgroundImage:backgroundImage forState:UIControlStateSelected];
|
||||
}
|
||||
|
||||
if (selectedHighlightedColor) {
|
||||
backgroundImage = [self _backgroundImageWithColor:selectedHighlightedColor cornerRadius:3.0 scale:scale];
|
||||
[self setBackgroundImage:backgroundImage forState:UIControlStateSelected | UIControlStateHighlighted];
|
||||
#if TARGET_OS_TV
|
||||
[self setBackgroundImage:backgroundImage forState:UIControlStateSelected | UIControlStateFocused];
|
||||
#endif
|
||||
}
|
||||
|
||||
[self setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
|
||||
|
||||
[self setTitle:title forState:UIControlStateNormal];
|
||||
#if TARGET_OS_TV
|
||||
[self setTitle:title forState:UIControlStateFocused];
|
||||
#endif
|
||||
if (selectedTitle) {
|
||||
[self setTitle:selectedTitle forState:UIControlStateSelected];
|
||||
[self setTitle:selectedTitle forState:UIControlStateSelected | UIControlStateHighlighted];
|
||||
#if TARGET_OS_TV
|
||||
[self setTitle:selectedTitle forState:UIControlStateSelected | UIControlStateFocused];
|
||||
#endif
|
||||
}
|
||||
|
||||
UILabel *titleLabel = self.titleLabel;
|
||||
titleLabel.lineBreakMode = NSLineBreakByClipping;
|
||||
UIFont *font = [self defaultFont];
|
||||
titleLabel.font = font;
|
||||
|
||||
CGSize imageSize = CGSizeMake(font.pointSize, font.pointSize);
|
||||
UIImage *image = [icon imageWithSize:imageSize];
|
||||
image = [image resizableImageWithCapInsets:UIEdgeInsetsZero resizingMode:UIImageResizingModeStretch];
|
||||
[self setImage:image forState:UIControlStateNormal];
|
||||
#if TARGET_OS_TV
|
||||
[self setImage:image forState:UIControlStateFocused];
|
||||
#endif
|
||||
|
||||
if (selectedIcon) {
|
||||
UIImage *selectedImage = [selectedIcon imageWithSize:imageSize];
|
||||
selectedImage = [selectedImage resizableImageWithCapInsets:UIEdgeInsetsZero
|
||||
resizingMode:UIImageResizingModeStretch];
|
||||
[self setImage:selectedImage forState:UIControlStateSelected];
|
||||
[self setImage:selectedImage forState:UIControlStateSelected | UIControlStateHighlighted];
|
||||
#if TARGET_OS_TV
|
||||
[self setImage:selectedImage forState:UIControlStateSelected | UIControlStateFocused];
|
||||
#endif
|
||||
}
|
||||
|
||||
if (forceSizeToFit) {
|
||||
[self sizeToFit];
|
||||
}
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(_applicationDidBecomeActiveNotification:)
|
||||
name:FBSDKApplicationDidBecomeActiveNotification
|
||||
object:[FBSDKApplicationDelegate sharedInstance]];
|
||||
}
|
||||
|
||||
- (CGFloat)_fontSizeForHeight:(CGFloat)height
|
||||
{
|
||||
return floorf(height * HEIGHT_TO_FONT_SIZE);
|
||||
}
|
||||
|
||||
- (CGFloat)_heightForContentRect:(CGRect)contentRect
|
||||
{
|
||||
UIEdgeInsets contentEdgeInsets = self.contentEdgeInsets;
|
||||
return contentEdgeInsets.top + CGRectGetHeight(contentRect) + contentEdgeInsets.bottom;
|
||||
}
|
||||
|
||||
- (CGFloat)_heightForFont:(UIFont *)font
|
||||
{
|
||||
return floorf(font.pointSize / (1 - 2 * HEIGHT_TO_MARGIN));
|
||||
}
|
||||
|
||||
- (CGFloat)_marginForHeight:(CGFloat)height
|
||||
{
|
||||
return floorf(height * HEIGHT_TO_MARGIN);
|
||||
}
|
||||
|
||||
- (CGFloat)_paddingForHeight:(CGFloat)height
|
||||
{
|
||||
return roundf(height * HEIGHT_TO_PADDING) - [self _textPaddingCorrectionForHeight:height];
|
||||
}
|
||||
|
||||
- (CGFloat)_textPaddingCorrectionForHeight:(CGFloat)height
|
||||
{
|
||||
return floorf(height * HEIGHT_TO_TEXT_PADDING_CORRECTION);
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,210 @@
|
||||
// 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/FBSDKMacros.h>
|
||||
|
||||
/*!
|
||||
@abstract The error domain for all errors from FBSDKCoreKit.
|
||||
@discussion Error codes from the SDK in the range 0-99 are reserved for this domain.
|
||||
*/
|
||||
FBSDK_EXTERN NSString *const FBSDKErrorDomain;
|
||||
|
||||
/*!
|
||||
@typedef NS_ENUM(NSInteger, FBSDKErrorCode)
|
||||
@abstract Error codes for FBSDKErrorDomain.
|
||||
*/
|
||||
typedef NS_ENUM(NSInteger, FBSDKErrorCode)
|
||||
{
|
||||
/*!
|
||||
@abstract Reserved.
|
||||
*/
|
||||
FBSDKReservedErrorCode = 0,
|
||||
|
||||
/*!
|
||||
@abstract The error code for errors from invalid encryption on incoming encryption URLs.
|
||||
*/
|
||||
FBSDKEncryptionErrorCode,
|
||||
|
||||
/*!
|
||||
@abstract The error code for errors from invalid arguments to SDK methods.
|
||||
*/
|
||||
FBSDKInvalidArgumentErrorCode,
|
||||
|
||||
/*!
|
||||
@abstract The error code for unknown errors.
|
||||
*/
|
||||
FBSDKUnknownErrorCode,
|
||||
|
||||
/*!
|
||||
@abstract A request failed due to a network error. Use NSUnderlyingErrorKey to retrieve
|
||||
the error object from the NSURLConnection for more information.
|
||||
*/
|
||||
FBSDKNetworkErrorCode,
|
||||
|
||||
/*!
|
||||
@abstract The error code for errors encounted during an App Events flush.
|
||||
*/
|
||||
FBSDKAppEventsFlushErrorCode,
|
||||
|
||||
/*!
|
||||
@abstract An endpoint that returns a binary response was used with FBSDKGraphRequestConnection.
|
||||
@discussion Endpoints that return image/jpg, etc. should be accessed using NSURLRequest
|
||||
*/
|
||||
FBSDKGraphRequestNonTextMimeTypeReturnedErrorCode,
|
||||
|
||||
/*!
|
||||
@abstract The operation failed because the server returned an unexpected response.
|
||||
@discussion You can get this error if you are not using the most recent SDK, or you are accessing a version of the
|
||||
Graph API incompatible with the current SDK.
|
||||
*/
|
||||
FBSDKGraphRequestProtocolMismatchErrorCode,
|
||||
|
||||
/*!
|
||||
@abstract The Graph API returned an error.
|
||||
@discussion See below for useful userInfo keys (beginning with FBSDKGraphRequestError*)
|
||||
*/
|
||||
FBSDKGraphRequestGraphAPIErrorCode,
|
||||
|
||||
/*!
|
||||
@abstract The specified dialog configuration is not available.
|
||||
@discussion This error may signify that the configuration for the dialogs has not yet been downloaded from the server
|
||||
or that the dialog is unavailable. Subsequent attempts to use the dialog may succeed as the configuration is loaded.
|
||||
*/
|
||||
FBSDKDialogUnavailableErrorCode,
|
||||
|
||||
/*!
|
||||
@abstract Indicates an operation failed because a required access token was not found.
|
||||
*/
|
||||
FBSDKAccessTokenRequiredErrorCode,
|
||||
|
||||
/*!
|
||||
@abstract Indicates an app switch (typically for a dialog) failed because the destination app is out of date.
|
||||
*/
|
||||
FBSDKAppVersionUnsupportedErrorCode,
|
||||
|
||||
/*!
|
||||
@abstract Indicates an app switch to the browser (typically for a dialog) failed.
|
||||
*/
|
||||
FBSDKBrowswerUnavailableErrorCode,
|
||||
};
|
||||
|
||||
/*!
|
||||
@typedef NS_ENUM(NSUInteger, FBSDKGraphRequestErrorCategory)
|
||||
@abstract Describes the category of Facebook error. See `FBSDKGraphRequestErrorCategoryKey`.
|
||||
*/
|
||||
typedef NS_ENUM(NSUInteger, FBSDKGraphRequestErrorCategory)
|
||||
{
|
||||
/*! The default error category that is not known to be recoverable. Check `FBSDKLocalizedErrorDescriptionKey` for a user facing message. */
|
||||
FBSDKGraphRequestErrorCategoryOther = 0,
|
||||
/*! Indicates the error is temporary (such as server throttling). While a recoveryAttempter will be provided with the error instance, the attempt is guaranteed to succeed so you can simply retry the operation if you do not want to present an alert. */
|
||||
FBSDKGraphRequestErrorCategoryTransient = 1,
|
||||
/*! Indicates the error can be recovered (such as requiring a login). A recoveryAttempter will be provided with the error instance that can take UI action. */
|
||||
FBSDKGraphRequestErrorCategoryRecoverable = 2
|
||||
};
|
||||
|
||||
/*
|
||||
@methodgroup error userInfo keys
|
||||
*/
|
||||
|
||||
/*!
|
||||
@abstract The userInfo key for the invalid collection for errors with FBSDKInvalidArgumentErrorCode.
|
||||
@discussion If the invalid argument is a collection, the collection can be found with this key and the individual
|
||||
invalid item can be found with FBSDKErrorArgumentValueKey.
|
||||
*/
|
||||
FBSDK_EXTERN NSString *const FBSDKErrorArgumentCollectionKey;
|
||||
|
||||
/*!
|
||||
@abstract The userInfo key for the invalid argument name for errors with FBSDKInvalidArgumentErrorCode.
|
||||
*/
|
||||
FBSDK_EXTERN NSString *const FBSDKErrorArgumentNameKey;
|
||||
|
||||
/*!
|
||||
@abstract The userInfo key for the invalid argument value for errors with FBSDKInvalidArgumentErrorCode.
|
||||
*/
|
||||
FBSDK_EXTERN NSString *const FBSDKErrorArgumentValueKey;
|
||||
|
||||
/*!
|
||||
@abstract The userInfo key for the message for developers in NSErrors that originate from the SDK.
|
||||
@discussion The developer message will not be localized and is not intended to be presented within the app.
|
||||
*/
|
||||
FBSDK_EXTERN NSString *const FBSDKErrorDeveloperMessageKey;
|
||||
|
||||
/*!
|
||||
@abstract The userInfo key describing a localized description that can be presented to the user.
|
||||
*/
|
||||
FBSDK_EXTERN NSString *const FBSDKErrorLocalizedDescriptionKey;
|
||||
|
||||
/*!
|
||||
@abstract The userInfo key describing a localized title that can be presented to the user, used with `FBSDKLocalizedErrorDescriptionKey`.
|
||||
*/
|
||||
FBSDK_EXTERN NSString *const FBSDKErrorLocalizedTitleKey;
|
||||
|
||||
/*
|
||||
@methodgroup FBSDKGraphRequest error userInfo keys
|
||||
*/
|
||||
|
||||
/*!
|
||||
@abstract The userInfo key describing the error category, for error recovery purposes.
|
||||
@discussion See `FBSDKGraphErrorRecoveryProcessor` and `[FBSDKGraphRequest disableErrorRecovery]`.
|
||||
*/
|
||||
FBSDK_EXTERN NSString *const FBSDKGraphRequestErrorCategoryKey;
|
||||
|
||||
/*
|
||||
@abstract The userInfo key for the Graph API error code.
|
||||
*/
|
||||
FBSDK_EXTERN NSString *const FBSDKGraphRequestErrorGraphErrorCode;
|
||||
|
||||
/*
|
||||
@abstract The userInfo key for the Graph API error subcode.
|
||||
*/
|
||||
FBSDK_EXTERN NSString *const FBSDKGraphRequestErrorGraphErrorSubcode;
|
||||
|
||||
/*
|
||||
@abstract The userInfo key for the HTTP status code.
|
||||
*/
|
||||
FBSDK_EXTERN NSString *const FBSDKGraphRequestErrorHTTPStatusCodeKey;
|
||||
|
||||
/*
|
||||
@abstract The userInfo key for the raw JSON response.
|
||||
*/
|
||||
FBSDK_EXTERN NSString *const FBSDKGraphRequestErrorParsedJSONResponseKey;
|
||||
|
||||
/*!
|
||||
@abstract a formal protocol very similar to the informal protocol NSErrorRecoveryAttempting
|
||||
*/
|
||||
@protocol FBSDKErrorRecoveryAttempting<NSObject>
|
||||
|
||||
/*!
|
||||
@abstract attempt the recovery
|
||||
@param error the error
|
||||
@param recoveryOptionIndex the selected option index
|
||||
@param delegate the delegate
|
||||
@param didRecoverSelector the callback selector, see discussion.
|
||||
@param contextInfo context info to pass back to callback selector, see discussion.
|
||||
@discussion
|
||||
Given that an error alert has been presented document-modally to the user, and the user has chosen one of the error's recovery options, attempt recovery from the error, and send the selected message to the specified delegate. The option index is an index into the error's array of localized recovery options. The method selected by didRecoverSelector must have the same signature as:
|
||||
|
||||
- (void)didPresentErrorWithRecovery:(BOOL)didRecover contextInfo:(void *)contextInfo;
|
||||
|
||||
The value passed for didRecover must be YES if error recovery was completely successful, NO otherwise.
|
||||
*/
|
||||
- (void)attemptRecoveryFromError:(NSError *)error optionIndex:(NSUInteger)recoveryOptionIndex delegate:(id)delegate didRecoverSelector:(SEL)didRecoverSelector contextInfo:(void *)contextInfo;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,34 @@
|
||||
// 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 "FBSDKConstants.h"
|
||||
|
||||
NSString *const FBSDKErrorDomain = @"com.facebook.sdk.core";
|
||||
|
||||
NSString *const FBSDKErrorArgumentCollectionKey = @"com.facebook.sdk:FBSDKErrorArgumentCollectionKey";
|
||||
NSString *const FBSDKErrorArgumentNameKey = @"com.facebook.sdk:FBSDKErrorArgumentNameKey";
|
||||
NSString *const FBSDKErrorArgumentValueKey = @"com.facebook.sdk:FBSDKErrorArgumentValueKey";
|
||||
NSString *const FBSDKErrorDeveloperMessageKey = @"com.facebook.sdk:FBSDKErrorDeveloperMessageKey";
|
||||
NSString *const FBSDKErrorLocalizedDescriptionKey = @"com.facebook.sdk:FBSDKErrorLocalizedDescriptionKey";
|
||||
NSString *const FBSDKErrorLocalizedTitleKey = @"com.facebook.sdk:FBSDKErrorLocalizedErrorTitleKey";
|
||||
|
||||
NSString *const FBSDKGraphRequestErrorCategoryKey = @"com.facebook.sdk:FBSDKGraphRequestErrorCategoryKey";
|
||||
NSString *const FBSDKGraphRequestErrorGraphErrorCode = @"com.facebook.sdk:FBSDKGraphRequestErrorGraphErrorCode";
|
||||
NSString *const FBSDKGraphRequestErrorGraphErrorSubcode = @"com.facebook.sdk:FBSDKGraphRequestErrorGraphErrorSubcode";
|
||||
NSString *const FBSDKGraphRequestErrorHTTPStatusCodeKey = @"com.facebook.sdk:FBSDKGraphRequestErrorHTTPStatusCodeKey";
|
||||
NSString *const FBSDKGraphRequestErrorParsedJSONResponseKey = @"com.facebook.sdk:FBSDKGraphRequestErrorParsedJSONResponseKey";
|
||||
@@ -0,0 +1,33 @@
|
||||
// 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>
|
||||
|
||||
/*!
|
||||
@abstract Extension protocol for NSCopying that adds the copy method, which is implemented on NSObject.
|
||||
@discussion NSObject<NSCopying> implicitly conforms to this protocol.
|
||||
*/
|
||||
@protocol FBSDKCopying <NSCopying, NSObject>
|
||||
|
||||
/*!
|
||||
@abstract Implemented by NSObject as a convenience to copyWithZone:.
|
||||
@return A copy of the receiver.
|
||||
*/
|
||||
- (id)copy;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,45 @@
|
||||
// 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 <UIKit/UIKit.h>
|
||||
|
||||
#import <FBSDKCoreKit/FBSDKAccessToken.h>
|
||||
#import <FBSDKCoreKit/FBSDKAppEvents.h>
|
||||
#import <FBSDKCoreKit/FBSDKApplicationDelegate.h>
|
||||
#import <FBSDKCoreKit/FBSDKButton.h>
|
||||
#import <FBSDKCoreKit/FBSDKConstants.h>
|
||||
#import <FBSDKCoreKit/FBSDKCopying.h>
|
||||
#import <FBSDKCoreKit/FBSDKGraphRequest.h>
|
||||
#import <FBSDKCoreKit/FBSDKGraphRequestConnection.h>
|
||||
#import <FBSDKCoreKit/FBSDKGraphRequestDataAttachment.h>
|
||||
#import <FBSDKCoreKit/FBSDKMacros.h>
|
||||
#import <FBSDKCoreKit/FBSDKSettings.h>
|
||||
#import <FBSDKCoreKit/FBSDKTestUsersManager.h>
|
||||
#import <FBSDKCoreKit/FBSDKUtility.h>
|
||||
|
||||
#if !TARGET_OS_TV
|
||||
#import <FBSDKCoreKit/FBSDKAppLinkResolver.h>
|
||||
#import <FBSDKCoreKit/FBSDKAppLinkUtility.h>
|
||||
#import <FBSDKCoreKit/FBSDKGraphErrorRecoveryProcessor.h>
|
||||
#import <FBSDKCoreKit/FBSDKMutableCopying.h>
|
||||
#import <FBSDKCoreKit/FBSDKProfile.h>
|
||||
#import <FBSDKCoreKit/FBSDKProfilePictureView.h>
|
||||
#endif
|
||||
|
||||
#define FBSDK_VERSION_STRING @"4.10.0"
|
||||
#define FBSDK_TARGET_PLATFORM_VERSION @"v2.5"
|
||||
+97
@@ -0,0 +1,97 @@
|
||||
// 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 "FBSDKConstants.h"
|
||||
|
||||
@class FBSDKGraphErrorRecoveryProcessor;
|
||||
@class FBSDKGraphRequest;
|
||||
|
||||
/*!
|
||||
@abstract Defines a delegate for `FBSDKGraphErrorRecoveryProcessor`.
|
||||
*/
|
||||
@protocol FBSDKGraphErrorRecoveryProcessorDelegate<NSObject>
|
||||
|
||||
/*!
|
||||
@abstract Indicates the error recovery has been attempted.
|
||||
@param processor the processor instance.
|
||||
@param didRecover YES if the recovery was successful.
|
||||
@param error the error that that was attempted to be recovered from.
|
||||
*/
|
||||
- (void)processorDidAttemptRecovery:(FBSDKGraphErrorRecoveryProcessor *)processor didRecover:(BOOL)didRecover error:(NSError *)error;
|
||||
|
||||
@optional
|
||||
/*!
|
||||
@abstract Indicates the processor is about to process the error.
|
||||
@param processor the processor instance.
|
||||
@param error the error is about to be processed.
|
||||
@discussion return NO if the processor should not process the error. For example,
|
||||
if you want to prevent alerts of localized messages but otherwise perform retries and recoveries,
|
||||
you could return NO for errors where userInfo[FBSDKGraphRequestErrorCategoryKey] equal to FBSDKGraphRequestErrorCategoryOther
|
||||
*/
|
||||
- (BOOL)processorWillProcessError:(FBSDKGraphErrorRecoveryProcessor *)processor error:(NSError *)error;
|
||||
|
||||
@end
|
||||
|
||||
/*!
|
||||
@abstract Defines a type that can process Facebook NSErrors with best practices.
|
||||
@discussion Facebook NSErrors can contain FBSDKErrorRecoveryAttempting instances to recover from errors, or
|
||||
localized messages to present to the user. This class will process the instances as follows:
|
||||
|
||||
1. If the error is temporary as indicated by FBSDKGraphRequestErrorCategoryKey, assume the recovery succeeded and
|
||||
notify the delegate.
|
||||
2. If a FBSDKErrorRecoveryAttempting instance is available, display an alert (dispatched to main thread)
|
||||
with the recovery options and call the instance's [ attemptRecoveryFromError:optionIndex:...].
|
||||
3. If a FBSDKErrorRecoveryAttempting is not available, check the userInfo for FBSDKLocalizedErrorDescriptionKey
|
||||
and present that in an alert (dispatched to main thread).
|
||||
|
||||
By default, FBSDKGraphRequests use this type to process errors and retry the request upon a successful
|
||||
recovery.
|
||||
|
||||
Note that Facebook recovery attempters can present UI or even cause app switches (such as to login). Any such
|
||||
work is dispatched to the main thread (therefore your request handlers may then run on the main thread).
|
||||
|
||||
Login recovery requires FBSDKLoginKit. Login will use FBSDKLoginBehaviorNative and will prompt the user
|
||||
for all permissions last granted. If any are declined on the new request, the recovery is not successful but
|
||||
the `[FBSDKAccessToken currentAccessToken]` might still have been updated.
|
||||
.
|
||||
*/
|
||||
@interface FBSDKGraphErrorRecoveryProcessor : NSObject
|
||||
|
||||
/*!
|
||||
@abstract Gets the delegate. Note this is a strong reference, and is nil'ed out after recovery is complete.
|
||||
*/
|
||||
@property (nonatomic, strong, readonly) id<FBSDKGraphErrorRecoveryProcessorDelegate>delegate;
|
||||
|
||||
/*!
|
||||
@abstract Attempts to process the error, return YES if the error can be processed.
|
||||
@param error the error to process.
|
||||
@param request the relateed request that may be reissued.
|
||||
@param delegate the delegate that will be retained until recovery is complete.
|
||||
*/
|
||||
- (BOOL)processError:(NSError *)error request:(FBSDKGraphRequest *)request delegate:(id<FBSDKGraphErrorRecoveryProcessorDelegate>) delegate;
|
||||
|
||||
/*!
|
||||
@abstract The callback for FBSDKErrorRecoveryAttempting
|
||||
@param didRecover if the recovery succeeded
|
||||
@param contextInfo unused
|
||||
*/
|
||||
- (void)didPresentErrorWithRecovery:(BOOL)didRecover contextInfo:(void *)contextInfo;
|
||||
|
||||
@end
|
||||
+159
@@ -0,0 +1,159 @@
|
||||
// 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 "FBSDKGraphErrorRecoveryProcessor.h"
|
||||
|
||||
#import "FBSDKCoreKit+Internal.h"
|
||||
#import "FBSDKErrorRecoveryAttempter.h"
|
||||
|
||||
@interface FBSDKGraphErrorRecoveryProcessor()<UIAlertViewDelegate>
|
||||
{
|
||||
FBSDKErrorRecoveryAttempter *_recoveryAttempter;
|
||||
NSError *_error;
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||
UIAlertView *_alertView;
|
||||
#pragma clang diagnostic pop
|
||||
}
|
||||
|
||||
@property (nonatomic, strong, readwrite) id<FBSDKGraphErrorRecoveryProcessorDelegate>delegate;
|
||||
|
||||
@end
|
||||
|
||||
@implementation FBSDKGraphErrorRecoveryProcessor
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
_alertView.delegate = nil;
|
||||
}
|
||||
|
||||
- (BOOL)processError:(NSError *)error request:(FBSDKGraphRequest *)request delegate:(id<FBSDKGraphErrorRecoveryProcessorDelegate>) delegate
|
||||
{
|
||||
self.delegate = delegate;
|
||||
if ([self.delegate respondsToSelector:@selector(processorWillProcessError:error:)]) {
|
||||
if (![self.delegate processorWillProcessError:self error:error]) {
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
|
||||
FBSDKGraphRequestErrorCategory errorCategory = [error.userInfo[FBSDKGraphRequestErrorCategoryKey] unsignedIntegerValue];
|
||||
switch (errorCategory) {
|
||||
case FBSDKGraphRequestErrorCategoryTransient :
|
||||
[self.delegate processorDidAttemptRecovery:self didRecover:YES error:nil];
|
||||
self.delegate = nil;
|
||||
return YES;
|
||||
case FBSDKGraphRequestErrorCategoryRecoverable :
|
||||
if ([request.tokenString isEqualToString:[FBSDKAccessToken currentAccessToken].tokenString]) {
|
||||
_recoveryAttempter = error.recoveryAttempter;
|
||||
BOOL isLoginRecoveryAttempter = [_recoveryAttempter isKindOfClass:NSClassFromString(@"_FBSDKLoginRecoveryAttempter")];
|
||||
|
||||
// Set up a block to do the typical recovery work so that we can chain it for ios auth special cases.
|
||||
// the block returns YES if recovery UI is started (meaning we wait for the alertviewdelegate to resume control flow).
|
||||
BOOL (^standardRecoveryWork)(void) = ^BOOL{
|
||||
NSArray *recoveryOptionsTitles = error.userInfo[NSLocalizedRecoveryOptionsErrorKey];
|
||||
if (recoveryOptionsTitles.count > 0 && _recoveryAttempter) {
|
||||
NSString *recoverySuggestion = error.userInfo[NSLocalizedRecoverySuggestionErrorKey];
|
||||
_error = error;
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||
_alertView = [[UIAlertView alloc] initWithTitle:nil
|
||||
message:recoverySuggestion
|
||||
delegate:self
|
||||
cancelButtonTitle:nil
|
||||
otherButtonTitles:nil];
|
||||
#pragma clang diagnostic pop
|
||||
for (NSString *option in recoveryOptionsTitles) {
|
||||
[_alertView addButtonWithTitle:option];
|
||||
}
|
||||
[_alertView show];
|
||||
});
|
||||
return YES;
|
||||
}
|
||||
return NO;
|
||||
};
|
||||
|
||||
if ([request.tokenString isEqualToString:[[FBSDKSystemAccountStoreAdapter sharedInstance] accessTokenString]] &&
|
||||
isLoginRecoveryAttempter) {
|
||||
// special system auth case: if user has granted permissions we can simply renew. On a successful
|
||||
// renew, treat this as immediately recovered without the standard alert prompty.
|
||||
// (for example, this can repair expired tokens seamlessly)
|
||||
[[FBSDKSystemAccountStoreAdapter sharedInstance]
|
||||
renewSystemAuthorization:^(ACAccountCredentialRenewResult result, NSError *renewError) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
if (result == ACAccountCredentialRenewResultRenewed) {
|
||||
[self.delegate processorDidAttemptRecovery:self didRecover:YES error:nil];
|
||||
self.delegate = nil;
|
||||
} else if (!standardRecoveryWork()) {
|
||||
[self.delegate processorDidAttemptRecovery:self didRecover:NO error:_error];
|
||||
};
|
||||
});
|
||||
}];
|
||||
// short-circuit YES so that the renew callback resumes the control flow.
|
||||
return YES;
|
||||
}
|
||||
|
||||
return standardRecoveryWork();
|
||||
}
|
||||
return NO;
|
||||
case FBSDKGraphRequestErrorCategoryOther :
|
||||
if ([request.tokenString isEqualToString:[FBSDKAccessToken currentAccessToken].tokenString]) {
|
||||
NSString *message = error.userInfo[FBSDKErrorLocalizedDescriptionKey];
|
||||
NSString *title = error.userInfo[FBSDKErrorLocalizedTitleKey];
|
||||
if (message) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
NSString *localizedOK =
|
||||
NSLocalizedStringWithDefaultValue(@"ErrorRecovery.Alert.OK", @"FacebookSDK", [FBSDKInternalUtility bundleForStrings],
|
||||
@"OK",
|
||||
@"The title of the label to dismiss the alert when presenting user facing error messages");
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||
[[[UIAlertView alloc] initWithTitle:title
|
||||
message:message
|
||||
delegate:nil
|
||||
cancelButtonTitle:localizedOK
|
||||
otherButtonTitles:nil] show];
|
||||
#pragma clang diagnostic pop
|
||||
});
|
||||
}
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
#pragma mark - UIAlertViewDelegate
|
||||
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||
- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex
|
||||
{
|
||||
[_recoveryAttempter attemptRecoveryFromError:_error optionIndex:buttonIndex delegate:self didRecoverSelector:@selector(didPresentErrorWithRecovery:contextInfo:) contextInfo:nil];
|
||||
_alertView.delegate = nil;
|
||||
_alertView = nil;
|
||||
}
|
||||
#pragma clang diagnostic pop
|
||||
|
||||
#pragma mark - FBSDKErrorRecoveryAttempting "delegate"
|
||||
|
||||
- (void)didPresentErrorWithRecovery:(BOOL)didRecover contextInfo:(void *)contextInfo
|
||||
{
|
||||
[self.delegate processorDidAttemptRecovery:self didRecover:didRecover error:_error];
|
||||
self.delegate = nil;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,120 @@
|
||||
// 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/FBSDKGraphRequestConnection.h>
|
||||
|
||||
@class FBSDKAccessToken;
|
||||
|
||||
/*!
|
||||
@abstract Represents a request to the Facebook Graph API.
|
||||
|
||||
@discussion `FBSDKGraphRequest` encapsulates the components of a request (the
|
||||
Graph API path, the parameters, error recovery behavior) and should be
|
||||
used in conjunction with `FBSDKGraphRequestConnection` to issue the request.
|
||||
|
||||
Nearly all Graph APIs require an access token. Unless specified, the
|
||||
`[FBSDKAccessToken currentAccessToken]` is used. Therefore, most requests
|
||||
will require login first (see `FBSDKLoginManager` in FBSDKLoginKit.framework).
|
||||
|
||||
A `- start` method is provided for convenience for single requests.
|
||||
|
||||
By default, FBSDKGraphRequest will attempt to recover any errors returned from
|
||||
Facebook. You can disable this via `disableErrorRecovery:`.
|
||||
@see FBSDKGraphErrorRecoveryProcessor
|
||||
*/
|
||||
@interface FBSDKGraphRequest : NSObject
|
||||
|
||||
/*!
|
||||
@abstract Initializes a new instance that use use `[FBSDKAccessToken currentAccessToken]`.
|
||||
@param graphPath the graph path (e.g., @"me").
|
||||
@param parameters the optional parameters dictionary.
|
||||
*/
|
||||
- (instancetype)initWithGraphPath:(NSString *)graphPath
|
||||
parameters:(NSDictionary *)parameters;
|
||||
|
||||
/*!
|
||||
@abstract Initializes a new instance that use use `[FBSDKAccessToken currentAccessToken]`.
|
||||
@param graphPath the graph path (e.g., @"me").
|
||||
@param parameters the optional parameters dictionary.
|
||||
@param HTTPMethod the optional HTTP method. nil defaults to @"GET".
|
||||
*/
|
||||
- (instancetype)initWithGraphPath:(NSString *)graphPath
|
||||
parameters:(NSDictionary *)parameters
|
||||
HTTPMethod:(NSString *)HTTPMethod;
|
||||
|
||||
/*!
|
||||
@abstract Initializes a new instance.
|
||||
@param graphPath the graph path (e.g., @"me").
|
||||
@param parameters the optional parameters dictionary.
|
||||
@param tokenString the token string to use. Specifying nil will cause no token to be used.
|
||||
@param version the optional Graph API version (e.g., @"v2.0"). nil defaults to FBSDK_TARGET_PLATFORM_VERSION.
|
||||
@param HTTPMethod the optional HTTP method (e.g., @"POST"). nil defaults to @"GET".
|
||||
*/
|
||||
- (instancetype)initWithGraphPath:(NSString *)graphPath
|
||||
parameters:(NSDictionary *)parameters
|
||||
tokenString:(NSString *)tokenString
|
||||
version:(NSString *)version
|
||||
HTTPMethod:(NSString *)HTTPMethod
|
||||
NS_DESIGNATED_INITIALIZER;
|
||||
|
||||
/*!
|
||||
@abstract The request parameters.
|
||||
*/
|
||||
@property (nonatomic, strong, readonly) NSMutableDictionary *parameters;
|
||||
|
||||
/*!
|
||||
@abstract The access token string used by the request.
|
||||
*/
|
||||
@property (nonatomic, copy, readonly) NSString *tokenString;
|
||||
|
||||
/*!
|
||||
@abstract The Graph API endpoint to use for the request, for example "me".
|
||||
*/
|
||||
@property (nonatomic, copy, readonly) NSString *graphPath;
|
||||
|
||||
/*!
|
||||
@abstract The HTTPMethod to use for the request, for example "GET" or "POST".
|
||||
*/
|
||||
@property (nonatomic, copy, readonly) NSString *HTTPMethod;
|
||||
|
||||
/*!
|
||||
@abstract The Graph API version to use (e.g., "v2.0")
|
||||
*/
|
||||
@property (nonatomic, copy, readonly) NSString *version;
|
||||
|
||||
/*!
|
||||
@abstract If set, disables the automatic error recovery mechanism.
|
||||
@param disable whether to disable the automatic error recovery mechanism
|
||||
@discussion By default, non-batched FBSDKGraphRequest instances will automatically try to recover
|
||||
from errors by constructing a `FBSDKGraphErrorRecoveryProcessor` instance that
|
||||
re-issues the request on successful recoveries. The re-issued request will call the same
|
||||
handler as the receiver but may occur with a different `FBSDKGraphRequestConnection` instance.
|
||||
|
||||
This will override [FBSDKSettings setGraphErrorRecoveryDisabled:].
|
||||
*/
|
||||
- (void)setGraphErrorRecoveryDisabled:(BOOL)disable;
|
||||
|
||||
/*!
|
||||
@abstract Starts a connection to the Graph API.
|
||||
@param handler The handler block to call when the request completes.
|
||||
*/
|
||||
- (FBSDKGraphRequestConnection *)startWithCompletionHandler:(FBSDKGraphRequestHandler)handler;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,204 @@
|
||||
// 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 "FBSDKGraphRequest+Internal.h"
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
#import "FBSDKAccessToken.h"
|
||||
#import "FBSDKCoreKit.h"
|
||||
#import "FBSDKGraphRequestConnection.h"
|
||||
#import "FBSDKGraphRequestDataAttachment.h"
|
||||
#import "FBSDKInternalUtility.h"
|
||||
#import "FBSDKLogger.h"
|
||||
#import "FBSDKSettings+Internal.h"
|
||||
|
||||
// constants
|
||||
static NSString *const kGetHTTPMethod = @"GET";
|
||||
|
||||
@interface FBSDKGraphRequest()
|
||||
@property (nonatomic, assign) FBSDKGraphRequestFlags flags;
|
||||
@end
|
||||
|
||||
@implementation FBSDKGraphRequest
|
||||
|
||||
- (instancetype)init NS_UNAVAILABLE
|
||||
{
|
||||
assert(0);
|
||||
}
|
||||
|
||||
- (instancetype)initWithGraphPath:(NSString *)graphPath
|
||||
parameters:(NSDictionary *)parameters {
|
||||
return [self initWithGraphPath:graphPath
|
||||
parameters:parameters
|
||||
flags:FBSDKGraphRequestFlagNone];
|
||||
}
|
||||
|
||||
- (instancetype)initWithGraphPath:(NSString *)graphPath
|
||||
parameters:(NSDictionary *)parameters
|
||||
HTTPMethod:(NSString *)HTTPMethod {
|
||||
return [self initWithGraphPath:graphPath
|
||||
parameters:parameters
|
||||
tokenString:[FBSDKAccessToken currentAccessToken].tokenString
|
||||
version:nil
|
||||
HTTPMethod:HTTPMethod];
|
||||
}
|
||||
|
||||
- (instancetype)initWithGraphPath:(NSString *)graphPath
|
||||
parameters:(NSDictionary *)parameters
|
||||
flags:(FBSDKGraphRequestFlags)flags {
|
||||
return [self initWithGraphPath:graphPath
|
||||
parameters:parameters
|
||||
tokenString:[FBSDKAccessToken currentAccessToken].tokenString
|
||||
HTTPMethod:nil
|
||||
flags:flags];
|
||||
}
|
||||
|
||||
- (instancetype)initWithGraphPath:(NSString *)graphPath
|
||||
parameters:(NSDictionary *)parameters
|
||||
tokenString:(NSString *)tokenString
|
||||
HTTPMethod:(NSString *)HTTPMethod
|
||||
flags:(FBSDKGraphRequestFlags)flags {
|
||||
if ((self = [self initWithGraphPath:graphPath
|
||||
parameters:parameters
|
||||
tokenString:tokenString
|
||||
version:FBSDK_TARGET_PLATFORM_VERSION
|
||||
HTTPMethod:HTTPMethod])) {
|
||||
self.flags |= flags;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (instancetype)initWithGraphPath:(NSString *)graphPath
|
||||
parameters:(NSDictionary *)parameters
|
||||
tokenString:(NSString *)tokenString
|
||||
version:(NSString *)version
|
||||
HTTPMethod:(NSString *)HTTPMethod {
|
||||
if ((self = [super init])) {
|
||||
_tokenString = [tokenString copy];
|
||||
_version = version ? [version copy] : FBSDK_TARGET_PLATFORM_VERSION;
|
||||
_graphPath = [graphPath copy];
|
||||
_HTTPMethod = HTTPMethod ? [HTTPMethod copy] : kGetHTTPMethod;
|
||||
_parameters = [[NSMutableDictionary alloc] initWithDictionary:parameters];
|
||||
if ([FBSDKSettings isGraphErrorRecoveryDisabled]) {
|
||||
_flags = FBSDKGraphRequestFlagDisableErrorRecovery;
|
||||
}
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (BOOL)isGraphErrorRecoveryDisabled
|
||||
{
|
||||
return (self.flags & FBSDKGraphRequestFlagDisableErrorRecovery);
|
||||
}
|
||||
|
||||
- (void)setGraphErrorRecoveryDisabled:(BOOL)disable
|
||||
{
|
||||
if (disable) {
|
||||
self.flags |= FBSDKGraphRequestFlagDisableErrorRecovery;
|
||||
} else {
|
||||
self.flags &= ~FBSDKGraphRequestFlagDisableErrorRecovery;
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)hasAttachments
|
||||
{
|
||||
__block BOOL hasAttachments = NO;
|
||||
[self.parameters enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
|
||||
if ([FBSDKGraphRequest isAttachment:obj]) {
|
||||
hasAttachments = YES;
|
||||
*stop = YES;
|
||||
}
|
||||
}];
|
||||
return hasAttachments;
|
||||
}
|
||||
|
||||
+ (BOOL)isAttachment:(id)item
|
||||
{
|
||||
return ([item isKindOfClass:[UIImage class]] ||
|
||||
[item isKindOfClass:[NSData class]] ||
|
||||
[item isKindOfClass:[FBSDKGraphRequestDataAttachment class]]);
|
||||
}
|
||||
|
||||
|
||||
+ (NSString *)serializeURL:(NSString *)baseUrl
|
||||
params:(NSDictionary *)params {
|
||||
return [self serializeURL:baseUrl params:params httpMethod:kGetHTTPMethod];
|
||||
}
|
||||
|
||||
+ (NSString *)serializeURL:(NSString *)baseUrl
|
||||
params:(NSDictionary *)params
|
||||
httpMethod:(NSString *)httpMethod {
|
||||
params = [self preprocessParams: params];
|
||||
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||
NSURL *parsedURL = [NSURL URLWithString:[baseUrl stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
|
||||
#pragma clang pop
|
||||
NSString *queryPrefix = parsedURL.query ? @"&" : @"?";
|
||||
|
||||
NSString *query = [FBSDKInternalUtility queryStringWithDictionary:params error:NULL invalidObjectHandler:^id(id object, BOOL *stop) {
|
||||
if ([self isAttachment:object]) {
|
||||
if ([httpMethod isEqualToString:kGetHTTPMethod]) {
|
||||
[FBSDKLogger singleShotLogEntry:FBSDKLoggingBehaviorDeveloperErrors logEntry:@"can not use GET to upload a file"];
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
return object;
|
||||
}];
|
||||
return [NSString stringWithFormat:@"%@%@%@", baseUrl, queryPrefix, query];
|
||||
}
|
||||
|
||||
+ (NSDictionary *)preprocessParams:(NSDictionary *)params
|
||||
{
|
||||
NSString *debugValue = [FBSDKSettings graphAPIDebugParamValue];
|
||||
if (debugValue) {
|
||||
NSMutableDictionary *mutableParams = [NSMutableDictionary dictionaryWithDictionary:params];
|
||||
[mutableParams setObject:debugValue forKey:@"debug"];
|
||||
return mutableParams;
|
||||
}
|
||||
|
||||
return params;
|
||||
}
|
||||
|
||||
- (FBSDKGraphRequestConnection *)startWithCompletionHandler:(FBSDKGraphRequestHandler)handler
|
||||
{
|
||||
FBSDKGraphRequestConnection *connection = [[FBSDKGraphRequestConnection alloc] init];
|
||||
[connection addRequest:self completionHandler:handler];
|
||||
[connection start];
|
||||
return connection;
|
||||
}
|
||||
|
||||
#pragma mark - Debugging helpers
|
||||
|
||||
- (NSString *)description
|
||||
{
|
||||
NSMutableString *result = [NSMutableString stringWithFormat:@"<%@: %p",
|
||||
NSStringFromClass([self class]),
|
||||
self];
|
||||
if (self.graphPath) {
|
||||
[result appendFormat:@", graphPath: %@", self.graphPath];
|
||||
}
|
||||
if (self.HTTPMethod) {
|
||||
[result appendFormat:@", HTTPMethod: %@", self.HTTPMethod];
|
||||
}
|
||||
[result appendFormat:@", parameters: %@>", [self.parameters description]];
|
||||
return result;
|
||||
}
|
||||
|
||||
@end
|
||||
+325
@@ -0,0 +1,325 @@
|
||||
// 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/FBSDKMacros.h>
|
||||
|
||||
@class FBSDKGraphRequest;
|
||||
@class FBSDKGraphRequestConnection;
|
||||
|
||||
/*!
|
||||
@typedef FBSDKGraphRequestHandler
|
||||
|
||||
@abstract
|
||||
A block that is passed to addRequest to register for a callback with the results of that
|
||||
request once the connection completes.
|
||||
|
||||
@discussion
|
||||
Pass a block of this type when calling addRequest. This will be called once
|
||||
the request completes. The call occurs on the UI thread.
|
||||
|
||||
@param connection The `FBSDKGraphRequestConnection` that sent the request.
|
||||
|
||||
@param result The result of the request. This is a translation of
|
||||
JSON data to `NSDictionary` and `NSArray` objects. This
|
||||
is nil if there was an error.
|
||||
|
||||
@param error The `NSError` representing any error that occurred.
|
||||
|
||||
*/
|
||||
typedef void (^FBSDKGraphRequestHandler)(FBSDKGraphRequestConnection *connection,
|
||||
id result,
|
||||
NSError *error);
|
||||
|
||||
/*!
|
||||
@protocol
|
||||
|
||||
@abstract
|
||||
The `FBSDKGraphRequestConnectionDelegate` protocol defines the methods used to receive network
|
||||
activity progress information from a <FBSDKGraphRequestConnection>.
|
||||
*/
|
||||
@protocol FBSDKGraphRequestConnectionDelegate <NSObject>
|
||||
|
||||
@optional
|
||||
|
||||
/*!
|
||||
@method
|
||||
|
||||
@abstract
|
||||
Tells the delegate the request connection will begin loading
|
||||
|
||||
@discussion
|
||||
If the <FBSDKGraphRequestConnection> is created using one of the convenience factory methods prefixed with
|
||||
start, the object returned from the convenience method has already begun loading and this method
|
||||
will not be called when the delegate is set.
|
||||
|
||||
@param connection The request connection that is starting a network request
|
||||
*/
|
||||
- (void)requestConnectionWillBeginLoading:(FBSDKGraphRequestConnection *)connection;
|
||||
|
||||
/*!
|
||||
@method
|
||||
|
||||
@abstract
|
||||
Tells the delegate the request connection finished loading
|
||||
|
||||
@discussion
|
||||
If the request connection completes without a network error occuring then this method is called.
|
||||
Invocation of this method does not indicate success of every <FBSDKGraphRequest> made, only that the
|
||||
request connection has no further activity. Use the error argument passed to the FBSDKGraphRequestHandler
|
||||
block to determine success or failure of each <FBSDKGraphRequest>.
|
||||
|
||||
This method is invoked after the completion handler for each <FBSDKGraphRequest>.
|
||||
|
||||
@param connection The request connection that successfully completed a network request
|
||||
*/
|
||||
- (void)requestConnectionDidFinishLoading:(FBSDKGraphRequestConnection *)connection;
|
||||
|
||||
/*!
|
||||
@method
|
||||
|
||||
@abstract
|
||||
Tells the delegate the request connection failed with an error
|
||||
|
||||
@discussion
|
||||
If the request connection fails with a network error then this method is called. The `error`
|
||||
argument specifies why the network connection failed. The `NSError` object passed to the
|
||||
FBSDKGraphRequestHandler block may contain additional information.
|
||||
|
||||
@param connection The request connection that successfully completed a network request
|
||||
@param error The `NSError` representing the network error that occurred, if any. May be nil
|
||||
in some circumstances. Consult the `NSError` for the <FBSDKGraphRequest> for reliable
|
||||
failure information.
|
||||
*/
|
||||
- (void)requestConnection:(FBSDKGraphRequestConnection *)connection
|
||||
didFailWithError:(NSError *)error;
|
||||
|
||||
/*!
|
||||
@method
|
||||
|
||||
@abstract
|
||||
Tells the delegate how much data has been sent and is planned to send to the remote host
|
||||
|
||||
@discussion
|
||||
The byte count arguments refer to the aggregated <FBSDKGraphRequest> objects, not a particular <FBSDKGraphRequest>.
|
||||
|
||||
Like `NSURLConnection`, the values may change in unexpected ways if data needs to be resent.
|
||||
|
||||
@param connection The request connection transmitting data to a remote host
|
||||
@param bytesWritten The number of bytes sent in the last transmission
|
||||
@param totalBytesWritten The total number of bytes sent to the remote host
|
||||
@param totalBytesExpectedToWrite The total number of bytes expected to send to the remote host
|
||||
*/
|
||||
- (void)requestConnection:(FBSDKGraphRequestConnection *)connection
|
||||
didSendBodyData:(NSInteger)bytesWritten
|
||||
totalBytesWritten:(NSInteger)totalBytesWritten
|
||||
totalBytesExpectedToWrite:(NSInteger)totalBytesExpectedToWrite;
|
||||
|
||||
@end
|
||||
|
||||
/*!
|
||||
@class FBSDKGraphRequestConnection
|
||||
|
||||
@abstract
|
||||
The `FBSDKGraphRequestConnection` represents a single connection to Facebook to service a request.
|
||||
|
||||
@discussion
|
||||
The request settings are encapsulated in a reusable <FBSDKGraphRequest> object. The
|
||||
`FBSDKGraphRequestConnection` object encapsulates the concerns of a single communication
|
||||
e.g. starting a connection, canceling a connection, or batching requests.
|
||||
|
||||
*/
|
||||
@interface FBSDKGraphRequestConnection : NSObject
|
||||
|
||||
/*!
|
||||
@abstract
|
||||
The delegate object that receives updates.
|
||||
*/
|
||||
@property (nonatomic, assign) id<FBSDKGraphRequestConnectionDelegate> delegate;
|
||||
|
||||
/*!
|
||||
@abstract Gets or sets the timeout interval to wait for a response before giving up.
|
||||
*/
|
||||
@property (nonatomic) NSTimeInterval timeout;
|
||||
|
||||
/*!
|
||||
@abstract
|
||||
The raw response that was returned from the server. (readonly)
|
||||
|
||||
@discussion
|
||||
This property can be used to inspect HTTP headers that were returned from
|
||||
the server.
|
||||
|
||||
The property is nil until the request completes. If there was a response
|
||||
then this property will be non-nil during the FBSDKGraphRequestHandler callback.
|
||||
*/
|
||||
@property (nonatomic, retain, readonly) NSHTTPURLResponse *URLResponse;
|
||||
|
||||
/*!
|
||||
@methodgroup Class methods
|
||||
*/
|
||||
|
||||
/*!
|
||||
@method
|
||||
|
||||
@abstract
|
||||
This method sets the default timeout on all FBSDKGraphRequestConnection instances. Defaults to 60 seconds.
|
||||
|
||||
@param defaultConnectionTimeout The timeout interval.
|
||||
*/
|
||||
+ (void)setDefaultConnectionTimeout:(NSTimeInterval)defaultConnectionTimeout;
|
||||
|
||||
/*!
|
||||
@methodgroup Adding requests
|
||||
*/
|
||||
|
||||
/*!
|
||||
@method
|
||||
|
||||
@abstract
|
||||
This method adds an <FBSDKGraphRequest> object to this connection.
|
||||
|
||||
@param request A request to be included in the round-trip when start is called.
|
||||
@param handler A handler to call back when the round-trip completes or times out.
|
||||
|
||||
@discussion
|
||||
The completion handler is retained until the block is called upon the
|
||||
completion or cancellation of the connection.
|
||||
*/
|
||||
- (void)addRequest:(FBSDKGraphRequest *)request
|
||||
completionHandler:(FBSDKGraphRequestHandler)handler;
|
||||
|
||||
/*!
|
||||
@method
|
||||
|
||||
@abstract
|
||||
This method adds an <FBSDKGraphRequest> object to this connection.
|
||||
|
||||
@param request A request to be included in the round-trip when start is called.
|
||||
|
||||
@param handler A handler to call back when the round-trip completes or times out.
|
||||
The handler will be invoked on the main thread.
|
||||
|
||||
@param name An optional name for this request. This can be used to feed
|
||||
the results of one request to the input of another <FBSDKGraphRequest> in the same
|
||||
`FBSDKGraphRequestConnection` as described in
|
||||
[Graph API Batch Requests]( https://developers.facebook.com/docs/reference/api/batch/ ).
|
||||
|
||||
@discussion
|
||||
The completion handler is retained until the block is called upon the
|
||||
completion or cancellation of the connection. This request can be named
|
||||
to allow for using the request's response in a subsequent request.
|
||||
*/
|
||||
- (void)addRequest:(FBSDKGraphRequest *)request
|
||||
completionHandler:(FBSDKGraphRequestHandler)handler
|
||||
batchEntryName:(NSString *)name;
|
||||
|
||||
/*!
|
||||
@method
|
||||
|
||||
@abstract
|
||||
This method adds an <FBSDKGraphRequest> object to this connection.
|
||||
|
||||
@param request A request to be included in the round-trip when start is called.
|
||||
|
||||
@param handler A handler to call back when the round-trip completes or times out.
|
||||
|
||||
@param batchParameters The optional dictionary of parameters to include for this request
|
||||
as described in [Graph API Batch Requests]( https://developers.facebook.com/docs/reference/api/batch/ ).
|
||||
Examples include "depends_on", "name", or "omit_response_on_success".
|
||||
|
||||
@discussion
|
||||
The completion handler is retained until the block is called upon the
|
||||
completion or cancellation of the connection. This request can be named
|
||||
to allow for using the request's response in a subsequent request.
|
||||
*/
|
||||
- (void)addRequest:(FBSDKGraphRequest *)request
|
||||
completionHandler:(FBSDKGraphRequestHandler)handler
|
||||
batchParameters:(NSDictionary *)batchParameters;
|
||||
|
||||
/*!
|
||||
@methodgroup Instance methods
|
||||
*/
|
||||
|
||||
/*!
|
||||
@method
|
||||
|
||||
@abstract
|
||||
Signals that a connection should be logically terminated as the
|
||||
application is no longer interested in a response.
|
||||
|
||||
@discussion
|
||||
Synchronously calls any handlers indicating the request was cancelled. Cancel
|
||||
does not guarantee that the request-related processing will cease. It
|
||||
does promise that all handlers will complete before the cancel returns. A call to
|
||||
cancel prior to a start implies a cancellation of all requests associated
|
||||
with the connection.
|
||||
*/
|
||||
- (void)cancel;
|
||||
|
||||
/*!
|
||||
@method
|
||||
|
||||
@abstract
|
||||
This method starts a connection with the server and is capable of handling all of the
|
||||
requests that were added to the connection.
|
||||
|
||||
@discussion By default, a connection is scheduled on the current thread in the default mode when it is created.
|
||||
See `setDelegateQueue:` for other options.
|
||||
|
||||
This method cannot be called twice for an `FBSDKGraphRequestConnection` instance.
|
||||
*/
|
||||
- (void)start;
|
||||
|
||||
/*!
|
||||
@abstract Determines the operation queue that is used to call methods on the connection's delegate.
|
||||
@param queue The operation queue to use when calling delegate methods.
|
||||
@discussion By default, a connection is scheduled on the current thread in the default mode when it is created.
|
||||
You cannot reschedule a connection after it has started.
|
||||
|
||||
This is very similar to `[NSURLConnection setDelegateQueue:]`.
|
||||
*/
|
||||
- (void)setDelegateQueue:(NSOperationQueue *)queue;
|
||||
|
||||
/*!
|
||||
@method
|
||||
|
||||
@abstract
|
||||
Overrides the default version for a batch request
|
||||
|
||||
@discussion
|
||||
The SDK automatically prepends a version part, such as "v2.0" to API paths in order to simplify API versioning
|
||||
for applications. If you want to override the version part while using batch requests on the connection, call
|
||||
this method to set the version for the batch request.
|
||||
|
||||
@param version This is a string in the form @"v2.0" which will be used for the version part of an API path
|
||||
*/
|
||||
- (void)overrideVersionPartWith:(NSString *)version;
|
||||
|
||||
@end
|
||||
|
||||
/*!
|
||||
@abstract The key in the result dictionary for requests to old versions of the Graph API
|
||||
whose response is not a JSON object.
|
||||
|
||||
@discussion When a request returns a non-JSON response (such as a "true" literal), that response
|
||||
will be wrapped into a dictionary using this const as the key. This only applies for very few Graph API
|
||||
prior to v2.1.
|
||||
*/
|
||||
FBSDK_EXTERN NSString *const FBSDKNonJSONResponseProperty;
|
||||
+1031
File diff suppressed because it is too large.
Load diff
+52
@@ -0,0 +1,52 @@
|
||||
// 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>
|
||||
|
||||
/*!
|
||||
@abstract A container class for data attachments so that additional metadata can be provided about the attachment.
|
||||
*/
|
||||
@interface FBSDKGraphRequestDataAttachment : NSObject
|
||||
|
||||
/*!
|
||||
@abstract Initializes the receiver with the attachment data and metadata.
|
||||
@param data The attachment data (retained, not copied)
|
||||
@param filename The filename for the attachment
|
||||
@param contentType The content type for the attachment
|
||||
*/
|
||||
- (instancetype)initWithData:(NSData *)data
|
||||
filename:(NSString *)filename
|
||||
contentType:(NSString *)contentType
|
||||
NS_DESIGNATED_INITIALIZER;
|
||||
|
||||
/*!
|
||||
@abstract The content type for the attachment.
|
||||
*/
|
||||
@property (nonatomic, copy, readonly) NSString *contentType;
|
||||
|
||||
/*!
|
||||
@abstract The attachment data.
|
||||
*/
|
||||
@property (nonatomic, strong, readonly) NSData *data;
|
||||
|
||||
/*!
|
||||
@abstract The filename for the attachment.
|
||||
*/
|
||||
@property (nonatomic, copy, readonly) NSString *filename;
|
||||
|
||||
@end
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
// 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 "FBSDKGraphRequestDataAttachment.h"
|
||||
|
||||
#import "FBSDKMacros.h"
|
||||
|
||||
@implementation FBSDKGraphRequestDataAttachment
|
||||
|
||||
- (instancetype)initWithData:(NSData *)data filename:(NSString *)filename contentType:(NSString *)contentType
|
||||
{
|
||||
if ((self = [super init])) {
|
||||
_data = data;
|
||||
_filename = [filename copy];
|
||||
_contentType = [contentType copy];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (instancetype)init
|
||||
{
|
||||
FBSDK_NOT_DESIGNATED_INITIALIZER(initWithData:filename:contentType:);
|
||||
return [self initWithData:nil filename:nil contentType:nil];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,39 @@
|
||||
// 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>
|
||||
|
||||
#ifdef __cplusplus
|
||||
#define FBSDK_EXTERN extern "C" __attribute__((visibility ("default")))
|
||||
#else
|
||||
#define FBSDK_EXTERN extern __attribute__((visibility ("default")))
|
||||
#endif
|
||||
|
||||
#define FBSDK_STATIC_INLINE static inline
|
||||
|
||||
#define FBSDK_NO_DESIGNATED_INITIALIZER() \
|
||||
@throw [NSException exceptionWithName:NSInvalidArgumentException \
|
||||
reason:[NSString stringWithFormat:@"unrecognized selector sent to instance %p", self] \
|
||||
userInfo:nil]
|
||||
|
||||
#define FBSDK_NOT_DESIGNATED_INITIALIZER(DESIGNATED_INITIALIZER) \
|
||||
@throw [NSException exceptionWithName:NSInvalidArgumentException \
|
||||
reason:[NSString stringWithFormat:@"Please use the designated initializer [%p %@]", \
|
||||
self, \
|
||||
NSStringFromSelector(@selector(DESIGNATED_INITIALIZER))] \
|
||||
userInfo:nil]
|
||||
@@ -0,0 +1,35 @@
|
||||
// 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/FBSDKCopying.h>
|
||||
|
||||
/*!
|
||||
@abstract Extension protocol for NSMutableCopying that adds the mutableCopy method, which is implemented on NSObject.
|
||||
@discussion NSObject<NSCopying, NSMutableCopying> implicitly conforms to this protocol.
|
||||
*/
|
||||
@protocol FBSDKMutableCopying <FBSDKCopying, NSMutableCopying>
|
||||
|
||||
/*!
|
||||
@abstract Implemented by NSObject as a convenience to mutableCopyWithZone:.
|
||||
@return A mutable copy of the receiver.
|
||||
*/
|
||||
- (id)mutableCopy;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,148 @@
|
||||
// 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 "FBSDKMacros.h"
|
||||
#import "FBSDKProfilePictureView.h"
|
||||
|
||||
/*!
|
||||
@abstract Notification indicating that the `currentProfile` has changed.
|
||||
@discussion the userInfo dictionary of the notification will contain keys
|
||||
`FBSDKProfileChangeOldKey` and
|
||||
`FBSDKProfileChangeNewKey`.
|
||||
*/
|
||||
FBSDK_EXTERN NSString *const FBSDKProfileDidChangeNotification;
|
||||
|
||||
/* @abstract key in notification's userInfo object for getting the old profile.
|
||||
@discussion If there was no old profile, the key will not be present.
|
||||
*/
|
||||
FBSDK_EXTERN NSString *const FBSDKProfileChangeOldKey;
|
||||
|
||||
/* @abstract key in notification's userInfo object for getting the new profile.
|
||||
@discussion If there is no new profile, the key will not be present.
|
||||
*/
|
||||
FBSDK_EXTERN NSString *const FBSDKProfileChangeNewKey;
|
||||
|
||||
/*!
|
||||
@abstract Represents an immutable Facebook profile
|
||||
@discussion This class provides a global "currentProfile" instance to more easily
|
||||
add social context to your application. When the profile changes, a notification is
|
||||
posted so that you can update relevant parts of your UI and is persisted to NSUserDefaults.
|
||||
|
||||
Typically, you will want to call `enableUpdatesOnAccessTokenChange:YES` so that
|
||||
it automatically observes changes to the `[FBSDKAccessToken currentAccessToken]`.
|
||||
|
||||
You can use this class to build your own `FBSDKProfilePictureView` or in place of typical requests to "/me".
|
||||
*/
|
||||
@interface FBSDKProfile : NSObject<NSCopying, NSSecureCoding>
|
||||
|
||||
/*!
|
||||
@abstract initializes a new instance.
|
||||
@param userID the user ID
|
||||
@param firstName the user's first name
|
||||
@param middleName the user's middle name
|
||||
@param lastName the user's last name
|
||||
@param name the user's complete name
|
||||
@param linkURL the link for this profile
|
||||
@param refreshDate the optional date this profile was fetched. Defaults to [NSDate date].
|
||||
*/
|
||||
- (instancetype)initWithUserID:(NSString *)userID
|
||||
firstName:(NSString *)firstName
|
||||
middleName:(NSString *)middleName
|
||||
lastName:(NSString *)lastName
|
||||
name:(NSString *)name
|
||||
linkURL:(NSURL *)linkURL
|
||||
refreshDate:(NSDate *)refreshDate NS_DESIGNATED_INITIALIZER;
|
||||
/*!
|
||||
@abstract The user id
|
||||
*/
|
||||
@property (nonatomic, readonly) NSString *userID;
|
||||
/*!
|
||||
@abstract The user's first name
|
||||
*/
|
||||
@property (nonatomic, readonly) NSString *firstName;
|
||||
/*!
|
||||
@abstract The user's middle name
|
||||
*/
|
||||
@property (nonatomic, readonly) NSString *middleName;
|
||||
/*!
|
||||
@abstract The user's last name
|
||||
*/
|
||||
@property (nonatomic, readonly) NSString *lastName;
|
||||
/*!
|
||||
@abstract The user's complete name
|
||||
*/
|
||||
@property (nonatomic, readonly) NSString *name;
|
||||
/*!
|
||||
@abstract A URL to the user's profile.
|
||||
@discussion Consider using Bolts and `FBSDKAppLinkResolver` to resolve this
|
||||
to an app link to link directly to the user's profile in the Facebook app.
|
||||
*/
|
||||
@property (nonatomic, readonly) NSURL *linkURL;
|
||||
|
||||
/*!
|
||||
@abstract The last time the profile data was fetched.
|
||||
*/
|
||||
@property (nonatomic, readonly) NSDate *refreshDate;
|
||||
|
||||
/*!
|
||||
@abstract Gets the current FBSDKProfile instance.
|
||||
*/
|
||||
+ (FBSDKProfile *)currentProfile;
|
||||
|
||||
/*!
|
||||
@abstract Sets the current instance and posts the appropriate notification if the profile parameter is different
|
||||
than the receiver.
|
||||
@param profile the profile to set
|
||||
@discussion This persists the profile to NSUserDefaults.
|
||||
*/
|
||||
+ (void)setCurrentProfile:(FBSDKProfile *)profile;
|
||||
|
||||
/*!
|
||||
@abstract Indicates if `currentProfile` will automatically observe `FBSDKAccessTokenDidChangeNotification` notifications
|
||||
@param enable YES is observing
|
||||
@discussion If observing, this class will issue a graph request for public profile data when the current token's userID
|
||||
differs from the current profile. You can observe `FBSDKProfileDidChangeNotification` for when the profile is updated.
|
||||
|
||||
Note that if `[FBSDKAccessToken currentAccessToken]` is unset, the `currentProfile` instance remains. It's also possible
|
||||
for `currentProfile` to return nil until the data is fetched.
|
||||
*/
|
||||
+ (void)enableUpdatesOnAccessTokenChange:(BOOL)enable;
|
||||
|
||||
/*!
|
||||
@abstract A convenience method for returning a complete `NSURL` for retrieving the user's profile image.
|
||||
@param mode The picture mode
|
||||
@param size The height and width. This will be rounded to integer precision.
|
||||
*/
|
||||
- (NSURL *)imageURLForPictureMode:(FBSDKProfilePictureMode)mode size:(CGSize)size;
|
||||
|
||||
/*!
|
||||
@abstract A convenience method for returning a Graph API path for retrieving the user's profile image.
|
||||
@deprecated use `imageURLForPictureMode:size:` instead
|
||||
@discussion You can pass this to a `FBSDKGraphRequest` instance to download the image.
|
||||
@param mode The picture mode
|
||||
@param size The height and width. This will be rounded to integer precision.
|
||||
*/
|
||||
- (NSString *)imagePathForPictureMode:(FBSDKProfilePictureMode)mode size:(CGSize)size
|
||||
__attribute__ ((deprecated("use imageURLForPictureMode:size: instead")));
|
||||
|
||||
/*!
|
||||
@abstract Returns YES if the profile is equivalent to the receiver.
|
||||
@param profile the profile to compare to.
|
||||
*/
|
||||
- (BOOL)isEqualToProfile:(FBSDKProfile *)profile;
|
||||
@end
|
||||
@@ -0,0 +1,268 @@
|
||||
// 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 "FBSDKProfile+Internal.h"
|
||||
|
||||
#import "FBSDKCoreKit+Internal.h"
|
||||
|
||||
NSString *const FBSDKProfileDidChangeNotification = @"com.facebook.sdk.FBSDKProfile.FBSDKProfileDidChangeNotification";;
|
||||
NSString *const FBSDKProfileChangeOldKey = @"FBSDKProfileOld";
|
||||
NSString *const FBSDKProfileChangeNewKey = @"FBSDKProfileNew";
|
||||
static NSString *const FBSDKProfileUserDefaultsKey = @"com.facebook.sdk.FBSDKProfile.currentProfile";
|
||||
static FBSDKProfile *g_currentProfile;
|
||||
|
||||
#define FBSDKPROFILE_USERID_KEY @"userID"
|
||||
#define FBSDKPROFILE_FIRSTNAME_KEY @"firstName"
|
||||
#define FBSDKPROFILE_MIDDLENAME_KEY @"middleName"
|
||||
#define FBSDKPROFILE_LASTNAME_KEY @"lastName"
|
||||
#define FBSDKPROFILE_NAME_KEY @"name"
|
||||
#define FBSDKPROFILE_LINKURL_KEY @"linkURL"
|
||||
#define FBSDKPROFILE_REFRESHDATE_KEY @"refreshDate"
|
||||
|
||||
// Once a day
|
||||
#define FBSDKPROFILE_STALE_IN_SECONDS (60 * 60 * 24)
|
||||
|
||||
@implementation FBSDKProfile
|
||||
|
||||
- (instancetype)init NS_UNAVAILABLE
|
||||
{
|
||||
assert(0);
|
||||
}
|
||||
|
||||
- (instancetype)initWithUserID:(NSString *)userID
|
||||
firstName:(NSString *)firstName
|
||||
middleName:(NSString *)middleName
|
||||
lastName:(NSString *)lastName
|
||||
name:(NSString *)name
|
||||
linkURL:(NSURL *)linkURL
|
||||
refreshDate:(NSDate *)refreshDate
|
||||
{
|
||||
if ((self = [super init])) {
|
||||
_userID = [userID copy];
|
||||
_firstName = [firstName copy];
|
||||
_middleName = [middleName copy];
|
||||
_lastName = [lastName copy];
|
||||
_name = [name copy];
|
||||
_linkURL = [linkURL copy];
|
||||
_refreshDate = [refreshDate copy] ?: [NSDate date];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
+ (FBSDKProfile *)currentProfile
|
||||
{
|
||||
return g_currentProfile;
|
||||
}
|
||||
|
||||
+ (void)setCurrentProfile:(FBSDKProfile *)profile
|
||||
{
|
||||
if (profile != g_currentProfile && ![profile isEqualToProfile:g_currentProfile]) {
|
||||
[[self class] cacheProfile:profile];
|
||||
NSMutableDictionary *userInfo = [NSMutableDictionary dictionary];
|
||||
|
||||
[FBSDKInternalUtility dictionary:userInfo setObject:profile forKey:FBSDKProfileChangeNewKey];
|
||||
[FBSDKInternalUtility dictionary:userInfo setObject:g_currentProfile forKey:FBSDKProfileChangeOldKey];
|
||||
g_currentProfile = profile;
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:FBSDKProfileDidChangeNotification
|
||||
object:[self class]
|
||||
userInfo:userInfo];
|
||||
}
|
||||
}
|
||||
|
||||
- (NSURL *)imageURLForPictureMode:(FBSDKProfilePictureMode)mode size:(CGSize)size
|
||||
{
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||
NSString *path = [self imagePathForPictureMode:FBSDKProfilePictureModeNormal size:size];
|
||||
#pragma clang diagnostic pop
|
||||
return [FBSDKInternalUtility facebookURLWithHostPrefix:@"graph"
|
||||
path:path
|
||||
queryParameters:nil
|
||||
error:NULL];
|
||||
}
|
||||
|
||||
- (NSString *)imagePathForPictureMode:(FBSDKProfilePictureMode)mode size:(CGSize)size
|
||||
{
|
||||
NSString *type;
|
||||
switch (mode) {
|
||||
case FBSDKProfilePictureModeNormal: type = @"normal"; break;
|
||||
case FBSDKProfilePictureModeSquare: type = @"square"; break;
|
||||
}
|
||||
return [NSString stringWithFormat:@"%@/picture?type=%@&width=%d&height=%d",
|
||||
_userID,
|
||||
type,
|
||||
(int) roundf(size.width),
|
||||
(int) roundf(size.height)];
|
||||
}
|
||||
|
||||
+ (void)enableUpdatesOnAccessTokenChange:(BOOL)enable
|
||||
{
|
||||
if (enable) {
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(observeChangeAccessTokenChange:)
|
||||
name:FBSDKAccessTokenDidChangeNotification
|
||||
object:nil];
|
||||
} else {
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - NSCopying
|
||||
|
||||
- (instancetype)copyWithZone:(NSZone *)zone
|
||||
{
|
||||
//immutable
|
||||
return self;
|
||||
}
|
||||
|
||||
#pragma mark - Equality
|
||||
|
||||
- (NSUInteger)hash
|
||||
{
|
||||
NSUInteger subhashes[] = {
|
||||
[self.userID hash],
|
||||
[self.firstName hash],
|
||||
[self.middleName hash],
|
||||
[self.lastName hash],
|
||||
[self.name hash],
|
||||
[self.linkURL hash],
|
||||
[self.refreshDate hash]
|
||||
};
|
||||
return [FBSDKMath hashWithIntegerArray:subhashes count:sizeof(subhashes) / sizeof(subhashes[0])];
|
||||
}
|
||||
|
||||
- (BOOL)isEqual:(id)object
|
||||
{
|
||||
if (self == object) {
|
||||
return YES;
|
||||
}
|
||||
if (![object isKindOfClass:[FBSDKProfile class]]){
|
||||
return NO;
|
||||
}
|
||||
return [self isEqualToProfile:object];
|
||||
}
|
||||
|
||||
- (BOOL)isEqualToProfile:(FBSDKProfile *)profile
|
||||
{
|
||||
return ([_userID isEqualToString:profile.userID] &&
|
||||
[_firstName isEqualToString:profile.firstName] &&
|
||||
[_middleName isEqualToString:profile.middleName] &&
|
||||
[_lastName isEqualToString:profile.lastName] &&
|
||||
[_name isEqualToString:profile.name] &&
|
||||
[_linkURL isEqual:profile.linkURL] &&
|
||||
[_refreshDate isEqualToDate:profile.refreshDate]);
|
||||
}
|
||||
#pragma mark NSCoding
|
||||
|
||||
+ (BOOL)supportsSecureCoding
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (id)initWithCoder:(NSCoder *)decoder
|
||||
{
|
||||
NSString *userID = [decoder decodeObjectOfClass:[NSString class] forKey:FBSDKPROFILE_USERID_KEY];
|
||||
NSString *firstName = [decoder decodeObjectOfClass:[NSString class] forKey:FBSDKPROFILE_FIRSTNAME_KEY];
|
||||
NSString *middleName = [decoder decodeObjectOfClass:[NSString class] forKey:FBSDKPROFILE_MIDDLENAME_KEY];
|
||||
NSString *lastName = [decoder decodeObjectOfClass:[NSString class] forKey:FBSDKPROFILE_LASTNAME_KEY];
|
||||
NSString *name = [decoder decodeObjectOfClass:[NSString class] forKey:FBSDKPROFILE_NAME_KEY];
|
||||
NSURL *linkURL = [decoder decodeObjectOfClass:[NSURL class] forKey:FBSDKPROFILE_LINKURL_KEY];
|
||||
NSDate *refreshDate = [decoder decodeObjectOfClass:[NSURL class] forKey:FBSDKPROFILE_REFRESHDATE_KEY];
|
||||
return [self initWithUserID:userID
|
||||
firstName:firstName
|
||||
middleName:middleName
|
||||
lastName:lastName
|
||||
name:name
|
||||
linkURL:linkURL
|
||||
refreshDate:refreshDate];
|
||||
}
|
||||
|
||||
- (void)encodeWithCoder:(NSCoder *)encoder
|
||||
{
|
||||
[encoder encodeObject:self.userID forKey:FBSDKPROFILE_USERID_KEY];
|
||||
[encoder encodeObject:self.firstName forKey:FBSDKPROFILE_FIRSTNAME_KEY];
|
||||
[encoder encodeObject:self.middleName forKey:FBSDKPROFILE_MIDDLENAME_KEY];
|
||||
[encoder encodeObject:self.lastName forKey:FBSDKPROFILE_LASTNAME_KEY];
|
||||
[encoder encodeObject:self.name forKey:FBSDKPROFILE_NAME_KEY];
|
||||
[encoder encodeObject:self.linkURL forKey:FBSDKPROFILE_LINKURL_KEY];
|
||||
[encoder encodeObject:self.refreshDate forKey:FBSDKPROFILE_REFRESHDATE_KEY];
|
||||
}
|
||||
|
||||
#pragma mark - Private
|
||||
|
||||
+ (void)observeChangeAccessTokenChange:(NSNotification *)notification
|
||||
{
|
||||
FBSDKAccessToken *token = notification.userInfo[FBSDKAccessTokenChangeNewKey];
|
||||
static FBSDKGraphRequestConnection *executingRequestConnection = nil;
|
||||
|
||||
BOOL isStale = [[NSDate date] timeIntervalSinceDate:g_currentProfile.refreshDate] > FBSDKPROFILE_STALE_IN_SECONDS;
|
||||
if (token &&
|
||||
(isStale || ![g_currentProfile.userID isEqualToString:token.userID])) {
|
||||
FBSDKProfile *expectedCurrentProfile = g_currentProfile;
|
||||
|
||||
NSString *graphPath = @"me?fields=id,first_name,middle_name,last_name,name,link";
|
||||
[executingRequestConnection cancel];
|
||||
FBSDKGraphRequest *request = [[FBSDKGraphRequest alloc] initWithGraphPath:graphPath
|
||||
parameters:nil
|
||||
flags:FBSDKGraphRequestFlagDoNotInvalidateTokenOnError | FBSDKGraphRequestFlagDisableErrorRecovery];
|
||||
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.
|
||||
return;
|
||||
}
|
||||
FBSDKProfile *profile = nil;
|
||||
if (!error) {
|
||||
profile = [[FBSDKProfile alloc] initWithUserID:result[@"id"]
|
||||
firstName:result[@"first_name"]
|
||||
middleName:result[@"middle_name"]
|
||||
lastName:result[@"last_name"]
|
||||
name:result[@"name"]
|
||||
linkURL:[NSURL URLWithString:result[@"link"]]
|
||||
refreshDate:[NSDate date]];
|
||||
}
|
||||
[[self class] setCurrentProfile:profile];
|
||||
}];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation FBSDKProfile(Internal)
|
||||
|
||||
+ (void)cacheProfile:(FBSDKProfile *) profile
|
||||
{
|
||||
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
|
||||
if (profile) {
|
||||
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:profile];
|
||||
[userDefaults setObject:data forKey:FBSDKProfileUserDefaultsKey];
|
||||
} else {
|
||||
[userDefaults removeObjectForKey:FBSDKProfileUserDefaultsKey];
|
||||
}
|
||||
[userDefaults synchronize];
|
||||
}
|
||||
|
||||
+ (FBSDKProfile *)fetchCachedProfile
|
||||
{
|
||||
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
|
||||
NSData *data = [userDefaults objectForKey:FBSDKProfileUserDefaultsKey];
|
||||
return (data != nil)
|
||||
? [NSKeyedUnarchiver unarchiveObjectWithData:data]
|
||||
: nil;
|
||||
}
|
||||
|
||||
@end
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
// 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 <UIKit/UIKit.h>
|
||||
|
||||
/*!
|
||||
@typedef FBSDKProfilePictureMode enum
|
||||
@abstract Defines the aspect ratio mode for the source image of the profile picture.
|
||||
*/
|
||||
typedef NS_ENUM(NSUInteger, FBSDKProfilePictureMode)
|
||||
{
|
||||
/*!
|
||||
@abstract A square cropped version of the image will be included in the view.
|
||||
*/
|
||||
FBSDKProfilePictureModeSquare,
|
||||
/*!
|
||||
@abstract The original picture's aspect ratio will be used for the source image in the view.
|
||||
*/
|
||||
FBSDKProfilePictureModeNormal,
|
||||
};
|
||||
|
||||
/*!
|
||||
@abstract A view to display a profile picture.
|
||||
*/
|
||||
@interface FBSDKProfilePictureView : UIView
|
||||
|
||||
/*!
|
||||
@abstract The mode for the receiver to determine the aspect ratio of the source image.
|
||||
*/
|
||||
@property (nonatomic, assign) FBSDKProfilePictureMode pictureMode;
|
||||
|
||||
/*!
|
||||
@abstract The profile ID to show the picture for.
|
||||
*/
|
||||
@property (nonatomic, copy) NSString *profileID;
|
||||
|
||||
/*!
|
||||
@abstract Explicitly marks the receiver as needing to update the image.
|
||||
@discussion This method is called whenever any properties that affect the source image are modified, but this can also
|
||||
be used to trigger a manual update of the image if it needs to be re-downloaded.
|
||||
*/
|
||||
- (void)setNeedsImageUpdate;
|
||||
|
||||
@end
|
||||
+368
@@ -0,0 +1,368 @@
|
||||
// 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 "FBSDKProfilePictureView.h"
|
||||
|
||||
#import "FBSDKAccessToken.h"
|
||||
#import "FBSDKInternalUtility.h"
|
||||
#import "FBSDKMaleSilhouetteIcon.h"
|
||||
#import "FBSDKMath.h"
|
||||
#import "FBSDKURLConnection.h"
|
||||
#import "FBSDKUtility.h"
|
||||
|
||||
@interface FBSDKProfilePictureViewState : NSObject
|
||||
|
||||
- (instancetype)initWithProfileID:(NSString *)profileID
|
||||
size:(CGSize)size
|
||||
scale:(CGFloat)scale
|
||||
pictureMode:(FBSDKProfilePictureMode)pictureMode
|
||||
imageShouldFit:(BOOL)imageShouldFit;
|
||||
|
||||
@property (nonatomic, assign, readonly) BOOL imageShouldFit;
|
||||
@property (nonatomic, assign, readonly) FBSDKProfilePictureMode pictureMode;
|
||||
@property (nonatomic, copy, readonly) NSString *profileID;
|
||||
@property (nonatomic, assign, readonly) CGFloat scale;
|
||||
@property (nonatomic, assign, readonly) CGSize size;
|
||||
|
||||
- (BOOL)isEqualToState:(FBSDKProfilePictureViewState *)other;
|
||||
- (BOOL)isValidForState:(FBSDKProfilePictureViewState *)other;
|
||||
|
||||
@end
|
||||
|
||||
@implementation FBSDKProfilePictureViewState
|
||||
|
||||
- (instancetype)initWithProfileID:(NSString *)profileID
|
||||
size:(CGSize)size
|
||||
scale:(CGFloat)scale
|
||||
pictureMode:(FBSDKProfilePictureMode)pictureMode
|
||||
imageShouldFit:(BOOL)imageShouldFit
|
||||
{
|
||||
if ((self = [super init])) {
|
||||
_profileID = [profileID copy];
|
||||
_size = size;
|
||||
_scale = scale;
|
||||
_pictureMode = pictureMode;
|
||||
_imageShouldFit = imageShouldFit;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (NSUInteger)hash
|
||||
{
|
||||
NSUInteger subhashes[] = {
|
||||
(NSUInteger)_imageShouldFit,
|
||||
(NSUInteger)_size.width,
|
||||
(NSUInteger)_size.height,
|
||||
(NSUInteger)_scale,
|
||||
(NSUInteger)_pictureMode,
|
||||
[_profileID hash],
|
||||
};
|
||||
return [FBSDKMath hashWithIntegerArray:subhashes count:sizeof(subhashes) / sizeof(subhashes[0])];
|
||||
}
|
||||
|
||||
- (BOOL)isEqual:(id)object
|
||||
{
|
||||
if (![object isKindOfClass:[FBSDKProfilePictureViewState class]]) {
|
||||
return NO;
|
||||
}
|
||||
FBSDKProfilePictureViewState *other = (FBSDKProfilePictureViewState *)object;
|
||||
return [self isEqualToState:other];
|
||||
}
|
||||
|
||||
- (BOOL)isEqualToState:(FBSDKProfilePictureViewState *)other
|
||||
{
|
||||
return ([self isValidForState:other] &&
|
||||
CGSizeEqualToSize(_size, other->_size) &&
|
||||
(_scale == other->_scale));
|
||||
}
|
||||
|
||||
- (BOOL)isValidForState:(FBSDKProfilePictureViewState *)other
|
||||
{
|
||||
return (other != nil &&
|
||||
(_imageShouldFit == other->_imageShouldFit) &&
|
||||
(_pictureMode == other->_pictureMode) &&
|
||||
[FBSDKInternalUtility object:_profileID isEqualToObject:other->_profileID]);
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation FBSDKProfilePictureView
|
||||
{
|
||||
BOOL _hasProfileImage;
|
||||
UIImageView *_imageView;
|
||||
FBSDKProfilePictureViewState *_lastState;
|
||||
BOOL _needsImageUpdate;
|
||||
BOOL _placeholderImageIsValid;
|
||||
}
|
||||
|
||||
#pragma mark - Object Lifecycle
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame
|
||||
{
|
||||
if ((self = [super initWithFrame:frame])) {
|
||||
[self _configureProfilePictureView];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id)initWithCoder:(NSCoder *)decoder
|
||||
{
|
||||
if ((self = [super initWithCoder:decoder])) {
|
||||
[self _configureProfilePictureView];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||
}
|
||||
|
||||
#pragma mark - Properties
|
||||
|
||||
- (void)setBounds:(CGRect)bounds
|
||||
{
|
||||
CGRect currentBounds = self.bounds;
|
||||
if (!CGRectEqualToRect(currentBounds, bounds)) {
|
||||
[super setBounds:bounds];
|
||||
if (!CGSizeEqualToSize(currentBounds.size, bounds.size)) {
|
||||
_placeholderImageIsValid = NO;
|
||||
[self setNeedsImageUpdate];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (UIViewContentMode)contentMode
|
||||
{
|
||||
return _imageView.contentMode;
|
||||
}
|
||||
|
||||
- (void)setContentMode:(UIViewContentMode)contentMode
|
||||
{
|
||||
if (_imageView.contentMode != contentMode) {
|
||||
_imageView.contentMode = contentMode;
|
||||
[super setContentMode:contentMode];
|
||||
[self setNeedsImageUpdate];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setMode:(FBSDKProfilePictureMode)pictureMode
|
||||
{
|
||||
if (_pictureMode != pictureMode) {
|
||||
_pictureMode = pictureMode;
|
||||
[self setNeedsImageUpdate];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setProfileID:(NSString *)profileID
|
||||
{
|
||||
if (![FBSDKInternalUtility object:_profileID isEqualToObject:profileID]) {
|
||||
_profileID = [profileID copy];
|
||||
_placeholderImageIsValid = NO;
|
||||
[self setNeedsImageUpdate];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Public Methods
|
||||
|
||||
- (void)setNeedsImageUpdate
|
||||
{
|
||||
if (!_imageView || CGRectIsEmpty(self.bounds)) {
|
||||
// we can't do anything with an empty view, so just bail out until we have a size
|
||||
return;
|
||||
}
|
||||
|
||||
// ensure that we have an image. do this here so we can draw the placeholder image synchronously if we don't have one
|
||||
if (!_placeholderImageIsValid && !_hasProfileImage) {
|
||||
[self _setPlaceholderImage];
|
||||
}
|
||||
|
||||
// debounce calls to needsImage against the main runloop
|
||||
if (_needsImageUpdate) {
|
||||
return;
|
||||
}
|
||||
_needsImageUpdate = YES;
|
||||
__weak FBSDKProfilePictureView *weakSelf = self;
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[weakSelf _needsImageUpdate];
|
||||
});
|
||||
}
|
||||
|
||||
#pragma mark - Helper Methods
|
||||
|
||||
+ (void)_downloadImageWithState:(FBSDKProfilePictureViewState *)state
|
||||
completionBlock:(void(^)(NSData *data))completionBlock;
|
||||
{
|
||||
NSURL *imageURL = [self _imageURLWithState:state];
|
||||
if (!imageURL) {
|
||||
return;
|
||||
}
|
||||
FBSDKURLConnectionHandler completionHandler = ^(FBSDKURLConnection *connection,
|
||||
NSError *error,
|
||||
NSURLResponse *response,
|
||||
NSData *responseData) {
|
||||
if (!error && [responseData length]) {
|
||||
completionBlock(responseData);
|
||||
}
|
||||
};
|
||||
NSURLRequest *request = [[NSURLRequest alloc] initWithURL:imageURL];
|
||||
[[[FBSDKURLConnection alloc] initWithRequest:request completionHandler:completionHandler] start];
|
||||
}
|
||||
|
||||
+ (NSURL *)_imageURLWithState:(FBSDKProfilePictureViewState *)state
|
||||
{
|
||||
FBSDKAccessToken *accessToken = [FBSDKAccessToken currentAccessToken];
|
||||
if ([state.profileID isEqualToString:@"me"] && !accessToken) {
|
||||
return nil;
|
||||
}
|
||||
NSString *path = [[NSString alloc] initWithFormat:@"/%@/picture", [FBSDKUtility URLEncode:state.profileID]];
|
||||
CGSize size = state.size;
|
||||
NSMutableDictionary *parameters = [[NSMutableDictionary alloc] init];
|
||||
parameters[@"width"] = @(size.width);
|
||||
parameters[@"height"] = @(size.height);
|
||||
[FBSDKInternalUtility dictionary:parameters setObject:accessToken.tokenString forKey:@"access_token"];
|
||||
return [FBSDKInternalUtility facebookURLWithHostPrefix:@"graph" path:path queryParameters:parameters error:NULL];
|
||||
}
|
||||
|
||||
- (void)_accessTokenDidChangeNotification:(NSNotification *)notification
|
||||
{
|
||||
if (![_profileID isEqualToString:@"me"] || !notification.userInfo[FBSDKAccessTokenDidChangeUserID]) {
|
||||
return;
|
||||
}
|
||||
_lastState = nil;
|
||||
[self setNeedsImageUpdate];
|
||||
}
|
||||
|
||||
- (void)_configureProfilePictureView
|
||||
{
|
||||
_imageView = [[UIImageView alloc] initWithFrame:self.bounds];
|
||||
_imageView.autoresizingMask = (UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight);
|
||||
[self addSubview:_imageView];
|
||||
|
||||
_profileID = @"me";
|
||||
self.backgroundColor = [UIColor whiteColor];
|
||||
self.contentMode = UIViewContentModeScaleAspectFit;
|
||||
self.userInteractionEnabled = NO;
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(_accessTokenDidChangeNotification:)
|
||||
name:FBSDKAccessTokenDidChangeNotification
|
||||
object:nil];
|
||||
|
||||
[self setNeedsImageUpdate];
|
||||
}
|
||||
|
||||
- (BOOL)_imageShouldFit
|
||||
{
|
||||
switch (self.contentMode) {
|
||||
case UIViewContentModeBottom:
|
||||
case UIViewContentModeBottomLeft:
|
||||
case UIViewContentModeBottomRight:
|
||||
case UIViewContentModeCenter:
|
||||
case UIViewContentModeLeft:
|
||||
case UIViewContentModeRedraw:
|
||||
case UIViewContentModeRight:
|
||||
case UIViewContentModeScaleAspectFit:
|
||||
case UIViewContentModeTop:
|
||||
case UIViewContentModeTopLeft:
|
||||
case UIViewContentModeTopRight:
|
||||
return YES;
|
||||
case UIViewContentModeScaleAspectFill:
|
||||
case UIViewContentModeScaleToFill:
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
|
||||
- (CGSize)_imageSize:(BOOL)imageShouldFit scale:(CGFloat)scale
|
||||
{
|
||||
// get the image size based on the contentMode and pictureMode
|
||||
CGSize size = self.bounds.size;
|
||||
switch (_pictureMode) {
|
||||
case FBSDKProfilePictureModeSquare:{
|
||||
CGFloat imageSize;
|
||||
if (imageShouldFit) {
|
||||
imageSize = MIN(size.width, size.height);
|
||||
} else {
|
||||
imageSize = MAX(size.width, size.height);
|
||||
}
|
||||
size = CGSizeMake(imageSize, imageSize);
|
||||
break;
|
||||
}
|
||||
case FBSDKProfilePictureModeNormal:
|
||||
// use the bounds size
|
||||
break;
|
||||
}
|
||||
|
||||
// adjust for the screen scale
|
||||
size = CGSizeMake(size.width * scale, size.height * scale);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
- (void)_needsImageUpdate
|
||||
{
|
||||
_needsImageUpdate = NO;
|
||||
|
||||
if (!_profileID) {
|
||||
if (!_placeholderImageIsValid) {
|
||||
[self _setPlaceholderImage];
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// if the current image is no longer representative of the current state, clear the current value out; otherwise,
|
||||
// leave the current value until the new resolution image is downloaded
|
||||
BOOL imageShouldFit = [self _imageShouldFit];
|
||||
UIScreen *screen = self.window.screen ?: [UIScreen mainScreen];
|
||||
CGFloat scale = [screen scale];
|
||||
CGSize imageSize = [self _imageSize:imageShouldFit scale:scale];
|
||||
FBSDKProfilePictureViewState *state = [[FBSDKProfilePictureViewState alloc] initWithProfileID:_profileID
|
||||
size:imageSize
|
||||
scale:scale
|
||||
pictureMode:_pictureMode
|
||||
imageShouldFit:imageShouldFit];
|
||||
if (![_lastState isValidForState:state]) {
|
||||
[self _setPlaceholderImage];
|
||||
}
|
||||
_lastState = state;
|
||||
|
||||
__weak FBSDKProfilePictureView *weakSelf = self;
|
||||
[[self class] _downloadImageWithState:state completionBlock:^(NSData *data) {
|
||||
[weakSelf _updateImageWithData:data state:state];
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)_setPlaceholderImage
|
||||
{
|
||||
UIColor *fillColor = [UIColor colorWithRed:157.0/255.0 green:177.0/255.0 blue:204.0/255.0 alpha:1.0];
|
||||
_imageView.image = [[[FBSDKMaleSilhouetteIcon alloc] initWithColor:fillColor] imageWithSize:_imageView.bounds.size];
|
||||
_placeholderImageIsValid = YES;
|
||||
_hasProfileImage = NO;
|
||||
}
|
||||
|
||||
- (void)_updateImageWithData:(NSData *)data state:(FBSDKProfilePictureViewState *)state
|
||||
{
|
||||
// make sure we haven't updated the state since we began fetching the image
|
||||
if (![state isValidForState:_lastState]) {
|
||||
return;
|
||||
}
|
||||
UIImage *image = [[UIImage alloc] initWithData:data scale:state.scale];
|
||||
_imageView.image = image;
|
||||
_hasProfileImage = YES;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,209 @@
|
||||
// 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 <UIKit/UIKit.h>
|
||||
|
||||
#import <FBSDKCoreKit/FBSDKMacros.h>
|
||||
|
||||
/*
|
||||
* Constants defining logging behavior. Use with <[FBSDKSettings setLoggingBehavior]>.
|
||||
*/
|
||||
|
||||
/*! Include access token in logging. */
|
||||
FBSDK_EXTERN NSString *const FBSDKLoggingBehaviorAccessTokens;
|
||||
|
||||
/*! Log performance characteristics */
|
||||
FBSDK_EXTERN NSString *const FBSDKLoggingBehaviorPerformanceCharacteristics;
|
||||
|
||||
/*! Log FBSDKAppEvents interactions */
|
||||
FBSDK_EXTERN NSString *const FBSDKLoggingBehaviorAppEvents;
|
||||
|
||||
/*! Log Informational occurrences */
|
||||
FBSDK_EXTERN NSString *const FBSDKLoggingBehaviorInformational;
|
||||
|
||||
/*! Log cache errors. */
|
||||
FBSDK_EXTERN NSString *const FBSDKLoggingBehaviorCacheErrors;
|
||||
|
||||
/*! Log errors from SDK UI controls */
|
||||
FBSDK_EXTERN NSString *const FBSDKLoggingBehaviorUIControlErrors;
|
||||
|
||||
/*! Log debug warnings from API response, i.e. when friends fields requested, but user_friends permission isn't granted. */
|
||||
FBSDK_EXTERN NSString *const FBSDKLoggingBehaviorGraphAPIDebugWarning;
|
||||
|
||||
/*! Log warnings from API response, i.e. when requested feature will be deprecated in next version of API.
|
||||
Info is the lowest level of severity, using it will result in logging all previously mentioned levels.
|
||||
*/
|
||||
FBSDK_EXTERN NSString *const FBSDKLoggingBehaviorGraphAPIDebugInfo;
|
||||
|
||||
/*! Log errors from SDK network requests */
|
||||
FBSDK_EXTERN NSString *const FBSDKLoggingBehaviorNetworkRequests;
|
||||
|
||||
/*! Log errors likely to be preventable by the developer. This is in the default set of enabled logging behaviors. */
|
||||
FBSDK_EXTERN NSString *const FBSDKLoggingBehaviorDeveloperErrors;
|
||||
|
||||
@interface FBSDKSettings : NSObject
|
||||
|
||||
/*!
|
||||
@abstract Get the Facebook App ID used by the SDK.
|
||||
@discussion If not explicitly set, the default will be read from the application's plist (FacebookAppID).
|
||||
*/
|
||||
+ (NSString *)appID;
|
||||
|
||||
/*!
|
||||
@abstract Set the Facebook App ID to be used by the SDK.
|
||||
@param appID The Facebook App ID to be used by the SDK.
|
||||
*/
|
||||
+ (void)setAppID:(NSString *)appID;
|
||||
|
||||
/*!
|
||||
@abstract Get the default url scheme suffix used for sessions.
|
||||
@discussion If not explicitly set, the default will be read from the application's plist (FacebookUrlSchemeSuffix).
|
||||
*/
|
||||
+ (NSString *)appURLSchemeSuffix;
|
||||
|
||||
/*!
|
||||
@abstract Set the app url scheme suffix used by the SDK.
|
||||
@param appURLSchemeSuffix The url scheme suffix to be used by the SDK.
|
||||
*/
|
||||
+ (void)setAppURLSchemeSuffix:(NSString *)appURLSchemeSuffix;
|
||||
|
||||
/*!
|
||||
@abstract Retrieve the Client Token that has been set via [FBSDKSettings setClientToken].
|
||||
@discussion If not explicitly set, the default will be read from the application's plist (FacebookClientToken).
|
||||
*/
|
||||
+ (NSString *)clientToken;
|
||||
|
||||
/*!
|
||||
@abstract Sets the Client Token for the Facebook App.
|
||||
@discussion This is needed for certain API calls when made anonymously, without a user-based access token.
|
||||
@param clientToken The Facebook App's "client token", which, for a given appid can be found in the Security
|
||||
section of the Advanced tab of the Facebook App settings found at <https://developers.facebook.com/apps/[your-app-id]>
|
||||
*/
|
||||
+ (void)setClientToken:(NSString *)clientToken;
|
||||
|
||||
/*!
|
||||
@abstract A convenient way to toggle error recovery for all FBSDKGraphRequest instances created after this is set.
|
||||
@param disableGraphErrorRecovery YES or NO.
|
||||
*/
|
||||
+ (void)setGraphErrorRecoveryDisabled:(BOOL)disableGraphErrorRecovery;
|
||||
|
||||
/*!
|
||||
@abstract Get the Facebook Display Name used by the SDK.
|
||||
@discussion If not explicitly set, the default will be read from the application's plist (FacebookDisplayName).
|
||||
*/
|
||||
+ (NSString *)displayName;
|
||||
|
||||
/*!
|
||||
@abstract Set the default Facebook Display Name to be used by the SDK.
|
||||
@discussion This should match the Display Name that has been set for the app with the corresponding Facebook App ID,
|
||||
in the Facebook App Dashboard.
|
||||
@param displayName The Facebook Display Name to be used by the SDK.
|
||||
*/
|
||||
+ (void)setDisplayName:(NSString *)displayName;
|
||||
|
||||
/*!
|
||||
@abstract Get the Facebook domain part.
|
||||
@discussion If not explicitly set, the default will be read from the application's plist (FacebookDomainPart).
|
||||
*/
|
||||
+ (NSString *)facebookDomainPart;
|
||||
|
||||
/*!
|
||||
@abstract Set the subpart of the Facebook domain.
|
||||
@discussion This can be used to change the Facebook domain (e.g. @"beta") so that requests will be sent to
|
||||
graph.beta.facebook.com
|
||||
@param facebookDomainPart The domain part to be inserted into facebook.com.
|
||||
*/
|
||||
+ (void)setFacebookDomainPart:(NSString *)facebookDomainPart;
|
||||
|
||||
/*!
|
||||
@abstract The quality of JPEG images sent to Facebook from the SDK.
|
||||
@discussion If not explicitly set, the default is 0.9.
|
||||
@see [UIImageJPEGRepresentation](https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIKitFunctionReference/#//apple_ref/c/func/UIImageJPEGRepresentation) */
|
||||
+ (CGFloat)JPEGCompressionQuality;
|
||||
|
||||
/*!
|
||||
@abstract Set the quality of JPEG images sent to Facebook from the SDK.
|
||||
@param JPEGCompressionQuality The quality for JPEG images, expressed as a value from 0.0 to 1.0.
|
||||
@see [UIImageJPEGRepresentation](https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIKitFunctionReference/#//apple_ref/c/func/UIImageJPEGRepresentation) */
|
||||
+ (void)setJPEGCompressionQuality:(CGFloat)JPEGCompressionQuality;
|
||||
|
||||
/*!
|
||||
@abstract
|
||||
Gets whether data such as that generated through FBSDKAppEvents and sent to Facebook should be restricted from being used for other than analytics and conversions. Defaults to NO. This value is stored on the device and persists across app launches.
|
||||
*/
|
||||
+ (BOOL)limitEventAndDataUsage;
|
||||
|
||||
/*!
|
||||
@abstract
|
||||
Sets whether data such as that generated through FBSDKAppEvents and sent to Facebook should be restricted from being used for other than analytics and conversions. Defaults to NO. This value is stored on the device and persists across app launches.
|
||||
|
||||
@param limitEventAndDataUsage The desired value.
|
||||
*/
|
||||
+ (void)setLimitEventAndDataUsage:(BOOL)limitEventAndDataUsage;
|
||||
|
||||
/*!
|
||||
@abstract Retrieve the current iOS SDK version.
|
||||
*/
|
||||
+ (NSString *)sdkVersion;
|
||||
|
||||
/*!
|
||||
@abstract Retrieve the current Facebook SDK logging behavior.
|
||||
*/
|
||||
+ (NSSet *)loggingBehavior;
|
||||
|
||||
/*!
|
||||
@abstract Set the current Facebook SDK logging behavior. This should consist of strings defined as
|
||||
constants with FBSDKLoggingBehavior*.
|
||||
|
||||
@param loggingBehavior A set of strings indicating what information should be logged. If nil is provided, the logging
|
||||
behavior is reset to the default set of enabled behaviors. Set to an empty set in order to disable all logging.
|
||||
|
||||
@discussion You can also define this via an array in your app plist with key "FacebookLoggingBehavior" or add and remove individual values via enableLoggingBehavior: or disableLogginBehavior:
|
||||
*/
|
||||
+ (void)setLoggingBehavior:(NSSet *)loggingBehavior;
|
||||
|
||||
/*!
|
||||
@abstract Enable a particular Facebook SDK logging behavior.
|
||||
|
||||
@param loggingBehavior The LoggingBehavior to enable. This should be a string defined as a constant with FBSDKLoggingBehavior*.
|
||||
*/
|
||||
+ (void)enableLoggingBehavior:(NSString *)loggingBehavior;
|
||||
|
||||
/*!
|
||||
@abstract Disable a particular Facebook SDK logging behavior.
|
||||
|
||||
@param loggingBehavior The LoggingBehavior to disable. This should be a string defined as a constant with FBSDKLoggingBehavior*.
|
||||
*/
|
||||
+ (void)disableLoggingBehavior:(NSString *)loggingBehavior;
|
||||
|
||||
/*!
|
||||
@abstract Set the user defaults key used by legacy token caches.
|
||||
|
||||
@param tokenInformationKeyName the key used by legacy token caches.
|
||||
|
||||
@discussion Use this only if you customized FBSessionTokenCachingStrategy in v3.x of
|
||||
the Facebook SDK for iOS.
|
||||
*/
|
||||
+ (void)setLegacyUserDefaultTokenInformationKeyName:(NSString *)tokenInformationKeyName;
|
||||
|
||||
/*!
|
||||
@abstract Get the user defaults key used by legacy token caches.
|
||||
*/
|
||||
+ (NSString *)legacyUserDefaultTokenInformationKeyName;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,223 @@
|
||||
// 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 "FBSDKSettings+Internal.h"
|
||||
|
||||
#import "FBSDKCoreKit.h"
|
||||
|
||||
#define FBSDKSETTINGS_PLIST_CONFIGURATION_SETTING_IMPL(TYPE, PLIST_KEY, GETTER, SETTER, DEFAULT_VALUE) \
|
||||
static TYPE *g_##PLIST_KEY = nil; \
|
||||
+ (TYPE *)GETTER \
|
||||
{ \
|
||||
if (!g_##PLIST_KEY) { \
|
||||
g_##PLIST_KEY = [[[NSBundle mainBundle] objectForInfoDictionaryKey:@#PLIST_KEY] copy] ?: DEFAULT_VALUE; \
|
||||
} \
|
||||
return g_##PLIST_KEY; \
|
||||
} \
|
||||
+ (void)SETTER:(TYPE *)value { \
|
||||
g_##PLIST_KEY = [value copy]; \
|
||||
}
|
||||
|
||||
NSString *const FBSDKLoggingBehaviorAccessTokens = @"include_access_tokens";
|
||||
NSString *const FBSDKLoggingBehaviorPerformanceCharacteristics = @"perf_characteristics";
|
||||
NSString *const FBSDKLoggingBehaviorAppEvents = @"app_events";
|
||||
NSString *const FBSDKLoggingBehaviorInformational = @"informational";
|
||||
NSString *const FBSDKLoggingBehaviorCacheErrors = @"cache_errors";
|
||||
NSString *const FBSDKLoggingBehaviorUIControlErrors = @"ui_control_errors";
|
||||
NSString *const FBSDKLoggingBehaviorDeveloperErrors = @"developer_errors";
|
||||
NSString *const FBSDKLoggingBehaviorGraphAPIDebugWarning = @"graph_api_debug_warning";
|
||||
NSString *const FBSDKLoggingBehaviorGraphAPIDebugInfo = @"graph_api_debug_info";
|
||||
NSString *const FBSDKLoggingBehaviorNetworkRequests = @"network_requests";
|
||||
|
||||
static FBSDKAccessTokenCache *g_tokenCache;
|
||||
static NSMutableSet *g_loggingBehavior;
|
||||
static NSString *g_legacyUserDefaultTokenInformationKeyName = @"FBAccessTokenInformationKey";
|
||||
static NSString *const FBSDKSettingsLimitEventAndDataUsage = @"com.facebook.sdk:FBSDKSettingsLimitEventAndDataUsage";
|
||||
static BOOL g_disableErrorRecovery;
|
||||
static NSString *g_userAgentSuffix;
|
||||
|
||||
@implementation FBSDKSettings
|
||||
|
||||
+ (void)initialize
|
||||
{
|
||||
if (self == [FBSDKSettings class]) {
|
||||
g_tokenCache = [[FBSDKAccessTokenCache alloc] init];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Plist Configuration Settings
|
||||
|
||||
FBSDKSETTINGS_PLIST_CONFIGURATION_SETTING_IMPL(NSString, FacebookAppID, appID, setAppID, nil);
|
||||
FBSDKSETTINGS_PLIST_CONFIGURATION_SETTING_IMPL(NSString, FacebookUrlSchemeSuffix, appURLSchemeSuffix, setAppURLSchemeSuffix, nil);
|
||||
FBSDKSETTINGS_PLIST_CONFIGURATION_SETTING_IMPL(NSString, FacebookClientToken, clientToken, setClientToken, nil);
|
||||
FBSDKSETTINGS_PLIST_CONFIGURATION_SETTING_IMPL(NSString, FacebookDisplayName, displayName, setDisplayName, nil);
|
||||
FBSDKSETTINGS_PLIST_CONFIGURATION_SETTING_IMPL(NSString, FacebookDomainPart, facebookDomainPart, setFacebookDomainPart, nil);
|
||||
FBSDKSETTINGS_PLIST_CONFIGURATION_SETTING_IMPL(NSNumber, FacebookJpegCompressionQuality, _JPEGCompressionQualityNumber, _setJPEGCompressionQualityNumber, @(0.9));
|
||||
|
||||
+ (void)setGraphErrorRecoveryDisabled:(BOOL)disableGraphErrorRecovery {
|
||||
g_disableErrorRecovery = disableGraphErrorRecovery;
|
||||
}
|
||||
|
||||
+ (BOOL)isGraphErrorRecoveryDisabled {
|
||||
return g_disableErrorRecovery;
|
||||
}
|
||||
|
||||
+ (CGFloat)JPEGCompressionQuality
|
||||
{
|
||||
return [[self _JPEGCompressionQualityNumber] floatValue];
|
||||
}
|
||||
|
||||
+ (void)setJPEGCompressionQuality:(CGFloat)JPEGCompressionQuality
|
||||
{
|
||||
[self _setJPEGCompressionQualityNumber:@(JPEGCompressionQuality)];
|
||||
}
|
||||
|
||||
+ (BOOL)limitEventAndDataUsage
|
||||
{
|
||||
NSNumber *storedValue = [[NSUserDefaults standardUserDefaults] objectForKey:FBSDKSettingsLimitEventAndDataUsage];
|
||||
if (storedValue == nil) {
|
||||
return NO;
|
||||
}
|
||||
return storedValue.boolValue;
|
||||
}
|
||||
|
||||
+ (void)setLimitEventAndDataUsage:(BOOL)limitEventAndDataUsage
|
||||
{
|
||||
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
|
||||
[defaults setObject:@(limitEventAndDataUsage) forKey:FBSDKSettingsLimitEventAndDataUsage];
|
||||
[defaults synchronize];
|
||||
}
|
||||
|
||||
+ (NSSet *)loggingBehavior
|
||||
{
|
||||
if (!g_loggingBehavior) {
|
||||
NSArray *bundleLoggingBehaviors = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"FacebookLoggingBehavior"];
|
||||
if (bundleLoggingBehaviors) {
|
||||
g_loggingBehavior = [[NSMutableSet alloc] initWithArray:bundleLoggingBehaviors];
|
||||
} else {
|
||||
// Establish set of default enabled logging behaviors. You can completely disable logging by
|
||||
// specifying an empty array for FacebookLoggingBehavior in your Info.plist.
|
||||
g_loggingBehavior = [[NSMutableSet alloc] initWithObjects:FBSDKLoggingBehaviorDeveloperErrors, nil];
|
||||
}
|
||||
}
|
||||
return [g_loggingBehavior copy];
|
||||
}
|
||||
|
||||
+ (void)setLoggingBehavior:(NSSet *)loggingBehavior
|
||||
{
|
||||
if (![g_loggingBehavior isEqualToSet:loggingBehavior]) {
|
||||
g_loggingBehavior = [loggingBehavior mutableCopy];
|
||||
|
||||
[self updateGraphAPIDebugBehavior];
|
||||
}
|
||||
}
|
||||
|
||||
+ (void)enableLoggingBehavior:(NSString *)loggingBehavior
|
||||
{
|
||||
if (!g_loggingBehavior) {
|
||||
[self loggingBehavior];
|
||||
}
|
||||
[g_loggingBehavior addObject:loggingBehavior];
|
||||
[self updateGraphAPIDebugBehavior];
|
||||
}
|
||||
|
||||
+ (void)disableLoggingBehavior:(NSString *)loggingBehavior
|
||||
{
|
||||
if (!g_loggingBehavior) {
|
||||
[self loggingBehavior];
|
||||
}
|
||||
[g_loggingBehavior removeObject:loggingBehavior];
|
||||
[self updateGraphAPIDebugBehavior];
|
||||
}
|
||||
|
||||
+ (void)setLegacyUserDefaultTokenInformationKeyName:(NSString *)tokenInformationKeyName
|
||||
{
|
||||
if (![g_legacyUserDefaultTokenInformationKeyName isEqualToString:tokenInformationKeyName]) {
|
||||
g_legacyUserDefaultTokenInformationKeyName = tokenInformationKeyName;
|
||||
}
|
||||
}
|
||||
|
||||
+ (NSString *)legacyUserDefaultTokenInformationKeyName
|
||||
{
|
||||
return g_legacyUserDefaultTokenInformationKeyName;
|
||||
}
|
||||
|
||||
#pragma mark - Readonly Configuration Settings
|
||||
|
||||
+ (NSString *)sdkVersion
|
||||
{
|
||||
return FBSDK_VERSION_STRING;
|
||||
}
|
||||
|
||||
#pragma mark - Object Lifecycle
|
||||
|
||||
- (instancetype)init
|
||||
{
|
||||
FBSDK_NO_DESIGNATED_INITIALIZER();
|
||||
return nil;
|
||||
}
|
||||
|
||||
#pragma mark - Internal
|
||||
|
||||
+ (FBSDKAccessTokenCache *)accessTokenCache
|
||||
{
|
||||
return g_tokenCache;
|
||||
}
|
||||
|
||||
- (void)setAccessTokenCache:(FBSDKAccessTokenCache *)cache
|
||||
{
|
||||
if (g_tokenCache != cache) {
|
||||
g_tokenCache = cache;
|
||||
}
|
||||
}
|
||||
|
||||
+ (NSString *)userAgentSuffix
|
||||
{
|
||||
return g_userAgentSuffix;
|
||||
}
|
||||
|
||||
+ (void)setUserAgentSuffix:(NSString *)suffix
|
||||
{
|
||||
if (![g_userAgentSuffix isEqualToString:suffix]) {
|
||||
g_userAgentSuffix = suffix;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Internal - Graph API Debug
|
||||
|
||||
+ (void)updateGraphAPIDebugBehavior
|
||||
{
|
||||
// Enable Warnings everytime Info is enabled
|
||||
if ([g_loggingBehavior containsObject:FBSDKLoggingBehaviorGraphAPIDebugInfo]
|
||||
&& ![g_loggingBehavior containsObject:FBSDKLoggingBehaviorGraphAPIDebugWarning]) {
|
||||
[g_loggingBehavior addObject:FBSDKLoggingBehaviorGraphAPIDebugWarning];
|
||||
}
|
||||
}
|
||||
|
||||
+ (NSString *)graphAPIDebugParamValue
|
||||
{
|
||||
if ([[self loggingBehavior] containsObject:FBSDKLoggingBehaviorGraphAPIDebugInfo]) {
|
||||
return @"info";
|
||||
} else if ([[self loggingBehavior] containsObject:FBSDKLoggingBehaviorGraphAPIDebugWarning]) {
|
||||
return @"warning";
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
@end
|
||||
+102
@@ -0,0 +1,102 @@
|
||||
// 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>
|
||||
|
||||
@class FBSDKAccessToken;
|
||||
|
||||
/*!
|
||||
@typedef
|
||||
|
||||
@abstract Callback block for returning an array of FBSDKAccessToken instances (and possibly `NSNull` instances); or an error.
|
||||
*/
|
||||
typedef void (^FBSDKTestUsersManagerRetrieveTestAccountTokensHandler)(NSArray *tokens, NSError *error) ;
|
||||
|
||||
/*!
|
||||
@typedef
|
||||
|
||||
@abstract Callback block for removing a test user.
|
||||
*/
|
||||
typedef void (^FBSDKTestUsersManagerRemoveTestAccountHandler)(NSError *error) ;
|
||||
|
||||
|
||||
/*!
|
||||
@class FBSDKTestUsersManager
|
||||
@abstract Provides methods for managing test accounts for testing Facebook integration.
|
||||
|
||||
@discussion Facebook allows developers to create test accounts for testing their applications'
|
||||
Facebook integration (see https://developers.facebook.com/docs/test_users/). This class
|
||||
simplifies use of these accounts for writing tests. It is not designed for use in
|
||||
production application code.
|
||||
|
||||
This class will make Graph API calls on behalf of your app to manage test accounts and requires
|
||||
an app id and app secret. You will typically use this class to write unit or integration tests.
|
||||
Make sure you NEVER include your app secret in your production app.
|
||||
*/
|
||||
@interface FBSDKTestUsersManager : NSObject
|
||||
|
||||
/*!
|
||||
@abstract construct or return the shared instance
|
||||
@param appID the Facebook app id
|
||||
@param appSecret the Facebook app secret
|
||||
*/
|
||||
+ (instancetype)sharedInstanceForAppID:(NSString *)appID appSecret:(NSString *)appSecret;
|
||||
|
||||
/*!
|
||||
@abstract retrieve FBSDKAccessToken instances for test accounts with the specific permissions.
|
||||
@param arraysOfPermissions an array of permissions sets, such as @[ [NSSet setWithObject:@"email"], [NSSet setWithObject:@"user_birthday"]]
|
||||
if you needed two test accounts with email and birthday permissions, respectively. You can pass in empty nested sets
|
||||
if you need two arbitrary test accounts. For convenience, passing nil is treated as @[ [NSSet set] ]
|
||||
for fetching a single test user.
|
||||
@param createIfNotFound if YES, new test accounts are created if no test accounts existed that fit the permissions
|
||||
requirement
|
||||
@param handler the callback to invoke which will return an array of `FBAccessTokenData` instances or an `NSError`.
|
||||
If param `createIfNotFound` is NO, the array may contain `[NSNull null]` instances.
|
||||
|
||||
@discussion If you are requesting test accounts with differing number of permissions, try to order
|
||||
`arrayOfPermissionsArrays` so that the most number of permissions come first to minimize creation of new
|
||||
test accounts.
|
||||
*/
|
||||
- (void)requestTestAccountTokensWithArraysOfPermissions:(NSArray *)arraysOfPermissions
|
||||
createIfNotFound:(BOOL)createIfNotFound
|
||||
completionHandler:(FBSDKTestUsersManagerRetrieveTestAccountTokensHandler)handler;
|
||||
|
||||
/*!
|
||||
@abstract add a test account with the specified permissions
|
||||
@param permissions the set of permissions, e.g., [NSSet setWithObjects:@"email", @"user_friends"]
|
||||
@param handler the callback handler
|
||||
*/
|
||||
- (void)addTestAccountWithPermissions:(NSSet *)permissions
|
||||
completionHandler:(FBSDKTestUsersManagerRetrieveTestAccountTokensHandler)handler;
|
||||
|
||||
/*!
|
||||
@abstract remove a test account for the given user id
|
||||
@param userId the user id
|
||||
@param handler the callback handler
|
||||
*/
|
||||
- (void)removeTestAccount:(NSString *)userId completionHandler:(FBSDKTestUsersManagerRemoveTestAccountHandler)handler;
|
||||
|
||||
/*!
|
||||
@abstract Make two test users friends with each other.
|
||||
@param first the token of the first user
|
||||
@param second the token of the second user
|
||||
@param callback the callback handler
|
||||
*/
|
||||
- (void)makeFriendsWithFirst:(FBSDKAccessToken *)first second:(FBSDKAccessToken *)second callback:(void (^)(NSError *))callback;
|
||||
|
||||
@end
|
||||
+329
@@ -0,0 +1,329 @@
|
||||
// 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 "FBSDKTestUsersManager.h"
|
||||
|
||||
#import "FBSDKCoreKit+Internal.h"
|
||||
|
||||
static NSString *const kFBGraphAPITestUsersPathFormat = @"%@/accounts/test-users";
|
||||
static NSString *const kAccountsDictionaryTokenKey = @"access_token";
|
||||
static NSString *const kAccountsDictionaryPermissionsKey = @"permissions";
|
||||
static NSMutableDictionary *gInstancesDictionary;
|
||||
|
||||
@interface FBSDKTestUsersManager()
|
||||
- (instancetype)initWithAppID:(NSString *)appID appSecret:(NSString *)appSecret NS_DESIGNATED_INITIALIZER;
|
||||
@end
|
||||
|
||||
@implementation FBSDKTestUsersManager
|
||||
{
|
||||
NSString *_appID;
|
||||
NSString *_appSecret;
|
||||
// dictionary with format like:
|
||||
// { user_id : { kAccountsDictionaryTokenKey : "token",
|
||||
// kAccountsDictionaryPermissionsKey : [ permissions ] }
|
||||
NSMutableDictionary *_accounts;
|
||||
}
|
||||
|
||||
- (instancetype)initWithAppID:(NSString *)appID appSecret:(NSString *)appSecret {
|
||||
if ((self = [super init])) {
|
||||
_appID = [appID copy];
|
||||
_appSecret = [appSecret copy];
|
||||
_accounts = [NSMutableDictionary dictionary];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (instancetype)init
|
||||
{
|
||||
FBSDK_NOT_DESIGNATED_INITIALIZER(initWithAppID:appSecret:);
|
||||
return [self initWithAppID:nil appSecret:nil];
|
||||
}
|
||||
|
||||
+ (instancetype)sharedInstanceForAppID:(NSString *)appID appSecret:(NSString *)appSecret {
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
gInstancesDictionary = [NSMutableDictionary dictionary];
|
||||
});
|
||||
|
||||
NSString *instanceKey = [NSString stringWithFormat:@"%@|%@", appID, appSecret];
|
||||
if (!gInstancesDictionary[instanceKey]) {
|
||||
gInstancesDictionary[instanceKey] = [[FBSDKTestUsersManager alloc] initWithAppID:appID appSecret:appSecret];
|
||||
}
|
||||
return gInstancesDictionary[instanceKey];
|
||||
}
|
||||
|
||||
- (void)requestTestAccountTokensWithArraysOfPermissions:(NSArray *)arraysOfPermissions
|
||||
createIfNotFound:(BOOL)createIfNotFound
|
||||
completionHandler:(FBSDKTestUsersManagerRetrieveTestAccountTokensHandler)handler {
|
||||
arraysOfPermissions = arraysOfPermissions ?: @[[NSSet set]];
|
||||
|
||||
// wrap work in a block so that we can chain it to after a fetch of existing accounts if we need to.
|
||||
void (^helper)(NSError *) = ^(NSError *error){
|
||||
if (error) {
|
||||
if (handler) {
|
||||
handler(nil, error);
|
||||
}
|
||||
return;
|
||||
}
|
||||
NSMutableArray *tokenDatum = [NSMutableArray arrayWithCapacity:arraysOfPermissions.count];
|
||||
NSMutableSet *collectedUserIds = [NSMutableSet setWithCapacity:arraysOfPermissions.count];
|
||||
__block BOOL canInvokeHandler = YES;
|
||||
__weak id weakSelf = self;
|
||||
[arraysOfPermissions enumerateObjectsUsingBlock:^(NSSet *desiredPermissions, NSUInteger idx, BOOL *stop) {
|
||||
NSArray* userIdAndTokenPair = [self userIdAndTokenOfExistingAccountWithPermissions:desiredPermissions skip:collectedUserIds];
|
||||
if (!userIdAndTokenPair) {
|
||||
if (createIfNotFound) {
|
||||
[self addTestAccountWithPermissions:desiredPermissions
|
||||
completionHandler:^(NSArray *tokens, NSError *addError) {
|
||||
if (addError) {
|
||||
if (handler) {
|
||||
handler(nil, addError);
|
||||
}
|
||||
} else {
|
||||
[weakSelf requestTestAccountTokensWithArraysOfPermissions:arraysOfPermissions
|
||||
createIfNotFound:createIfNotFound
|
||||
completionHandler:handler];
|
||||
}
|
||||
}];
|
||||
// stop the enumeration (ane flag so that callback to addTestAccount* will resolve our handler now).
|
||||
canInvokeHandler = NO;
|
||||
*stop = YES;
|
||||
return;
|
||||
} else {
|
||||
[tokenDatum addObject:[NSNull null]];
|
||||
}
|
||||
} else {
|
||||
NSString *userId = userIdAndTokenPair[0];
|
||||
NSString *tokenString = userIdAndTokenPair[1];
|
||||
[collectedUserIds addObject:userId];
|
||||
[tokenDatum addObject:[self tokenDataForTokenString:tokenString
|
||||
permissions:desiredPermissions
|
||||
userId:userId]];
|
||||
}
|
||||
}];
|
||||
|
||||
if (canInvokeHandler && handler) {
|
||||
handler(tokenDatum, nil);
|
||||
}
|
||||
};
|
||||
if (_accounts.count == 0) {
|
||||
[self fetchExistingTestAccountsWithAfterCursor:nil handler:helper];
|
||||
} else {
|
||||
helper(NULL);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)addTestAccountWithPermissions:(NSSet *)permissions
|
||||
completionHandler:(FBSDKTestUsersManagerRetrieveTestAccountTokensHandler)handler {
|
||||
NSDictionary *params = @{
|
||||
@"installed" : @"true",
|
||||
@"permissions" : [[permissions allObjects] componentsJoinedByString:@","],
|
||||
@"access_token" : self.appAccessToken
|
||||
};
|
||||
FBSDKGraphRequest *request = [[FBSDKGraphRequest alloc] initWithGraphPath:[NSString stringWithFormat:kFBGraphAPITestUsersPathFormat, _appID]
|
||||
parameters:params
|
||||
tokenString:[self appAccessToken]
|
||||
version:nil
|
||||
HTTPMethod:@"POST"];
|
||||
[request startWithCompletionHandler:^(FBSDKGraphRequestConnection *connection, id result, NSError *error) {
|
||||
if (error) {
|
||||
if (handler) {
|
||||
handler(nil, error);
|
||||
}
|
||||
} else {
|
||||
NSMutableDictionary *accountData = [NSMutableDictionary dictionaryWithCapacity:2];
|
||||
accountData[kAccountsDictionaryPermissionsKey] = [NSSet setWithSet:permissions];
|
||||
accountData[kAccountsDictionaryTokenKey] = result[@"access_token"];
|
||||
_accounts[result[@"id"]] = accountData;
|
||||
|
||||
if (handler) {
|
||||
FBSDKAccessToken *token = [self tokenDataForTokenString:accountData[kAccountsDictionaryTokenKey]
|
||||
permissions:permissions
|
||||
userId:result[@"id"]];
|
||||
handler(@[token], nil);
|
||||
}
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)makeFriendsWithFirst:(FBSDKAccessToken *)first second:(FBSDKAccessToken *)second callback:(void (^)(NSError *))callback
|
||||
{
|
||||
__block int expectedCount = 2;
|
||||
void (^complete)(NSError *) = ^(NSError *error) {
|
||||
// ignore if they're already friends or pending request
|
||||
if ([error.userInfo[FBSDKGraphRequestErrorGraphErrorCode] integerValue] == 522 ||
|
||||
[error.userInfo[FBSDKGraphRequestErrorGraphErrorCode] integerValue] == 520) {
|
||||
error = nil;
|
||||
}
|
||||
if (--expectedCount == 0 || error) {
|
||||
callback(error);
|
||||
}
|
||||
};
|
||||
FBSDKGraphRequest *one = [[FBSDKGraphRequest alloc] initWithGraphPath:[NSString stringWithFormat:@"%@/friends/%@", first.userID, second.userID]
|
||||
parameters:nil
|
||||
tokenString:first.tokenString
|
||||
version:nil
|
||||
HTTPMethod:@"POST"];
|
||||
FBSDKGraphRequest *two = [[FBSDKGraphRequest alloc] initWithGraphPath:[NSString stringWithFormat:@"%@/friends/%@", second.userID, first.userID]
|
||||
parameters:nil
|
||||
tokenString:second.tokenString
|
||||
version:nil
|
||||
HTTPMethod:@"POST"];
|
||||
FBSDKGraphRequestConnection *conn = [[FBSDKGraphRequestConnection alloc] init];
|
||||
[conn addRequest:one completionHandler:^(FBSDKGraphRequestConnection *connection, id result, NSError *error) {
|
||||
complete(error);
|
||||
} batchEntryName:@"first"];
|
||||
[conn addRequest:two completionHandler:^(FBSDKGraphRequestConnection *connection, id result, NSError *error) {
|
||||
complete(error);
|
||||
} batchParameters:@{ @"depends_on" : @"first"} ];
|
||||
[conn start];
|
||||
}
|
||||
|
||||
- (void)removeTestAccount:(NSString *)userId completionHandler:(FBSDKTestUsersManagerRemoveTestAccountHandler)handler {
|
||||
FBSDKGraphRequest *request = [[FBSDKGraphRequest alloc] initWithGraphPath:userId
|
||||
parameters:nil
|
||||
tokenString:self.appAccessToken
|
||||
version:nil
|
||||
HTTPMethod:@"DELETE"];
|
||||
[request startWithCompletionHandler:^(FBSDKGraphRequestConnection *connection, id result, NSError *error) {
|
||||
if (handler) {
|
||||
handler(error);
|
||||
}
|
||||
}];
|
||||
[_accounts removeObjectForKey:userId];
|
||||
}
|
||||
|
||||
#pragma mark - private methods
|
||||
- (FBSDKAccessToken *)tokenDataForTokenString:(NSString *)tokenString permissions:(NSSet *)permissions userId:(NSString *)userId{
|
||||
return [[FBSDKAccessToken alloc] initWithTokenString:tokenString
|
||||
permissions:[permissions allObjects]
|
||||
declinedPermissions:nil
|
||||
appID:_appID
|
||||
userID:userId
|
||||
expirationDate:nil
|
||||
refreshDate:nil];
|
||||
}
|
||||
|
||||
- (NSArray *)userIdAndTokenOfExistingAccountWithPermissions:(NSSet *)permissions skip:(NSSet *)setToSkip {
|
||||
__block NSString *userId = nil;
|
||||
__block NSString *token = nil;
|
||||
|
||||
[_accounts enumerateKeysAndObjectsUsingBlock:^(NSString *key, NSDictionary *accountData, BOOL *stop) {
|
||||
if ([setToSkip containsObject:key]) {
|
||||
return;
|
||||
}
|
||||
NSSet *accountPermissions = accountData[kAccountsDictionaryPermissionsKey];
|
||||
if ([permissions isSubsetOfSet:accountPermissions]) {
|
||||
token = accountData[kAccountsDictionaryTokenKey];
|
||||
userId = key;
|
||||
*stop = YES;
|
||||
}
|
||||
}];
|
||||
if (userId && token) {
|
||||
return @[userId, token];
|
||||
} else {
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
|
||||
- (NSString *)appAccessToken {
|
||||
return [NSString stringWithFormat:@"%@|%@", _appID, _appSecret];
|
||||
}
|
||||
|
||||
- (void)fetchExistingTestAccountsWithAfterCursor:(NSString *)after handler:(void(^)(NSError *error))handler {
|
||||
FBSDKGraphRequestConnection *connection = [[FBSDKGraphRequestConnection alloc] init];
|
||||
FBSDKGraphRequest *requestForAccountIds = [[FBSDKGraphRequest alloc] initWithGraphPath:[NSString stringWithFormat:kFBGraphAPITestUsersPathFormat, _appID]
|
||||
parameters:@{@"limit" : @"50",
|
||||
@"after" : after ?: @"",
|
||||
@"fields": @""
|
||||
}
|
||||
tokenString:self.appAccessToken
|
||||
version:nil
|
||||
HTTPMethod:nil];
|
||||
__block NSString *afterCursor = nil;
|
||||
__block NSInteger expectedTestAccounts = 0;
|
||||
FBSDKGraphRequestConnection *permissionConnection = [[FBSDKGraphRequestConnection alloc] init];
|
||||
[connection addRequest:requestForAccountIds completionHandler:^(FBSDKGraphRequestConnection *innerConnection, id result, NSError *error) {
|
||||
if (error) {
|
||||
if (handler) {
|
||||
handler(error);
|
||||
}
|
||||
// on errors, clear out accounts since it may be in a bad state
|
||||
[_accounts removeAllObjects];
|
||||
return;
|
||||
} else {
|
||||
for (NSDictionary *account in result[@"data"]) {
|
||||
NSString *userId = account[@"id"];
|
||||
NSString *token = account[@"access_token"];
|
||||
if (userId && token) {
|
||||
_accounts[userId] = [NSMutableDictionary dictionaryWithCapacity:2];
|
||||
_accounts[userId][kAccountsDictionaryTokenKey] = token;
|
||||
expectedTestAccounts++;
|
||||
[permissionConnection addRequest:[[FBSDKGraphRequest alloc] initWithGraphPath:[NSString stringWithFormat:@"%@?fields=permissions", userId]
|
||||
parameters:nil
|
||||
tokenString:self.appAccessToken
|
||||
version:nil
|
||||
HTTPMethod:nil]
|
||||
completionHandler:^(FBSDKGraphRequestConnection *innerConnection2, id innerResult, NSError *innerError) {
|
||||
if (_accounts.count == 0) {
|
||||
// indicates an earlier error that was already passed to handler, so just short circuit.
|
||||
return;
|
||||
}
|
||||
if (innerError) {
|
||||
if (handler) {
|
||||
handler(innerError);
|
||||
}
|
||||
[_accounts removeAllObjects];
|
||||
return;
|
||||
} else {
|
||||
NSMutableSet *grantedPermissions = [NSMutableSet set];
|
||||
NSArray *resultPermissionsDictionaries = innerResult[@"permissions"][@"data"];
|
||||
[resultPermissionsDictionaries enumerateObjectsUsingBlock:^(NSDictionary *obj, NSUInteger idx, BOOL *stop) {
|
||||
if ([obj[@"status"] isEqualToString:@"granted"]) {
|
||||
[grantedPermissions addObject:obj[@"permission"]];
|
||||
}
|
||||
}];
|
||||
_accounts[userId][kAccountsDictionaryPermissionsKey] = grantedPermissions;
|
||||
}
|
||||
expectedTestAccounts--;
|
||||
if (!expectedTestAccounts) {
|
||||
if (afterCursor) {
|
||||
[self fetchExistingTestAccountsWithAfterCursor:afterCursor handler:handler];
|
||||
} else if (handler) {
|
||||
handler(nil);
|
||||
}
|
||||
}
|
||||
}
|
||||
];
|
||||
}
|
||||
}
|
||||
afterCursor = result[@"paging"][@"cursors"][@"after"];
|
||||
}
|
||||
|
||||
if (expectedTestAccounts) {
|
||||
// finished fetching ids and tokens, now kick off the request for all the permissions
|
||||
[permissionConnection start];
|
||||
} else {
|
||||
if (handler) {
|
||||
handler(nil);
|
||||
}
|
||||
}
|
||||
}];
|
||||
[connection start];
|
||||
}
|
||||
@end
|
||||
@@ -0,0 +1,55 @@
|
||||
// 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>
|
||||
|
||||
/*!
|
||||
@abstract Class to contain common utility methods.
|
||||
*/
|
||||
@interface FBSDKUtility : NSObject
|
||||
|
||||
/*!
|
||||
@abstract Parses a query string into a dictionary.
|
||||
@param queryString The query string value.
|
||||
@return A dictionary with the key/value pairs.
|
||||
*/
|
||||
+ (NSDictionary *)dictionaryWithQueryString:(NSString *)queryString;
|
||||
|
||||
/*!
|
||||
@abstract Constructs a query string from a dictionary.
|
||||
@param dictionary The dictionary with key/value pairs for the query string.
|
||||
@param errorRef If an error occurs, upon return contains an NSError object that describes the problem.
|
||||
@result Query string representation of the parameters.
|
||||
*/
|
||||
+ (NSString *)queryStringWithDictionary:(NSDictionary *)dictionary error:(NSError *__autoreleasing *)errorRef;
|
||||
|
||||
/*!
|
||||
@abstract Decodes a value from an URL.
|
||||
@param value The value to decode.
|
||||
@result The decoded value.
|
||||
*/
|
||||
+ (NSString *)URLDecode:(NSString *)value;
|
||||
|
||||
/*!
|
||||
@abstract Encodes a value for an URL.
|
||||
@param value The value to encode.
|
||||
@result The encoded value.
|
||||
*/
|
||||
+ (NSString *)URLEncode:(NSString *)value;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,90 @@
|
||||
// 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 "FBSDKUtility.h"
|
||||
|
||||
#import "FBSDKInternalUtility.h"
|
||||
#import "FBSDKMacros.h"
|
||||
|
||||
@implementation FBSDKUtility
|
||||
|
||||
+ (NSDictionary *)dictionaryWithQueryString:(NSString *)queryString
|
||||
{
|
||||
NSMutableDictionary *result = [[NSMutableDictionary alloc] init];
|
||||
NSArray *parts = [queryString componentsSeparatedByString:@"&"];
|
||||
|
||||
for (NSString *part in parts) {
|
||||
if ([part length] == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
NSRange index = [part rangeOfString:@"="];
|
||||
NSString *key;
|
||||
NSString *value;
|
||||
|
||||
if (index.location == NSNotFound) {
|
||||
key = part;
|
||||
value = @"";
|
||||
} else {
|
||||
key = [part substringToIndex:index.location];
|
||||
value = [part substringFromIndex:index.location + index.length];
|
||||
}
|
||||
|
||||
key = [self URLDecode:key];
|
||||
value = [self URLDecode:value];
|
||||
if (key && value) {
|
||||
result[key] = value;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
+ (NSString *)queryStringWithDictionary:(NSDictionary *)dictionary error:(NSError *__autoreleasing *)errorRef
|
||||
{
|
||||
return [FBSDKInternalUtility queryStringWithDictionary:dictionary error:errorRef invalidObjectHandler:NULL];
|
||||
}
|
||||
|
||||
+ (NSString *)URLDecode:(NSString *)value
|
||||
{
|
||||
value = [value stringByReplacingOccurrencesOfString:@"+" withString:@" "];
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||
value = [value stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
|
||||
#pragma clang diagnostic pop
|
||||
return value;
|
||||
}
|
||||
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||
+ (NSString *)URLEncode:(NSString *)value
|
||||
{
|
||||
return (__bridge_transfer NSString *)CFURLCreateStringByAddingPercentEscapes(NULL,
|
||||
(CFStringRef)value,
|
||||
NULL, // characters to leave unescaped
|
||||
CFSTR(":!*();@/&?+$,='"),
|
||||
kCFStringEncodingUTF8);
|
||||
}
|
||||
#pragma clang diagnostic pop
|
||||
|
||||
- (instancetype)init
|
||||
{
|
||||
FBSDK_NO_DESIGNATED_INITIALIZER();
|
||||
return nil;
|
||||
}
|
||||
|
||||
@end
|
||||
Generated
+158
@@ -0,0 +1,158 @@
|
||||
// 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 <FBSDKCoreKit/FBSDKAppEvents.h>
|
||||
#import <FBSDKCoreKit/FBSDKMacros.h>
|
||||
|
||||
#import "FBSDKAppEventsUtility.h"
|
||||
|
||||
@class FBSDKGraphRequest;
|
||||
|
||||
// Internally known event names
|
||||
|
||||
FBSDK_EXTERN NSString *const FBSDKAppEventNamePurchased;
|
||||
|
||||
/*! Use to log that the share dialog was launched */
|
||||
FBSDK_EXTERN NSString *const FBSDKAppEventNameShareSheetLaunch;
|
||||
|
||||
/*! Use to log that the share dialog was dismissed */
|
||||
FBSDK_EXTERN NSString *const FBSDKAppEventNameShareSheetDismiss;
|
||||
|
||||
/*! Use to log that the permissions UI was launched */
|
||||
FBSDK_EXTERN NSString *const FBSDKAppEventNamePermissionsUILaunch;
|
||||
|
||||
/*! Use to log that the permissions UI was dismissed */
|
||||
FBSDK_EXTERN NSString *const FBSDKAppEventNamePermissionsUIDismiss;
|
||||
|
||||
/*! Use to log that the login view was used */
|
||||
FBSDK_EXTERN NSString *const FBSDKAppEventNameLoginViewUsage;
|
||||
|
||||
// Internally known event parameters
|
||||
|
||||
/*! String parameter specifying the outcome of a dialog invocation */
|
||||
FBSDK_EXTERN NSString *const FBSDKAppEventParameterDialogOutcome;
|
||||
|
||||
/*! Parameter key used to specify which application launches this application. */
|
||||
FBSDK_EXTERN NSString *const FBSDKAppEventParameterLaunchSource;
|
||||
|
||||
/*! Use to log the result of a call to FBDialogs presentShareDialogWithParams: */
|
||||
FBSDK_EXTERN NSString *const FBSDKAppEventNameFBDialogsPresentShareDialog;
|
||||
|
||||
/*! Use to log the result of a call to FBDialogs presentShareDialogWithOpenGraphActionParams: */
|
||||
FBSDK_EXTERN NSString *const FBSDKAppEventNameFBDialogsPresentShareDialogOG;
|
||||
|
||||
/*! Use to log the result of a call to FBDialogs presentLikeDialogWithLikeParams: */
|
||||
FBSDK_EXTERN NSString *const FBSDKAppEventNameFBDialogsPresentLikeDialogOG;
|
||||
|
||||
FBSDK_EXTERN NSString *const FBSDKAppEventNameFBDialogsPresentShareDialogPhoto;
|
||||
FBSDK_EXTERN NSString *const FBSDKAppEventNameFBDialogsPresentMessageDialog;
|
||||
FBSDK_EXTERN NSString *const FBSDKAppEventNameFBDialogsPresentMessageDialogPhoto;
|
||||
FBSDK_EXTERN NSString *const FBSDKAppEventNameFBDialogsPresentMessageDialogOG;
|
||||
|
||||
/*! Use to log the start of an auth request that cannot be fulfilled by the token cache */
|
||||
FBSDK_EXTERN NSString *const FBSDKAppEventNameFBSessionAuthStart;
|
||||
|
||||
/*! Use to log the end of an auth request that was not fulfilled by the token cache */
|
||||
FBSDK_EXTERN NSString *const FBSDKAppEventNameFBSessionAuthEnd;
|
||||
|
||||
/*! Use to log the start of a specific auth method as part of an auth request */
|
||||
FBSDK_EXTERN NSString *const FBSDKAppEventNameFBSessionAuthMethodStart;
|
||||
|
||||
/*! Use to log the end of the last tried auth method as part of an auth request */
|
||||
FBSDK_EXTERN NSString *const FBSDKAppEventNameFBSessionAuthMethodEnd;
|
||||
|
||||
/*! Use to log the timestamp for the transition to the Facebook native login dialog */
|
||||
FBSDK_EXTERN NSString *const FBSDKAppEventNameFBDialogsNativeLoginDialogStart;
|
||||
|
||||
/*! Use to log the timestamp for the transition back to the app after the Facebook native login dialog */
|
||||
FBSDK_EXTERN NSString *const FBSDKAppEventNameFBDialogsNativeLoginDialogEnd;
|
||||
|
||||
/*! Use to log the e2e timestamp metrics for web login */
|
||||
FBSDK_EXTERN NSString *const FBSDKAppEventNameFBDialogsWebLoginCompleted;
|
||||
|
||||
/*! Use to log the results of a share dialog */
|
||||
FBSDK_EXTERN NSString *const FBSDLAppEventNameFBSDKEventShareDialogResult;
|
||||
FBSDK_EXTERN NSString *const FBSDKAppEventNameFBSDKEventMessengerShareDialogResult;
|
||||
FBSDK_EXTERN NSString *const FBSDKAppEventNameFBSDKEventAppInviteShareDialogResult;
|
||||
|
||||
FBSDK_EXTERN NSString *const FBSDKAppEventNameFBSDKEventShareDialogShow;
|
||||
FBSDK_EXTERN NSString *const FBSDKAppEventNameFBSDKEventMessengerShareDialogShow;
|
||||
FBSDK_EXTERN NSString *const FBSDKAppEventNameFBSDKEventAppInviteShareDialogShow;
|
||||
|
||||
FBSDK_EXTERN NSString *const FBSDKAppEventParameterDialogMode;
|
||||
FBSDK_EXTERN NSString *const FBSDKAppEventParameterDialogShareContentType;
|
||||
|
||||
// Internally known event parameter values
|
||||
|
||||
FBSDK_EXTERN NSString *const FBSDKAppEventsDialogOutcomeValue_Completed;
|
||||
FBSDK_EXTERN NSString *const FBSDKAppEventsDialogOutcomeValue_Cancelled;
|
||||
FBSDK_EXTERN NSString *const FBSDKAppEventsDialogOutcomeValue_Failed;
|
||||
|
||||
FBSDK_EXTERN NSString *const FBSDKAppEventsDialogShareContentTypeOpenGraph;
|
||||
FBSDK_EXTERN NSString *const FBSDKAppEventsDialogShareContentTypeStatus;
|
||||
FBSDK_EXTERN NSString *const FBSDKAppEventsDialogShareContentTypePhoto;
|
||||
FBSDK_EXTERN NSString *const FBSDKAppEventsDialogShareContentTypeVideo;
|
||||
FBSDK_EXTERN NSString *const FBSDKAppEventsDialogShareContentTypeUnknown;
|
||||
|
||||
|
||||
FBSDK_EXTERN NSString *const FBSDKAppEventsDialogShareModeAutomatic;
|
||||
FBSDK_EXTERN NSString *const FBSDKAppEventsDialogShareModeBrowser;
|
||||
FBSDK_EXTERN NSString *const FBSDKAppEventsDialogShareModeNative;
|
||||
FBSDK_EXTERN NSString *const FBSDKAppEventsDialogShareModeShareSheet;
|
||||
FBSDK_EXTERN NSString *const FBSDKAppEventsDialogShareModeWeb;
|
||||
FBSDK_EXTERN NSString *const FBSDKAppEventsDialogShareModeFeedBrowser;
|
||||
FBSDK_EXTERN NSString *const FBSDKAppEventsDialogShareModeFeedWeb;
|
||||
FBSDK_EXTERN NSString *const FBSDKAppEventsDialogShareModeUnknown;
|
||||
|
||||
FBSDK_EXTERN NSString *const FBSDKAppEventsNativeLoginDialogStartTime;
|
||||
FBSDK_EXTERN NSString *const FBSDKAppEventsNativeLoginDialogEndTime;
|
||||
|
||||
FBSDK_EXTERN NSString *const FBSDKAppEventsWebLoginE2E;
|
||||
|
||||
FBSDK_EXTERN NSString *const FBSDKAppEventNameFBSDKLikeButtonImpression;
|
||||
FBSDK_EXTERN NSString *const FBSDKAppEventNameFBSDKLoginButtonImpression;
|
||||
FBSDK_EXTERN NSString *const FBSDKAppEventNameFBSDKSendButtonImpression;
|
||||
FBSDK_EXTERN NSString *const FBSDKAppEventNameFBSDKShareButtonImpression;
|
||||
|
||||
FBSDK_EXTERN NSString *const FBSDKAppEventNameFBSDKLikeButtonDidTap;
|
||||
FBSDK_EXTERN NSString *const FBSDKAppEventNameFBSDKLoginButtonDidTap;
|
||||
FBSDK_EXTERN NSString *const FBSDKAppEventNameFBSDKSendButtonDidTap;
|
||||
FBSDK_EXTERN NSString *const FBSDKAppEventNameFBSDKShareButtonDidTap;
|
||||
|
||||
FBSDK_EXTERN NSString *const FBSDKAppEventNameFBSDKLikeControlDidDisable;
|
||||
FBSDK_EXTERN NSString *const FBSDKAppEventNameFBSDKLikeControlDidLike;
|
||||
FBSDK_EXTERN NSString *const FBSDKAppEventNameFBSDKLikeControlDidPresentDialog;
|
||||
FBSDK_EXTERN NSString *const FBSDKAppEventNameFBSDKLikeControlDidTap;
|
||||
FBSDK_EXTERN NSString *const FBSDKAppEventNameFBSDKLikeControlDidUnlike;
|
||||
FBSDK_EXTERN NSString *const FBSDKAppEventNameFBSDKLikeControlError;
|
||||
FBSDK_EXTERN NSString *const FBSDKAppEventNameFBSDKLikeControlImpression;
|
||||
FBSDK_EXTERN NSString *const FBSDKAppEventNameFBSDKLikeControlNetworkUnavailable;
|
||||
|
||||
FBSDK_EXTERN NSString *const FBSDKAppEventParameterDialogErrorMessage;
|
||||
|
||||
@interface FBSDKAppEvents (Internal)
|
||||
|
||||
+ (void)logImplicitEvent:(NSString *)eventName
|
||||
valueToSum:(NSNumber *)valueToSum
|
||||
parameters:(NSDictionary *)parameters
|
||||
accessToken:(FBSDKAccessToken *)accessToken;
|
||||
|
||||
+ (FBSDKAppEvents *)singleton;
|
||||
- (void)flushForReason:(FBSDKAppEventsFlushReason)flushReason;
|
||||
|
||||
@end
|
||||
Generated
+25
@@ -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>
|
||||
|
||||
@interface FBSDKAppEventsDeviceInfo : NSObject
|
||||
|
||||
+ (void)extendDictionaryWithDeviceInfo:(NSMutableDictionary *)dictionary;
|
||||
|
||||
@end
|
||||
Generated
+258
@@ -0,0 +1,258 @@
|
||||
// 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 "FBSDKAppEventsDeviceInfo.h"
|
||||
|
||||
#import <sys/sysctl.h>
|
||||
#import <sys/utsname.h>
|
||||
|
||||
#if !TARGET_OS_TV
|
||||
#import <CoreTelephony/CTCarrier.h>
|
||||
#import <CoreTelephony/CTTelephonyNetworkInfo.h>
|
||||
#endif
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
#import "FBSDKAppEvents+Internal.h"
|
||||
#import "FBSDKDynamicFrameworkLoader.h"
|
||||
#import "FBSDKInternalUtility.h"
|
||||
#import "FBSDKUtility.h"
|
||||
|
||||
#define FB_ARRAY_COUNT(x) sizeof(x) / sizeof(x[0])
|
||||
|
||||
static const u_int FB_GROUP1_RECHECK_DURATION = 30 * 60; // seconds
|
||||
|
||||
// Apple reports storage in binary gigabytes (1024^3) in their About menus, etc.
|
||||
static const u_int FB_GIGABYTE = 1024 * 1024 * 1024; // bytes
|
||||
|
||||
@implementation FBSDKAppEventsDeviceInfo
|
||||
|
||||
// Ephemeral data, may change during the lifetime of an app. We collect them in different
|
||||
// 'group' frequencies - group1 may gets collected once every 30 minutes.
|
||||
|
||||
// group1
|
||||
NSString *_carrierName;
|
||||
NSString *_timeZoneAbbrev;
|
||||
unsigned long long _remainingDiskSpaceGB;
|
||||
|
||||
// Persistent data, but we maintain it to make rebuilding the device info as fast as possible.
|
||||
NSString *_bundleIdentifier;
|
||||
NSString *_longVersion;
|
||||
NSString *_shortVersion;
|
||||
NSString *_sysVersion;
|
||||
NSString *_machine;
|
||||
NSString *_language;
|
||||
unsigned long long _totalDiskSpaceGB;
|
||||
unsigned long long _coreCount;
|
||||
CGFloat _width;
|
||||
CGFloat _height;
|
||||
CGFloat _density;
|
||||
|
||||
// Other state
|
||||
long _lastGroup1CheckTime;
|
||||
BOOL _isEncodingDirty = YES;
|
||||
NSString *_encodedDeviceInfo;
|
||||
static FBSDKAppEventsDeviceInfo *g_singleton;
|
||||
|
||||
#pragma mark - Public Methods
|
||||
|
||||
+ (void)extendDictionaryWithDeviceInfo:(NSMutableDictionary *)dictionary
|
||||
{
|
||||
dictionary[@"extinfo"] = [g_singleton encodedDeviceInfo];
|
||||
}
|
||||
|
||||
#pragma mark - Internal Methods
|
||||
|
||||
+ (void)initialize
|
||||
{
|
||||
if (self == [FBSDKAppEventsDeviceInfo class]) {
|
||||
g_singleton = [[FBSDKAppEventsDeviceInfo alloc] init];
|
||||
[g_singleton _collectPersistentData];
|
||||
}
|
||||
}
|
||||
|
||||
- (NSString *)encodedDeviceInfo
|
||||
{
|
||||
@synchronized (self) {
|
||||
|
||||
BOOL isGroup1Expired = [self _isGroup1Expired];
|
||||
BOOL isEncodingExpired = isGroup1Expired; // Can || other groups in if we add them
|
||||
|
||||
// As long as group1 hasn't expired, we can just return the last generated value
|
||||
if (_encodedDeviceInfo && !isEncodingExpired) {
|
||||
return _encodedDeviceInfo;
|
||||
}
|
||||
|
||||
if (isGroup1Expired) {
|
||||
[self _collectGroup1Data];
|
||||
}
|
||||
|
||||
if (_isEncodingDirty) {
|
||||
self.encodedDeviceInfo = [self _generateEncoding];
|
||||
_isEncodingDirty = NO;
|
||||
}
|
||||
|
||||
return _encodedDeviceInfo;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setEncodedDeviceInfo:(NSString *)encodedDeviceInfo
|
||||
{
|
||||
@synchronized (self) {
|
||||
if (![_encodedDeviceInfo isEqualToString:encodedDeviceInfo]) {
|
||||
_encodedDeviceInfo = [encodedDeviceInfo copy];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This data need only be collected once.
|
||||
- (void)_collectPersistentData
|
||||
{
|
||||
// Bundle stuff
|
||||
NSBundle *mainBundle = [NSBundle mainBundle];
|
||||
_bundleIdentifier = mainBundle.bundleIdentifier;
|
||||
_longVersion = [mainBundle objectForInfoDictionaryKey:@"CFBundleVersion"];
|
||||
_shortVersion = [mainBundle objectForInfoDictionaryKey:@"CFBundleShortVersionString"];
|
||||
|
||||
// Locale stuff
|
||||
_language = [[NSLocale currentLocale] localeIdentifier];
|
||||
|
||||
// Device stuff
|
||||
UIDevice *device = [UIDevice currentDevice];
|
||||
_sysVersion = device.systemVersion;
|
||||
_coreCount = [FBSDKAppEventsDeviceInfo _coreCount];
|
||||
|
||||
UIScreen *sc = [UIScreen mainScreen];
|
||||
CGRect sr = sc.bounds;
|
||||
_width = sr.size.width;
|
||||
_height = sr.size.height;
|
||||
_density = sc.scale;
|
||||
|
||||
struct utsname systemInfo;
|
||||
uname(&systemInfo);
|
||||
_machine = @(systemInfo.machine);
|
||||
|
||||
// Disk space stuff
|
||||
float totalDiskSpace = [[FBSDKAppEventsDeviceInfo _getTotalDiskSpace] floatValue];
|
||||
_totalDiskSpaceGB = (unsigned long long)round(totalDiskSpace / FB_GIGABYTE);
|
||||
}
|
||||
|
||||
- (BOOL)_isGroup1Expired
|
||||
{
|
||||
return ([FBSDKAppEventsUtility unixTimeNow] - _lastGroup1CheckTime) > FB_GROUP1_RECHECK_DURATION;
|
||||
}
|
||||
|
||||
// This data is collected only once every GROUP1_RECHECK_DURATION.
|
||||
- (void)_collectGroup1Data
|
||||
{
|
||||
// Carrier
|
||||
NSString *newCarrierName = [FBSDKAppEventsDeviceInfo _getCarrier];
|
||||
if (![newCarrierName isEqualToString:_carrierName]) {
|
||||
_carrierName = newCarrierName;
|
||||
_isEncodingDirty = YES;
|
||||
}
|
||||
|
||||
// Time zone
|
||||
NSString *newTimeZoneAbbrev = [[NSTimeZone systemTimeZone] abbreviation];
|
||||
if (![newTimeZoneAbbrev isEqualToString:_timeZoneAbbrev]) {
|
||||
_timeZoneAbbrev = newTimeZoneAbbrev;
|
||||
_isEncodingDirty = YES;
|
||||
}
|
||||
|
||||
// Remaining disk space
|
||||
float remainingDiskSpace = [[FBSDKAppEventsDeviceInfo _getRemainingDiskSpace] floatValue];
|
||||
unsigned long long newRemainingDiskSpaceGB = (unsigned long long)round(remainingDiskSpace / FB_GIGABYTE);
|
||||
if (_remainingDiskSpaceGB != newRemainingDiskSpaceGB) {
|
||||
_remainingDiskSpaceGB = newRemainingDiskSpaceGB;
|
||||
_isEncodingDirty = YES;
|
||||
}
|
||||
|
||||
_lastGroup1CheckTime = [FBSDKAppEventsUtility unixTimeNow];
|
||||
}
|
||||
|
||||
- (NSString *)_generateEncoding
|
||||
{
|
||||
// Keep a bit of precision on density as it's the most likely to become non-integer.
|
||||
NSString *densityString = _density ? [NSString stringWithFormat:@"%.02f", _density] : @"";
|
||||
|
||||
NSArray *arr = @[
|
||||
@"i2", // version - starts with 'i' for iOS, we'll use 'a' for Android
|
||||
_bundleIdentifier ?: @"",
|
||||
_longVersion ?: @"",
|
||||
_shortVersion ?: @"",
|
||||
_sysVersion ?: @"",
|
||||
_machine ?: @"",
|
||||
_language ?: @"",
|
||||
_timeZoneAbbrev ?: @"",
|
||||
_carrierName ?: @"",
|
||||
_width ? @((unsigned long)_width) : @"",
|
||||
_height ? @((unsigned long)_height) : @"",
|
||||
densityString,
|
||||
@(_coreCount) ?: @"",
|
||||
@(_totalDiskSpaceGB) ?: @"",
|
||||
@(_remainingDiskSpaceGB) ?: @"",
|
||||
];
|
||||
|
||||
return [FBSDKInternalUtility JSONStringForObject:arr error:NULL invalidObjectHandler:NULL];
|
||||
}
|
||||
|
||||
#pragma mark - Helper Methods
|
||||
|
||||
+ (NSNumber *)_getTotalDiskSpace
|
||||
{
|
||||
NSDictionary *attrs = [[[NSFileManager alloc] init] attributesOfFileSystemForPath:NSHomeDirectory()
|
||||
error:nil];
|
||||
return [attrs objectForKey:NSFileSystemSize];
|
||||
}
|
||||
|
||||
+ (NSNumber *)_getRemainingDiskSpace
|
||||
{
|
||||
NSDictionary *attrs = [[[NSFileManager alloc] init] attributesOfFileSystemForPath:NSHomeDirectory()
|
||||
error:nil];
|
||||
return [attrs objectForKey:NSFileSystemFreeSize];
|
||||
}
|
||||
|
||||
+ (uint)_coreCount
|
||||
{
|
||||
return [FBSDKAppEventsDeviceInfo _readSysCtlUInt:CTL_HW type:HW_AVAILCPU];
|
||||
}
|
||||
|
||||
+ (uint)_readSysCtlUInt:(int)ctl type:(int)type
|
||||
{
|
||||
int mib[2] = {ctl, type};
|
||||
uint value;
|
||||
size_t size = sizeof value;
|
||||
if (0 != sysctl(mib, FB_ARRAY_COUNT(mib), &value, &size, NULL, 0)) {
|
||||
return 0;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
+ (NSString *)_getCarrier
|
||||
{
|
||||
#if TARGET_OS_TV
|
||||
return @"NoCarrier";
|
||||
#else
|
||||
// Dynamically load class for this so calling app doesn't need to link framework in.
|
||||
CTTelephonyNetworkInfo *networkInfo = [[fbsdkdfl_CTTelephonyNetworkInfoClass() alloc] init];
|
||||
CTCarrier *carrier = [networkInfo subscriberCellularProvider];
|
||||
return [carrier carrierName] ?: @"NoCarrier";
|
||||
#endif
|
||||
}
|
||||
|
||||
@end
|
||||
Generated
+38
@@ -0,0 +1,38 @@
|
||||
// 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>
|
||||
|
||||
// this type is not thread safe.
|
||||
@interface FBSDKAppEventsState : NSObject<NSCopying, NSSecureCoding>
|
||||
|
||||
@property (readonly, copy) NSArray *events;
|
||||
@property (readonly, assign) NSUInteger numSkipped;
|
||||
@property (readonly, copy) NSString *tokenString;
|
||||
@property (readonly, copy) NSString *appID;
|
||||
|
||||
- (instancetype)initWithToken:(NSString *)tokenString appID:(NSString *)appID NS_DESIGNATED_INITIALIZER;
|
||||
|
||||
- (void)addEvent:(NSDictionary *)eventDictionary isImplicit:(BOOL)isImplicit;
|
||||
- (void)addEventsFromAppEventState:(FBSDKAppEventsState *)appEventsState;
|
||||
- (BOOL)areAllEventsImplicit;
|
||||
- (BOOL)isCompatibleWithAppEventsState:(FBSDKAppEventsState *)appEventsState;
|
||||
- (BOOL)isCompatibleWithTokenString:(NSString *)tokenString appID:(NSString *)appID;
|
||||
- (NSString *)JSONStringForEvents:(BOOL)includeImplicitEvents;
|
||||
|
||||
@end
|
||||
Generated
+161
@@ -0,0 +1,161 @@
|
||||
// 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 "FBSDKAppEventsState.h"
|
||||
|
||||
#import "FBSDKInternalUtility.h"
|
||||
#import "FBSDKMacros.h"
|
||||
|
||||
#define FBSDK_APPEVENTSTATE_ISIMPLICIT_KEY @"isImplicit"
|
||||
|
||||
#define FBSDK_APPEVENTSSTATE_MAX_EVENTS 1000
|
||||
|
||||
#define FBSDK_APPEVENTSSTATE_APPID_KEY @"appID"
|
||||
#define FBSDK_APPEVENTSSTATE_EVENTS_KEY @"events"
|
||||
#define FBSDK_APPEVENTSSTATE_NUMSKIPPED_KEY @"numSkipped"
|
||||
#define FBSDK_APPEVENTSSTATE_TOKENSTRING_KEY @"tokenString"
|
||||
|
||||
@implementation FBSDKAppEventsState
|
||||
{
|
||||
NSMutableArray *_mutableEvents;
|
||||
}
|
||||
|
||||
- (instancetype)init
|
||||
{
|
||||
FBSDK_NOT_DESIGNATED_INITIALIZER(initWithToken:appID:);
|
||||
return [self initWithToken:nil appID:nil];
|
||||
}
|
||||
|
||||
- (instancetype)initWithToken:(NSString *)tokenString appID:(NSString *)appID
|
||||
{
|
||||
if ((self = [super init])) {
|
||||
_tokenString = [tokenString copy];
|
||||
_appID = [appID copy];
|
||||
_mutableEvents = [NSMutableArray array];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (instancetype)copyWithZone:(NSZone *)zone
|
||||
{
|
||||
FBSDKAppEventsState *copy = [[FBSDKAppEventsState allocWithZone:zone] initWithToken:_tokenString appID:_appID];
|
||||
if (copy) {
|
||||
[copy->_mutableEvents addObjectsFromArray:_mutableEvents];
|
||||
copy->_numSkipped = _numSkipped;
|
||||
}
|
||||
return copy;
|
||||
}
|
||||
|
||||
#pragma mark - NSCoding
|
||||
|
||||
+ (BOOL)supportsSecureCoding
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (id)initWithCoder:(NSCoder *)decoder
|
||||
{
|
||||
NSString *appID = [decoder decodeObjectOfClass:[NSString class] forKey:FBSDK_APPEVENTSSTATE_APPID_KEY];
|
||||
NSString *tokenString = [decoder decodeObjectOfClass:[NSString class] forKey:FBSDK_APPEVENTSSTATE_TOKENSTRING_KEY];
|
||||
NSArray *events = [decoder decodeObjectOfClass:[NSArray class] forKey:FBSDK_APPEVENTSSTATE_EVENTS_KEY];
|
||||
NSUInteger numSkipped = [[decoder decodeObjectOfClass:[NSNumber class] forKey:FBSDK_APPEVENTSSTATE_NUMSKIPPED_KEY] unsignedIntegerValue];
|
||||
|
||||
if ((self = [self initWithToken:tokenString appID:appID])) {
|
||||
_mutableEvents = [NSMutableArray arrayWithArray:events];
|
||||
_numSkipped = numSkipped;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)encodeWithCoder:(NSCoder *)encoder
|
||||
{
|
||||
[encoder encodeObject:_appID forKey:FBSDK_APPEVENTSSTATE_APPID_KEY];
|
||||
[encoder encodeObject:_tokenString forKey:FBSDK_APPEVENTSSTATE_TOKENSTRING_KEY];
|
||||
[encoder encodeObject:@(_numSkipped) forKey:FBSDK_APPEVENTSSTATE_NUMSKIPPED_KEY];
|
||||
[encoder encodeObject:_mutableEvents forKey:FBSDK_APPEVENTSSTATE_EVENTS_KEY];
|
||||
}
|
||||
|
||||
#pragma mark - Implementation
|
||||
|
||||
- (NSArray *)events
|
||||
{
|
||||
return [_mutableEvents copy];
|
||||
}
|
||||
|
||||
- (void)addEventsFromAppEventState:(FBSDKAppEventsState *)appEventsState
|
||||
{
|
||||
NSArray *toAdd = appEventsState->_mutableEvents;
|
||||
NSInteger excess = _mutableEvents.count + toAdd.count - FBSDK_APPEVENTSSTATE_MAX_EVENTS;
|
||||
if (excess > 0) {
|
||||
NSInteger range = FBSDK_APPEVENTSSTATE_MAX_EVENTS - _mutableEvents.count;
|
||||
toAdd = [toAdd subarrayWithRange:NSMakeRange(0, range)];
|
||||
_numSkipped += excess;
|
||||
}
|
||||
|
||||
[_mutableEvents addObjectsFromArray:toAdd];
|
||||
}
|
||||
|
||||
- (void)addEvent:(NSDictionary *)eventDictionary
|
||||
isImplicit:(BOOL)isImplicit {
|
||||
if (_mutableEvents.count >= FBSDK_APPEVENTSSTATE_MAX_EVENTS) {
|
||||
_numSkipped++;
|
||||
} else {
|
||||
[_mutableEvents addObject:@{
|
||||
@"event" : eventDictionary,
|
||||
FBSDK_APPEVENTSTATE_ISIMPLICIT_KEY : @(isImplicit)
|
||||
}];
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)areAllEventsImplicit
|
||||
{
|
||||
for (NSDictionary *event in _mutableEvents) {
|
||||
if (![[event valueForKey:FBSDK_APPEVENTSTATE_ISIMPLICIT_KEY] boolValue]) {
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (BOOL)isCompatibleWithAppEventsState:(FBSDKAppEventsState *)appEventsState
|
||||
{
|
||||
return ([self isCompatibleWithTokenString:appEventsState.tokenString appID:appEventsState.appID]);
|
||||
}
|
||||
|
||||
- (BOOL)isCompatibleWithTokenString:(NSString *)tokenString appID:(NSString *)appID
|
||||
{
|
||||
// token strings can be nil (e.g., no user token) but appIDs should not.
|
||||
BOOL tokenCompatible = ([self.tokenString isEqualToString:tokenString] ||
|
||||
(self.tokenString == nil && tokenString == nil));
|
||||
return (tokenCompatible &&
|
||||
[self.appID isEqualToString:appID]);
|
||||
}
|
||||
|
||||
- (NSString *)JSONStringForEvents:(BOOL)includeImplicitEvents
|
||||
{
|
||||
NSMutableArray *events = [[NSMutableArray alloc] initWithCapacity:_mutableEvents.count];
|
||||
for (NSDictionary *eventAndImplicitFlag in _mutableEvents) {
|
||||
if (!includeImplicitEvents && [eventAndImplicitFlag[FBSDK_APPEVENTSTATE_ISIMPLICIT_KEY] boolValue]) {
|
||||
continue;
|
||||
}
|
||||
[events addObject:eventAndImplicitFlag[@"event"]];
|
||||
}
|
||||
|
||||
return [FBSDKInternalUtility JSONStringForObject:events error:NULL invalidObjectHandler:NULL];
|
||||
}
|
||||
@end
|
||||
Generated
+34
@@ -0,0 +1,34 @@
|
||||
// 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>
|
||||
|
||||
@class FBSDKAppEventsState;
|
||||
|
||||
@interface FBSDKAppEventsStateManager : NSObject
|
||||
|
||||
+ (void)clearPersistedAppEventsStates;
|
||||
|
||||
// reads all saved event states, appends the param, and writes them all.
|
||||
+ (void)persistAppEventsData:(FBSDKAppEventsState *)appEventsState;
|
||||
|
||||
// returns the array of saved app event states and deletes them.
|
||||
+ (NSArray *)retrievePersistedAppEventsStates;
|
||||
|
||||
|
||||
@end
|
||||
Generated
+78
@@ -0,0 +1,78 @@
|
||||
// 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 "FBSDKAppEventsStateManager.h"
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#import "FBSDKAppEventsState.h"
|
||||
#import "FBSDKAppEventsUtility.h"
|
||||
#import "FBSDKLogger.h"
|
||||
#import "FBSDKSettings.h"
|
||||
|
||||
// A quick optimization to allow returning empty array if we know there are no persisted events.
|
||||
static BOOL g_canSkipDiskCheck = NO;
|
||||
|
||||
@implementation FBSDKAppEventsStateManager
|
||||
|
||||
+ (void)clearPersistedAppEventsStates
|
||||
{
|
||||
[FBSDKLogger singleShotLogEntry:FBSDKLoggingBehaviorAppEvents
|
||||
logEntry:@"FBSDKAppEvents Persist: Clearing"];
|
||||
[[NSFileManager defaultManager] removeItemAtPath:[[self class] filePath]
|
||||
error:NULL];
|
||||
g_canSkipDiskCheck = YES;
|
||||
}
|
||||
|
||||
+ (void)persistAppEventsData:(FBSDKAppEventsState *)appEventsState
|
||||
{
|
||||
[FBSDKLogger singleShotLogEntry:FBSDKLoggingBehaviorAppEvents
|
||||
formatString:@"FBSDKAppEvents Persist: Writing %lu events", (unsigned long)appEventsState.events.count];
|
||||
|
||||
if (!appEventsState.events.count) {
|
||||
return;
|
||||
}
|
||||
NSMutableArray *existingEvents = [NSMutableArray arrayWithArray:[[self class] retrievePersistedAppEventsStates]];
|
||||
[existingEvents addObject:appEventsState];
|
||||
|
||||
[NSKeyedArchiver archiveRootObject:existingEvents toFile:[[self class] filePath]];
|
||||
g_canSkipDiskCheck = NO;
|
||||
}
|
||||
|
||||
+ (NSArray *)retrievePersistedAppEventsStates
|
||||
{
|
||||
NSMutableArray *eventsStates = [NSMutableArray array];
|
||||
if (!g_canSkipDiskCheck) {
|
||||
[eventsStates addObjectsFromArray:[NSKeyedUnarchiver unarchiveObjectWithFile:[[self class] filePath]]];
|
||||
|
||||
[FBSDKLogger singleShotLogEntry:FBSDKLoggingBehaviorAppEvents
|
||||
formatString:@"FBSDKAppEvents Persist: Read %lu event states. First state has %lu events",
|
||||
(unsigned long)eventsStates.count,
|
||||
(unsigned long)(eventsStates.count > 0 ? ((FBSDKAppEventsState *)eventsStates[0]).events.count : 0)];
|
||||
[[self class] clearPersistedAppEventsStates];
|
||||
}
|
||||
return eventsStates;
|
||||
}
|
||||
|
||||
#pragma mark - Private Helpers
|
||||
|
||||
+ (NSString *)filePath
|
||||
{
|
||||
return [FBSDKAppEventsUtility persistenceFilePath:@"com-facebook-sdk-AppEventsPersistedEvents.json"];
|
||||
}
|
||||
@end
|
||||
Generated
+57
@@ -0,0 +1,57 @@
|
||||
// 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>
|
||||
|
||||
@class FBSDKAccessToken;
|
||||
|
||||
typedef NS_ENUM(NSUInteger, FBSDKAdvertisingTrackingStatus)
|
||||
{
|
||||
FBSDKAdvertisingTrackingAllowed,
|
||||
FBSDKAdvertisingTrackingDisallowed,
|
||||
FBSDKAdvertisingTrackingUnspecified
|
||||
};
|
||||
|
||||
typedef NS_ENUM(NSUInteger, FBSDKAppEventsFlushReason)
|
||||
{
|
||||
FBSDKAppEventsFlushReasonExplicit,
|
||||
FBSDKAppEventsFlushReasonTimer,
|
||||
FBSDKAppEventsFlushReasonSessionChange,
|
||||
FBSDKAppEventsFlushReasonPersistedEvents,
|
||||
FBSDKAppEventsFlushReasonEventThreshold,
|
||||
FBSDKAppEventsFlushReasonEagerlyFlushingEvent
|
||||
};
|
||||
|
||||
@interface FBSDKAppEventsUtility : NSObject
|
||||
|
||||
+ (NSMutableDictionary *)activityParametersDictionaryForEvent:(NSString *)eventCategory
|
||||
implicitEventsOnly:(BOOL)implicitEventsOnly
|
||||
shouldAccessAdvertisingID:(BOOL)shouldAccessAdvertisingID;
|
||||
+ (NSString *)advertiserID;
|
||||
+ (FBSDKAdvertisingTrackingStatus)advertisingTrackingStatus;
|
||||
+ (NSString *)attributionID;
|
||||
+ (void)ensureOnMainThread:(NSString *)methodName className:(NSString *)className;
|
||||
+ (NSString *)flushReasonToString:(FBSDKAppEventsFlushReason)flushReason;
|
||||
+ (void)logAndNotify:(NSString *)msg allowLogAsDeveloperError:(BOOL)allowLogAsDeveloperError;
|
||||
+ (void)logAndNotify:(NSString *)msg;
|
||||
+ (NSString *)persistenceFilePath:(NSString *)filename;
|
||||
+ (NSString *)tokenStringToUseFor:(FBSDKAccessToken *)token;
|
||||
+ (long)unixTimeNow;
|
||||
+ (BOOL)validateIdentifier:(NSString *)identifier;
|
||||
|
||||
@end
|
||||
Generated
+313
@@ -0,0 +1,313 @@
|
||||
// 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 "FBSDKAppEventsUtility.h"
|
||||
|
||||
#import <AdSupport/AdSupport.h>
|
||||
|
||||
#import "FBSDKAccessToken.h"
|
||||
#import "FBSDKAppEvents.h"
|
||||
#import "FBSDKAppEventsDeviceInfo.h"
|
||||
#import "FBSDKConstants.h"
|
||||
#import "FBSDKDynamicFrameworkLoader.h"
|
||||
#import "FBSDKError.h"
|
||||
#import "FBSDKInternalUtility.h"
|
||||
#import "FBSDKLogger.h"
|
||||
#import "FBSDKMacros.h"
|
||||
#import "FBSDKSettings.h"
|
||||
#import "FBSDKTimeSpentData.h"
|
||||
|
||||
#define FBSDK_APPEVENTSUTILITY_ANONYMOUSIDFILENAME @"com-facebook-sdk-PersistedAnonymousID.json"
|
||||
#define FBSDK_APPEVENTSUTILITY_ANONYMOUSID_KEY @"anon_id"
|
||||
#define FBSDK_APPEVENTSUTILITY_MAX_IDENTIFIER_LENGTH 40
|
||||
|
||||
@implementation FBSDKAppEventsUtility
|
||||
|
||||
+ (NSMutableDictionary *)activityParametersDictionaryForEvent:(NSString *)eventCategory
|
||||
implicitEventsOnly:(BOOL)implicitEventsOnly
|
||||
shouldAccessAdvertisingID:(BOOL)shouldAccessAdvertisingID {
|
||||
NSMutableDictionary *parameters = [NSMutableDictionary dictionary];
|
||||
parameters[@"event"] = eventCategory;
|
||||
|
||||
NSString *attributionID = [[self class] attributionID]; // Only present on iOS 6 and below.
|
||||
[FBSDKInternalUtility dictionary:parameters setObject:attributionID forKey:@"attribution"];
|
||||
|
||||
if (!implicitEventsOnly && shouldAccessAdvertisingID) {
|
||||
NSString *advertiserID = [[self class] advertiserID];
|
||||
[FBSDKInternalUtility dictionary:parameters setObject:advertiserID forKey:@"advertiser_id"];
|
||||
}
|
||||
|
||||
parameters[FBSDK_APPEVENTSUTILITY_ANONYMOUSID_KEY] = [self anonymousID];
|
||||
|
||||
FBSDKAdvertisingTrackingStatus advertisingTrackingStatus = [[self class] advertisingTrackingStatus];
|
||||
if (advertisingTrackingStatus != FBSDKAdvertisingTrackingUnspecified) {
|
||||
BOOL allowed = (advertisingTrackingStatus == FBSDKAdvertisingTrackingAllowed);
|
||||
parameters[@"advertiser_tracking_enabled"] = [@(allowed) stringValue];
|
||||
}
|
||||
|
||||
parameters[@"application_tracking_enabled"] = [@(!FBSDKSettings.limitEventAndDataUsage) stringValue];
|
||||
|
||||
[FBSDKAppEventsDeviceInfo extendDictionaryWithDeviceInfo:parameters];
|
||||
|
||||
static dispatch_once_t fetchBundleOnce;
|
||||
static NSMutableArray *urlSchemes;
|
||||
|
||||
dispatch_once(&fetchBundleOnce, ^{
|
||||
NSBundle *mainBundle = [NSBundle mainBundle];
|
||||
urlSchemes = [[NSMutableArray alloc] init];
|
||||
for (NSDictionary *fields in [mainBundle objectForInfoDictionaryKey:@"CFBundleURLTypes"]) {
|
||||
NSArray *schemesForType = [fields objectForKey:@"CFBundleURLSchemes"];
|
||||
if (schemesForType) {
|
||||
[urlSchemes addObjectsFromArray:schemesForType];
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (urlSchemes.count > 0) {
|
||||
[parameters setObject:[FBSDKInternalUtility JSONStringForObject:urlSchemes error:NULL invalidObjectHandler:NULL]
|
||||
forKey:@"url_schemes"];
|
||||
}
|
||||
|
||||
return parameters;
|
||||
}
|
||||
|
||||
+ (NSString *)advertiserID
|
||||
{
|
||||
NSString *result = nil;
|
||||
|
||||
Class ASIdentifierManagerClass = fbsdkdfl_ASIdentifierManagerClass();
|
||||
if ([ASIdentifierManagerClass class]) {
|
||||
ASIdentifierManager *manager = [ASIdentifierManagerClass sharedManager];
|
||||
result = [[manager advertisingIdentifier] UUIDString];
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
+ (FBSDKAdvertisingTrackingStatus)advertisingTrackingStatus
|
||||
{
|
||||
static dispatch_once_t fetchAdvertisingTrackingStatusOnce;
|
||||
static FBSDKAdvertisingTrackingStatus status;
|
||||
|
||||
dispatch_once(&fetchAdvertisingTrackingStatusOnce, ^{
|
||||
status = FBSDKAdvertisingTrackingUnspecified;
|
||||
Class ASIdentifierManagerClass = fbsdkdfl_ASIdentifierManagerClass();
|
||||
if ([ASIdentifierManagerClass class]) {
|
||||
ASIdentifierManager *manager = [ASIdentifierManagerClass sharedManager];
|
||||
if (manager) {
|
||||
status = [manager isAdvertisingTrackingEnabled] ? FBSDKAdvertisingTrackingAllowed : FBSDKAdvertisingTrackingDisallowed;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
+ (NSString *)anonymousID
|
||||
{
|
||||
// Grab previously written anonymous ID and, if none have been generated, create and
|
||||
// persist a new one which will remain associated with this app.
|
||||
NSString *result = [[self class] retrievePersistedAnonymousID];
|
||||
if (!result) {
|
||||
// Generate a new anonymous ID. Create as a UUID, but then prepend the fairly
|
||||
// arbitrary 'XZ' to the front so it's easily distinguishable from IDFA's which
|
||||
// will only contain hex.
|
||||
result = [NSString stringWithFormat:@"XZ%@", [[NSUUID UUID] UUIDString]];
|
||||
|
||||
[self persistAnonymousID:result];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
+ (NSString *)attributionID
|
||||
{
|
||||
#if TARGET_OS_TV
|
||||
return nil;
|
||||
#else
|
||||
return [[UIPasteboard pasteboardWithName:@"fb_app_attribution" create:NO] string];
|
||||
#endif
|
||||
}
|
||||
|
||||
// for tests only.
|
||||
+ (void)clearLibraryFiles
|
||||
{
|
||||
[[NSFileManager defaultManager] removeItemAtPath:[[self class] persistenceFilePath:FBSDK_APPEVENTSUTILITY_ANONYMOUSIDFILENAME]
|
||||
error:NULL];
|
||||
[[NSFileManager defaultManager] removeItemAtPath:[[self class] persistenceFilePath:FBSDKTimeSpentFilename]
|
||||
error:NULL];
|
||||
}
|
||||
|
||||
+ (void)ensureOnMainThread:(NSString *)methodName className:(NSString *)className
|
||||
{
|
||||
FBSDKConditionalLog([NSThread isMainThread],
|
||||
FBSDKLoggingBehaviorDeveloperErrors,
|
||||
@"*** <%@, %@> is not called on the main thread. This can lead to errors.",
|
||||
methodName,
|
||||
className);
|
||||
}
|
||||
|
||||
+ (NSString *)flushReasonToString:(FBSDKAppEventsFlushReason)flushReason
|
||||
{
|
||||
NSString *result = @"Unknown";
|
||||
switch (flushReason) {
|
||||
case FBSDKAppEventsFlushReasonExplicit:
|
||||
result = @"Explicit";
|
||||
break;
|
||||
case FBSDKAppEventsFlushReasonTimer:
|
||||
result = @"Timer";
|
||||
break;
|
||||
case FBSDKAppEventsFlushReasonSessionChange:
|
||||
result = @"SessionChange";
|
||||
break;
|
||||
case FBSDKAppEventsFlushReasonPersistedEvents:
|
||||
result = @"PersistedEvents";
|
||||
break;
|
||||
case FBSDKAppEventsFlushReasonEventThreshold:
|
||||
result = @"EventCountThreshold";
|
||||
break;
|
||||
case FBSDKAppEventsFlushReasonEagerlyFlushingEvent:
|
||||
result = @"EagerlyFlushingEvent";
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
+ (void)logAndNotify:(NSString *)msg
|
||||
{
|
||||
[[self class] logAndNotify:msg allowLogAsDeveloperError:YES];
|
||||
}
|
||||
|
||||
+ (void)logAndNotify:(NSString *)msg allowLogAsDeveloperError:(BOOL)allowLogAsDeveloperError
|
||||
{
|
||||
NSString *behaviorToLog = FBSDKLoggingBehaviorAppEvents;
|
||||
if (allowLogAsDeveloperError) {
|
||||
if ([[FBSDKSettings loggingBehavior] containsObject:FBSDKLoggingBehaviorDeveloperErrors]) {
|
||||
// Rather than log twice, prefer 'DeveloperErrors' if it's set over AppEvents.
|
||||
behaviorToLog = FBSDKLoggingBehaviorDeveloperErrors;
|
||||
}
|
||||
}
|
||||
|
||||
[FBSDKLogger singleShotLogEntry:behaviorToLog logEntry:msg];
|
||||
NSError *error = [FBSDKError errorWithCode:FBSDKAppEventsFlushErrorCode message:msg];
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:FBSDKAppEventsLoggingResultNotification object:error];
|
||||
}
|
||||
|
||||
+ (BOOL)regexValidateIdentifier:(NSString *)identifier
|
||||
{
|
||||
static NSRegularExpression *regex;
|
||||
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];
|
||||
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) {
|
||||
[cachedIdentifiers addObject:identifier];
|
||||
} else {
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
+ (BOOL)validateIdentifier:(NSString *)identifier
|
||||
{
|
||||
if (identifier == nil || identifier.length == 0 || identifier.length > FBSDK_APPEVENTSUTILITY_MAX_IDENTIFIER_LENGTH || ![[self class] regexValidateIdentifier:identifier]) {
|
||||
[[self class] logAndNotify:[NSString stringWithFormat:@"Invalid identifier: '%@'. Must be between 1 and %d characters, and must be contain only alphanumerics, _, - or spaces, starting with alphanumeric or _.",
|
||||
identifier, FBSDK_APPEVENTSUTILITY_MAX_IDENTIFIER_LENGTH]];
|
||||
return NO;
|
||||
}
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
+ (void)persistAnonymousID:(NSString *)anonymousID
|
||||
{
|
||||
[[self class] ensureOnMainThread:NSStringFromSelector(_cmd) className:NSStringFromClass(self)];
|
||||
NSDictionary *data = @{ FBSDK_APPEVENTSUTILITY_ANONYMOUSID_KEY : anonymousID };
|
||||
NSString *content = [FBSDKInternalUtility JSONStringForObject:data error:NULL invalidObjectHandler:NULL];
|
||||
|
||||
[content writeToFile:[[self class] persistenceFilePath:FBSDK_APPEVENTSUTILITY_ANONYMOUSIDFILENAME]
|
||||
atomically:YES
|
||||
encoding:NSASCIIStringEncoding
|
||||
error:nil];
|
||||
}
|
||||
|
||||
+ (NSString *)persistenceFilePath:(NSString *)filename
|
||||
{
|
||||
NSSearchPathDirectory directory = NSLibraryDirectory;
|
||||
NSArray *paths = NSSearchPathForDirectoriesInDomains(directory, NSUserDomainMask, YES);
|
||||
NSString *docDirectory = [paths objectAtIndex:0];
|
||||
return [docDirectory stringByAppendingPathComponent:filename];
|
||||
}
|
||||
|
||||
+ (NSString *)retrievePersistedAnonymousID
|
||||
{
|
||||
[[self class] ensureOnMainThread:NSStringFromSelector(_cmd) className:NSStringFromClass(self)];
|
||||
NSString *file = [[self class] persistenceFilePath:FBSDK_APPEVENTSUTILITY_ANONYMOUSIDFILENAME];
|
||||
NSString *content = [[NSString alloc] initWithContentsOfFile:file
|
||||
encoding:NSASCIIStringEncoding
|
||||
error:nil];
|
||||
NSDictionary *results = [FBSDKInternalUtility objectForJSONString:content error:NULL];
|
||||
return [results objectForKey:FBSDK_APPEVENTSUTILITY_ANONYMOUSID_KEY];
|
||||
}
|
||||
|
||||
// Given a candidate token (which may be nil), find the real token to string to use.
|
||||
// Precedence: 1) provided token, 2) current token, 3) app | client token, 4) fully anonymous session.
|
||||
+ (NSString *)tokenStringToUseFor:(FBSDKAccessToken *)token
|
||||
{
|
||||
if (!token) {
|
||||
token = [FBSDKAccessToken currentAccessToken];
|
||||
}
|
||||
|
||||
NSString *appID = [FBSDKAppEvents loggingOverrideAppID] ?: token.appID ?: [FBSDKSettings appID];
|
||||
NSString *tokenString = token.tokenString;
|
||||
if (!tokenString || ![appID isEqualToString:token.appID]) {
|
||||
// If there's an logging override app id present, then we don't want to use the client token since the client token
|
||||
// is intended to match up with the primary app id (and AppEvents doesn't require a client token).
|
||||
NSString *clientTokenString = [FBSDKSettings clientToken];
|
||||
if (clientTokenString && appID && [appID isEqualToString:token.appID]){
|
||||
tokenString = [NSString stringWithFormat:@"%@|%@", appID, clientTokenString];
|
||||
} else if (appID) {
|
||||
tokenString = nil;
|
||||
}
|
||||
}
|
||||
return tokenString;
|
||||
}
|
||||
|
||||
+ (long)unixTimeNow
|
||||
{
|
||||
return (long)round([[NSDate date] timeIntervalSince1970]);
|
||||
}
|
||||
|
||||
- (instancetype)init
|
||||
{
|
||||
FBSDK_NO_DESIGNATED_INITIALIZER();
|
||||
return nil;
|
||||
}
|
||||
|
||||
@end
|
||||
Generated
+25
@@ -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>
|
||||
|
||||
// Class to encapsulate implicit logging of purchase events
|
||||
@interface FBSDKPaymentObserver : NSObject
|
||||
+ (void)startObservingTransactions;
|
||||
+ (void)stopObservingTransactions;
|
||||
@end
|
||||
Generated
+281
@@ -0,0 +1,281 @@
|
||||
// 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 "FBSDKPaymentObserver.h"
|
||||
|
||||
#import <StoreKit/StoreKit.h>
|
||||
|
||||
#import "FBSDKAppEvents+Internal.h"
|
||||
#import "FBSDKDynamicFrameworkLoader.h"
|
||||
#import "FBSDKLogger.h"
|
||||
#import "FBSDKSettings.h"
|
||||
|
||||
static NSString *const FBSDKAppEventParameterImplicitlyLoggedPurchase = @"_implicitlyLoggedPurchaseEvent";
|
||||
static NSString *const FBSDKAppEventNamePurchaseFailed = @"fb_mobile_purchase_failed";
|
||||
static NSString *const FBSDKAppEventParameterNameProductTitle = @"fb_content_title";
|
||||
static NSString *const FBSDKAppEventParameterNameTransactionID = @"fb_transaction_id";
|
||||
static int const FBSDKMaxParameterValueLength = 100;
|
||||
static NSMutableArray *g_pendingRequestors;
|
||||
|
||||
@interface FBSDKPaymentProductRequestor : NSObject<SKProductsRequestDelegate>
|
||||
|
||||
@property (nonatomic, retain) SKPaymentTransaction *transaction;
|
||||
|
||||
- (instancetype)initWithTransaction:(SKPaymentTransaction*)transaction;
|
||||
- (void)resolveProducts;
|
||||
|
||||
@end
|
||||
|
||||
@interface FBSDKPaymentObserver() <SKPaymentTransactionObserver>
|
||||
@end
|
||||
|
||||
@implementation FBSDKPaymentObserver
|
||||
{
|
||||
BOOL _observingTransactions;
|
||||
}
|
||||
|
||||
+ (void)startObservingTransactions
|
||||
{
|
||||
[[self singleton] startObservingTransactions];
|
||||
}
|
||||
|
||||
+ (void)stopObservingTransactions
|
||||
{
|
||||
[[self singleton] stopObservingTransactions];
|
||||
}
|
||||
|
||||
//
|
||||
// Internal methods
|
||||
//
|
||||
|
||||
+ (FBSDKPaymentObserver *)singleton
|
||||
{
|
||||
static dispatch_once_t pred;
|
||||
static FBSDKPaymentObserver *shared = nil;
|
||||
|
||||
dispatch_once(&pred, ^{
|
||||
shared = [[FBSDKPaymentObserver alloc] init];
|
||||
});
|
||||
return shared;
|
||||
}
|
||||
|
||||
- (instancetype) init
|
||||
{
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_observingTransactions = NO;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)startObservingTransactions
|
||||
{
|
||||
@synchronized (self) {
|
||||
if (!_observingTransactions) {
|
||||
[(SKPaymentQueue *)[fbsdkdfl_SKPaymentQueueClass() defaultQueue] addTransactionObserver:self];
|
||||
_observingTransactions = YES;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)stopObservingTransactions
|
||||
{
|
||||
@synchronized (self) {
|
||||
if (_observingTransactions) {
|
||||
[(SKPaymentQueue *)[fbsdkdfl_SKPaymentQueueClass() defaultQueue] removeTransactionObserver:self];
|
||||
_observingTransactions = NO;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions
|
||||
{
|
||||
for (SKPaymentTransaction *transaction in transactions) {
|
||||
switch (transaction.transactionState) {
|
||||
case SKPaymentTransactionStatePurchasing:
|
||||
case SKPaymentTransactionStatePurchased:
|
||||
case SKPaymentTransactionStateFailed:
|
||||
[self handleTransaction:transaction];
|
||||
break;
|
||||
case SKPaymentTransactionStateDeferred:
|
||||
case SKPaymentTransactionStateRestored:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)handleTransaction:(SKPaymentTransaction *)transaction
|
||||
{
|
||||
FBSDKPaymentProductRequestor *productRequest = [[FBSDKPaymentProductRequestor alloc] initWithTransaction:transaction];
|
||||
[productRequest resolveProducts];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@interface FBSDKPaymentProductRequestor()
|
||||
@property (nonatomic, retain) SKProductsRequest *productRequest;
|
||||
@end
|
||||
|
||||
@implementation FBSDKPaymentProductRequestor
|
||||
|
||||
+ (void)initialize
|
||||
{
|
||||
if ([self class] == [FBSDKPaymentProductRequestor class]) {
|
||||
g_pendingRequestors = [[NSMutableArray alloc] init];
|
||||
}
|
||||
}
|
||||
|
||||
- (instancetype)initWithTransaction:(SKPaymentTransaction*)transaction
|
||||
{
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_transaction = transaction;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)setProductRequest:(SKProductsRequest *)productRequest
|
||||
{
|
||||
if (productRequest != _productRequest) {
|
||||
if (_productRequest) {
|
||||
_productRequest.delegate = nil;
|
||||
}
|
||||
_productRequest = productRequest;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)resolveProducts
|
||||
{
|
||||
NSString *productId = self.transaction.payment.productIdentifier;
|
||||
NSSet *productIdentifiers = [NSSet setWithObjects:productId, nil];
|
||||
self.productRequest = [[fbsdkdfl_SKProductsRequestClass() alloc] initWithProductIdentifiers:productIdentifiers];
|
||||
self.productRequest.delegate = self;
|
||||
@synchronized(g_pendingRequestors) {
|
||||
[g_pendingRequestors addObject:self];
|
||||
}
|
||||
[self.productRequest start];
|
||||
}
|
||||
|
||||
- (NSString *)getTruncatedString:(NSString *)inputString
|
||||
{
|
||||
if (!inputString) {
|
||||
return @"";
|
||||
}
|
||||
|
||||
return [inputString length] <= FBSDKMaxParameterValueLength ? inputString : [inputString substringToIndex:FBSDKMaxParameterValueLength];
|
||||
}
|
||||
|
||||
- (void)logTransactionEvent:(SKProduct *)product
|
||||
{
|
||||
NSString *eventName = nil;
|
||||
NSString *transactionID = nil;
|
||||
switch (self.transaction.transactionState) {
|
||||
case SKPaymentTransactionStatePurchasing:
|
||||
eventName = FBSDKAppEventNameInitiatedCheckout;
|
||||
break;
|
||||
case SKPaymentTransactionStatePurchased:
|
||||
eventName = FBSDKAppEventNamePurchased;
|
||||
transactionID = self.transaction.transactionIdentifier;
|
||||
break;
|
||||
case SKPaymentTransactionStateFailed:
|
||||
eventName = FBSDKAppEventNamePurchaseFailed;
|
||||
break;
|
||||
case SKPaymentTransactionStateDeferred:
|
||||
case SKPaymentTransactionStateRestored:
|
||||
return;
|
||||
}
|
||||
if (!eventName) {
|
||||
[FBSDKLogger singleShotLogEntry:FBSDKLoggingBehaviorAppEvents
|
||||
formatString:@"FBSDKPaymentObserver logTransactionEvent: event name cannot be nil"];
|
||||
return;
|
||||
}
|
||||
|
||||
SKPayment *payment = self.transaction.payment;
|
||||
NSMutableDictionary *eventParameters = [NSMutableDictionary dictionaryWithDictionary: @{
|
||||
FBSDKAppEventParameterNameContentID: payment.productIdentifier ?: @"",
|
||||
FBSDKAppEventParameterNameNumItems: @(payment.quantity),
|
||||
}];
|
||||
double totalAmount = 0;
|
||||
if (product) {
|
||||
totalAmount = payment.quantity * product.price.doubleValue;
|
||||
[eventParameters addEntriesFromDictionary: @{
|
||||
FBSDKAppEventParameterNameCurrency: [product.priceLocale objectForKey:NSLocaleCurrencyCode],
|
||||
FBSDKAppEventParameterNameNumItems: @(payment.quantity),
|
||||
FBSDKAppEventParameterNameProductTitle: [self getTruncatedString:product.localizedTitle],
|
||||
FBSDKAppEventParameterNameDescription: [self getTruncatedString:product.localizedDescription],
|
||||
}];
|
||||
if (transactionID) {
|
||||
[eventParameters setObject:transactionID forKey:FBSDKAppEventParameterNameTransactionID];
|
||||
}
|
||||
}
|
||||
|
||||
[self logImplicitPurchaseEvent:eventName
|
||||
valueToSum:totalAmount
|
||||
parameters:eventParameters];
|
||||
}
|
||||
|
||||
- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response
|
||||
{
|
||||
NSArray* products = response.products;
|
||||
NSArray* invalidProductIdentifiers = response.invalidProductIdentifiers;
|
||||
if (products.count + invalidProductIdentifiers.count != 1) {
|
||||
[FBSDKLogger singleShotLogEntry:FBSDKLoggingBehaviorAppEvents
|
||||
formatString:@"FBSDKPaymentObserver: Expect to resolve one product per request"];
|
||||
}
|
||||
SKProduct *product = nil;
|
||||
if (products.count) {
|
||||
product = products[0];
|
||||
}
|
||||
[self logTransactionEvent:product];
|
||||
}
|
||||
|
||||
- (void)requestDidFinish:(SKRequest *)request
|
||||
{
|
||||
[self cleanUp];
|
||||
}
|
||||
|
||||
- (void)request:(SKRequest *)request didFailWithError:(NSError *)error
|
||||
{
|
||||
[self logTransactionEvent:nil];
|
||||
[self cleanUp];
|
||||
}
|
||||
|
||||
- (void)cleanUp
|
||||
{
|
||||
@synchronized(g_pendingRequestors) {
|
||||
[g_pendingRequestors removeObject:self];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)logImplicitPurchaseEvent:(NSString *)eventName
|
||||
valueToSum:(double)valueToSum
|
||||
parameters:(NSDictionary *)parameters {
|
||||
NSMutableDictionary *eventParameters = [NSMutableDictionary dictionaryWithDictionary:parameters];
|
||||
[eventParameters setObject:@"1" forKey:FBSDKAppEventParameterImplicitlyLoggedPurchase];
|
||||
[FBSDKAppEvents logEvent:eventName
|
||||
valueToSum:valueToSum
|
||||
parameters:parameters];
|
||||
|
||||
// Unless the behavior is set to only allow explicit flushing, we go ahead and flush, since purchase events
|
||||
// are relatively rare and relatively high value and worth getting across on wire right away.
|
||||
if ([FBSDKAppEvents flushBehavior] != FBSDKAppEventsFlushBehaviorExplicitOnly) {
|
||||
[[FBSDKAppEvents singleton] flushForReason:FBSDKAppEventsFlushReasonEagerlyFlushingEvent];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
Generated
+36
@@ -0,0 +1,36 @@
|
||||
// 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/FBSDKMacros.h>
|
||||
|
||||
FBSDK_EXTERN NSString *const FBSDKTimeSpentFilename;
|
||||
|
||||
// Class to encapsulate persisting of time spent data collected by [FBSDKAppEvents activateApp]. The activate app App Event is
|
||||
// logged when restore: is called with sufficient time since the last deactivation.
|
||||
@interface FBSDKTimeSpentData : NSObject
|
||||
|
||||
+ (void)suspend;
|
||||
+ (void)restore:(BOOL)calledFromActivateApp;
|
||||
|
||||
+ (void)setSourceApplication:(NSString *)sourceApplication openURL:(NSURL *)url;
|
||||
+ (void)setSourceApplication:(NSString *)sourceApplication isFromAppLink:(BOOL)isFromAppLink;
|
||||
+ (void)registerAutoResetSourceApplication;
|
||||
|
||||
@end
|
||||
Generated
+305
@@ -0,0 +1,305 @@
|
||||
// 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 "FBSDKTimeSpentData.h"
|
||||
|
||||
#import "FBSDKAppEvents+Internal.h"
|
||||
#import "FBSDKAppEventsUtility.h"
|
||||
#import "FBSDKInternalUtility.h"
|
||||
#import "FBSDKLogger.h"
|
||||
#import "FBSDKSettings.h"
|
||||
|
||||
|
||||
// Filename and keys for session length
|
||||
NSString *const FBSDKTimeSpentFilename = @"com-facebook-sdk-AppEventsTimeSpent.json";
|
||||
static NSString *const FBSDKTimeSpentPersistKeySessionSecondsSpent = @"secondsSpentInCurrentSession";
|
||||
static NSString *const FBSDKTimeSpentPersistKeySessionNumInterruptions = @"numInterruptions";
|
||||
static NSString *const FBSDKTimeSpentPersistKeyLastSuspendTime = @"lastSuspendTime";
|
||||
|
||||
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 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;
|
||||
|
||||
static NSString *g_sourceApplication;
|
||||
static BOOL g_isOpenedFromAppLink;
|
||||
|
||||
// Will be translated and displayed in App Insights. Need to maintain same number and value of quanta on the server.
|
||||
static const long INACTIVE_SECONDS_QUANTA[] =
|
||||
{
|
||||
5 * SECS_PER_MIN,
|
||||
15 * SECS_PER_MIN,
|
||||
30 * SECS_PER_MIN,
|
||||
1 * SECS_PER_HOUR,
|
||||
6 * SECS_PER_HOUR,
|
||||
12 * SECS_PER_HOUR,
|
||||
1 * SECS_PER_DAY,
|
||||
2 * SECS_PER_DAY,
|
||||
3 * SECS_PER_DAY,
|
||||
7 * SECS_PER_DAY,
|
||||
14 * SECS_PER_DAY,
|
||||
21 * SECS_PER_DAY,
|
||||
28 * SECS_PER_DAY,
|
||||
60 * SECS_PER_DAY,
|
||||
90 * SECS_PER_DAY,
|
||||
120 * SECS_PER_DAY,
|
||||
150 * SECS_PER_DAY,
|
||||
180 * SECS_PER_DAY,
|
||||
365 * SECS_PER_DAY,
|
||||
LONG_MAX, // keep as LONG_MAX to guarantee loop will terminate
|
||||
};
|
||||
|
||||
/**
|
||||
* This class encapsulates the notion of an app 'session' - the length of time that the user has
|
||||
* spent in the app that can be considered a single usage of the app. Apps may be frequently interrupted
|
||||
* do to other device activity, like a text message, so this class allows those interruptions to be smoothed
|
||||
* out and the time actually spent in the app excluding this interruption time to be accumulated. Also,
|
||||
* once a certain amount of time has gone by where the app is not in the foreground, we consider the
|
||||
* session to be complete, and a new session beginning. When this occurs, we log an 'activate app' event
|
||||
* 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;
|
||||
BOOL _shouldLogActivateEvent;
|
||||
BOOL _shouldLogDeactivateEvent;
|
||||
long _secondsSpentInCurrentSession;
|
||||
long _timeSinceLastSuspend;
|
||||
int _numInterruptionsInCurrentSession;
|
||||
long _lastRestoreTime;
|
||||
}
|
||||
|
||||
//
|
||||
// Public methods
|
||||
//
|
||||
|
||||
+ (void)suspend
|
||||
{
|
||||
[self.singleton instanceSuspend];
|
||||
}
|
||||
|
||||
+ (void)restore:(BOOL)calledFromActivateApp
|
||||
{
|
||||
[self.singleton instanceRestore:calledFromActivateApp];
|
||||
}
|
||||
|
||||
//
|
||||
// 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;
|
||||
static FBSDKTimeSpentData *shared = nil;
|
||||
|
||||
dispatch_once(&pred, ^{
|
||||
shared = [[FBSDKTimeSpentData alloc] init];
|
||||
});
|
||||
return shared;
|
||||
}
|
||||
|
||||
// Calculate and persist time spent data for this instance of the app activation.
|
||||
- (void)instanceSuspend
|
||||
{
|
||||
|
||||
[FBSDKAppEventsUtility ensureOnMainThread:NSStringFromSelector(_cmd) className:NSStringFromClass([self class])];
|
||||
if (!_isCurrentlyLoaded) {
|
||||
FBSDKConditionalLog(YES, FBSDKLoggingBehaviorInformational, @"[FBSDKTimeSpentData suspend] invoked without corresponding restore");
|
||||
return;
|
||||
}
|
||||
|
||||
long now = [FBSDKAppEventsUtility unixTimeNow];
|
||||
long timeSinceRestore = now - _lastRestoreTime;
|
||||
|
||||
// Can happen if the clock on the device is changed
|
||||
if (timeSinceRestore < 0) {
|
||||
[FBSDKLogger singleShotLogEntry:FBSDKLoggingBehaviorAppEvents
|
||||
formatString:@"Clock skew detected"];
|
||||
timeSinceRestore = 0;
|
||||
}
|
||||
|
||||
_secondsSpentInCurrentSession += timeSinceRestore;
|
||||
|
||||
NSDictionary *timeSpentData =
|
||||
@{
|
||||
FBSDKTimeSpentPersistKeySessionSecondsSpent : @(_secondsSpentInCurrentSession),
|
||||
FBSDKTimeSpentPersistKeySessionNumInterruptions : @(_numInterruptionsInCurrentSession),
|
||||
FBSDKTimeSpentPersistKeyLastSuspendTime : @(now)
|
||||
};
|
||||
|
||||
NSString *content = [FBSDKInternalUtility JSONStringForObject:timeSpentData error:NULL invalidObjectHandler:NULL];
|
||||
|
||||
[content writeToFile:[FBSDKAppEventsUtility persistenceFilePath:FBSDKTimeSpentFilename]
|
||||
atomically:YES
|
||||
encoding:NSASCIIStringEncoding
|
||||
error:nil];
|
||||
|
||||
[FBSDKLogger singleShotLogEntry:FBSDKLoggingBehaviorAppEvents
|
||||
formatString:@"FBSDKTimeSpentData Persist: %@", content];
|
||||
|
||||
_isCurrentlyLoaded = NO;
|
||||
}
|
||||
|
||||
|
||||
// Called during activation - either through an explicit 'activateApp' call or implicitly when the app is foregrounded.
|
||||
// In both cases, we restore the persisted event data. In the case of the activateApp, we log an 'app activated'
|
||||
// event if there's been enough time between the last deactivation and now.
|
||||
- (void)instanceRestore:(BOOL)calledFromActivateApp
|
||||
{
|
||||
|
||||
[FBSDKAppEventsUtility ensureOnMainThread:NSStringFromSelector(_cmd) className:NSStringFromClass([self class])];
|
||||
|
||||
// It's possible to call this multiple times during the time the app is in the foreground. If this is the case,
|
||||
// just restore persisted data the first time.
|
||||
if (!_isCurrentlyLoaded) {
|
||||
|
||||
NSString *content =
|
||||
[[NSString alloc] initWithContentsOfFile:[FBSDKAppEventsUtility persistenceFilePath:FBSDKTimeSpentFilename]
|
||||
usedEncoding:nil
|
||||
error:nil];
|
||||
|
||||
[FBSDKLogger singleShotLogEntry:FBSDKLoggingBehaviorAppEvents
|
||||
formatString:@"FBSDKTimeSpentData Restore: %@", content];
|
||||
|
||||
long now = [FBSDKAppEventsUtility unixTimeNow];
|
||||
if (!content) {
|
||||
|
||||
// Nothing persisted, so this is the first launch.
|
||||
_secondsSpentInCurrentSession = 0;
|
||||
_numInterruptionsInCurrentSession = 0;
|
||||
|
||||
// We want to log the app activation event on the first launch, but not the deactivate event
|
||||
_shouldLogActivateEvent = YES;
|
||||
_shouldLogDeactivateEvent = NO;
|
||||
|
||||
} else {
|
||||
|
||||
NSDictionary *results = [FBSDKInternalUtility objectForJSONString:content error:NULL];
|
||||
|
||||
long lastActiveTime = [[results objectForKey:FBSDKTimeSpentPersistKeyLastSuspendTime] longValue];
|
||||
|
||||
_timeSinceLastSuspend = now - lastActiveTime;
|
||||
_secondsSpentInCurrentSession = [[results objectForKey:FBSDKTimeSpentPersistKeySessionSecondsSpent] intValue];
|
||||
_numInterruptionsInCurrentSession = [[results objectForKey:FBSDKTimeSpentPersistKeySessionNumInterruptions] intValue];
|
||||
_shouldLogActivateEvent = (_timeSinceLastSuspend > _numSecondsIdleToBeNewSession);
|
||||
|
||||
// Other than the first launch, we always log the last session's deactivate with this session's activate.
|
||||
_shouldLogDeactivateEvent = _shouldLogActivateEvent;
|
||||
|
||||
if (!_shouldLogDeactivateEvent) {
|
||||
// If we're not logging, then the time we spent deactivated is considered another interruption. But cap it
|
||||
// so errant or test uses doesn't blow out the cardinality on the backend processing
|
||||
_numInterruptionsInCurrentSession = MIN(_numInterruptionsInCurrentSession + 1, 200);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
_lastRestoreTime = now;
|
||||
_isCurrentlyLoaded = YES;
|
||||
|
||||
if (calledFromActivateApp) {
|
||||
|
||||
if (_shouldLogActivateEvent) {
|
||||
[FBSDKAppEvents logEvent:FBSDKAppEventNameActivatedApp
|
||||
parameters:@{
|
||||
FBSDKAppEventParameterLaunchSource: [[self class] getSourceApplication]
|
||||
}];
|
||||
}
|
||||
|
||||
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],
|
||||
}
|
||||
];
|
||||
|
||||
// We've logged the session stats, now reset.
|
||||
_secondsSpentInCurrentSession = 0;
|
||||
_numInterruptionsInCurrentSession = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+ (void)setSourceApplication:(NSString *)sourceApplication openURL:(NSURL *)url
|
||||
{
|
||||
[self setSourceApplication:sourceApplication
|
||||
isFromAppLink:[FBSDKInternalUtility dictionaryFromFBURL:url][@"al_applink_data"] != nil];
|
||||
}
|
||||
|
||||
+ (void)setSourceApplication:(NSString *)sourceApplication isFromAppLink:(BOOL)isFromAppLink
|
||||
{
|
||||
g_isOpenedFromAppLink = isFromAppLink;
|
||||
g_sourceApplication = sourceApplication;
|
||||
}
|
||||
|
||||
+ (NSString *)getSourceApplication
|
||||
{
|
||||
NSString *openType = @"Unclassified";
|
||||
if (g_isOpenedFromAppLink) {
|
||||
openType = @"AppLink";
|
||||
}
|
||||
return (g_sourceApplication ?
|
||||
[NSString stringWithFormat:@"%@(%@)", openType, g_sourceApplication]
|
||||
: openType);
|
||||
}
|
||||
|
||||
+ (void)resetSourceApplication
|
||||
{
|
||||
g_sourceApplication = nil;
|
||||
g_isOpenedFromAppLink = NO;
|
||||
}
|
||||
|
||||
+ (void)registerAutoResetSourceApplication
|
||||
{
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(resetSourceApplication)
|
||||
name:UIApplicationDidEnterBackgroundNotification
|
||||
object:nil];
|
||||
}
|
||||
|
||||
@end
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
// 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>
|
||||
|
||||
@interface FBSDKBoltsMeasurementEventListener : NSObject
|
||||
+ (FBSDKBoltsMeasurementEventListener *)defaultListener;
|
||||
@end
|
||||
+78
@@ -0,0 +1,78 @@
|
||||
// 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 "FBSDKBoltsMeasurementEventListener.h"
|
||||
|
||||
#import "FBSDKAppEvents+Internal.h"
|
||||
#import "FBSDKTimeSpentData.h"
|
||||
|
||||
static NSString *const BoltsMeasurementEventNotificationName = @"com.parse.bolts.measurement_event";
|
||||
static NSString *const BoltsMeasurementEventName = @"event_name";
|
||||
static NSString *const BoltsMeasurementEventArgs = @"event_args";
|
||||
static NSString *const BoltsMeasurementEventPrefix = @"bf_";
|
||||
|
||||
@implementation FBSDKBoltsMeasurementEventListener
|
||||
|
||||
+ (instancetype)defaultListener
|
||||
{
|
||||
static dispatch_once_t dispatchOnceLocker = 0;
|
||||
static FBSDKBoltsMeasurementEventListener *defaultListener = nil;
|
||||
dispatch_once(&dispatchOnceLocker, ^{
|
||||
defaultListener = [[self alloc] init];
|
||||
NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
|
||||
[center addObserver:defaultListener
|
||||
selector:@selector(logFBAppEventForNotification:)
|
||||
name:BoltsMeasurementEventNotificationName
|
||||
object:nil];
|
||||
});
|
||||
return defaultListener;
|
||||
}
|
||||
|
||||
- (void)logFBAppEventForNotification:(NSNotification *)note
|
||||
{
|
||||
// when catch al_nav_in event, we set source application for FBAppEvents.
|
||||
if ([note.userInfo[BoltsMeasurementEventName] isEqualToString:@"al_nav_in"]) {
|
||||
NSString *sourceApplication = note.userInfo[BoltsMeasurementEventArgs][@"sourceApplication"];
|
||||
if (sourceApplication) {
|
||||
[FBSDKTimeSpentData setSourceApplication:sourceApplication isFromAppLink:YES];
|
||||
}
|
||||
}
|
||||
NSDictionary *eventArgs = note.userInfo[BoltsMeasurementEventArgs];
|
||||
NSMutableDictionary *logData = [[NSMutableDictionary alloc] init];
|
||||
for(NSString *key in eventArgs.allKeys) {
|
||||
NSError *error = nil;
|
||||
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"[^0-9a-zA-Z _-]" options:0 error:&error];
|
||||
NSString *safeKey = [regex stringByReplacingMatchesInString:key
|
||||
options:0
|
||||
range:NSMakeRange(0, [key length])
|
||||
withTemplate:@"-"];
|
||||
safeKey = [safeKey stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@" -"]];
|
||||
logData[safeKey] = eventArgs[key];
|
||||
}
|
||||
[FBSDKAppEvents logImplicitEvent:[BoltsMeasurementEventPrefix stringByAppendingString:note.userInfo[BoltsMeasurementEventName]]
|
||||
valueToSum:nil
|
||||
parameters:logData
|
||||
accessToken:nil];
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||
}
|
||||
|
||||
@end
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
// 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>
|
||||
|
||||
@interface FBSDKBase64 : NSObject
|
||||
|
||||
/*!
|
||||
@abstract Decodes a base-64 encoded string.
|
||||
@param string The base-64 encoded string.
|
||||
@return NSData containing the decoded bytes.
|
||||
*/
|
||||
+ (NSData *)decodeAsData:(NSString *)string;
|
||||
|
||||
/*!
|
||||
@abstract Decodes a base-64 encoded string into a string.
|
||||
@param string The base-64 encoded string.
|
||||
@return NSString with the decoded UTF-8 value.
|
||||
*/
|
||||
+ (NSString *)decodeAsString:(NSString *)string;
|
||||
|
||||
/*!
|
||||
@abstract Encodes data into a string.
|
||||
@param data The data to be encoded.
|
||||
@return The base-64 encoded string.
|
||||
*/
|
||||
+ (NSString *)encodeData:(NSData *)data;
|
||||
|
||||
/*!
|
||||
@abstract Encodes string into a base-64 representation.
|
||||
@param string The string to be encoded.
|
||||
@return The base-64 encoded string.
|
||||
*/
|
||||
+ (NSString *)encodeString:(NSString *)string;
|
||||
|
||||
@end
|
||||
+133
@@ -0,0 +1,133 @@
|
||||
// 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 "FBSDKBase64.h"
|
||||
|
||||
#import "FBSDKMacros.h"
|
||||
|
||||
@implementation FBSDKBase64
|
||||
{
|
||||
BOOL _optionsEnabled;
|
||||
}
|
||||
|
||||
static FBSDKBase64 *_decoder;
|
||||
static FBSDKBase64 *_encoder;
|
||||
|
||||
#pragma mark - Class Methods
|
||||
|
||||
+ (void)initialize
|
||||
{
|
||||
if (self == [FBSDKBase64 class]) {
|
||||
BOOL optionsEnabled;
|
||||
optionsEnabled = [NSData instancesRespondToSelector:@selector(initWithBase64EncodedString:options:)];
|
||||
_decoder = [[FBSDKBase64 alloc] initWithOptionsEnabled:optionsEnabled];
|
||||
optionsEnabled = [NSData instancesRespondToSelector:@selector(base64EncodedStringWithOptions:)];
|
||||
_encoder = [[FBSDKBase64 alloc] initWithOptionsEnabled:optionsEnabled];
|
||||
}
|
||||
}
|
||||
|
||||
+ (NSData *)decodeAsData:(NSString *)string
|
||||
{
|
||||
return [_decoder decodeAsData:string];
|
||||
}
|
||||
|
||||
+ (NSString *)decodeAsString:(NSString *)string
|
||||
{
|
||||
return [_decoder decodeAsString:string];
|
||||
}
|
||||
|
||||
+ (NSString *)encodeData:(NSData *)data
|
||||
{
|
||||
return [_encoder encodeData:data];
|
||||
}
|
||||
|
||||
+ (NSString *)encodeString:(NSString *)string
|
||||
{
|
||||
return [_encoder encodeString:string];
|
||||
}
|
||||
|
||||
#pragma mark - Object Lifecycle
|
||||
|
||||
- (instancetype)init
|
||||
{
|
||||
FBSDK_NOT_DESIGNATED_INITIALIZER(initWithOptionsEnabled:);
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (instancetype)initWithOptionsEnabled:(BOOL)optionsEnabled
|
||||
{
|
||||
if ((self = [super init])) {
|
||||
_optionsEnabled = optionsEnabled;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
#pragma mark - Implementation Methods
|
||||
|
||||
- (NSData *)decodeAsData:(NSString *)string
|
||||
{
|
||||
if (!string) {
|
||||
return nil;
|
||||
}
|
||||
// This padding will be appended before stripping unknown characters, so if there are unknown characters of count % 4
|
||||
// it will not be able to decode. Since we assume valid base64 data, we will take this as is.
|
||||
int needPadding = string.length % 4;
|
||||
if (needPadding > 0) {
|
||||
needPadding = 4 - needPadding;
|
||||
string = [string stringByPaddingToLength:string.length+needPadding withString:@"=" startingAtIndex:0];
|
||||
}
|
||||
if (_optionsEnabled) {
|
||||
return [[NSData alloc] initWithBase64EncodedString:string options:NSDataBase64DecodingIgnoreUnknownCharacters];
|
||||
} else {
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||
return [[NSData alloc] initWithBase64Encoding:string];
|
||||
#pragma clang diagnostic pop
|
||||
}
|
||||
}
|
||||
|
||||
- (NSString *)decodeAsString:(NSString *)string
|
||||
{
|
||||
NSData *data = [self decodeAsData:string];
|
||||
if (!data) {
|
||||
return nil;
|
||||
}
|
||||
return [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
|
||||
}
|
||||
|
||||
- (NSString *)encodeData:(NSData *)data
|
||||
{
|
||||
if (!data) {
|
||||
return nil;
|
||||
}
|
||||
if (_optionsEnabled) {
|
||||
return [data base64EncodedStringWithOptions:0];
|
||||
} else {
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||
return [data base64Encoding];
|
||||
#pragma clang diagnostic pop
|
||||
}
|
||||
}
|
||||
|
||||
- (NSString *)encodeString:(NSString *)string
|
||||
{
|
||||
return [self encodeData:[string dataUsingEncoding:NSUTF8StringEncoding]];
|
||||
}
|
||||
|
||||
@end
|
||||
Generated
+31
@@ -0,0 +1,31 @@
|
||||
// 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 "FBSDKBridgeAPIRequest.h"
|
||||
|
||||
@interface FBSDKBridgeAPICrypto : NSObject
|
||||
|
||||
+ (void)addCipherKeyToQueryParameters:(NSMutableDictionary *)queryParameters;
|
||||
+ (NSDictionary *)decryptResponseForRequest:(FBSDKBridgeAPIRequest *)request
|
||||
queryParameters:(NSDictionary *)queryParameters
|
||||
error:(NSError *__autoreleasing *)errorRef;
|
||||
+ (void)reset;
|
||||
|
||||
@end
|
||||
Generated
+139
@@ -0,0 +1,139 @@
|
||||
// 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 "FBSDKBridgeAPICrypto.h"
|
||||
|
||||
#import "FBSDKBridgeAPIProtocol.h"
|
||||
#import "FBSDKConstants.h"
|
||||
#import "FBSDKCrypto.h"
|
||||
#import "FBSDKError.h"
|
||||
#import "FBSDKInternalUtility.h"
|
||||
#import "FBSDKMacros.h"
|
||||
#import "FBSDKSettings.h"
|
||||
#import "FBSDKUtility.h"
|
||||
|
||||
static NSString *const FBSDKBridgeAPICryptoCipherKey = @"cipher";
|
||||
static NSString *const FBSDKBridgeAPICryptoCipherKeyKey = @"cipher_key";
|
||||
static NSString *g_cipherKey = nil;
|
||||
|
||||
@implementation FBSDKBridgeAPICrypto
|
||||
|
||||
#pragma mark - Class Methods
|
||||
|
||||
+ (void)addCipherKeyToQueryParameters:(NSMutableDictionary *)queryParameters
|
||||
{
|
||||
[FBSDKInternalUtility dictionary:queryParameters setObject:[self _cipherKey] forKey:FBSDKBridgeAPICryptoCipherKeyKey];
|
||||
}
|
||||
|
||||
+ (NSDictionary *)decryptResponseForRequest:(FBSDKBridgeAPIRequest *)request
|
||||
queryParameters:(NSDictionary *)queryParameters
|
||||
error:(NSError *__autoreleasing *)errorRef
|
||||
{
|
||||
if (errorRef != NULL) {
|
||||
*errorRef = nil;
|
||||
}
|
||||
NSString *cipher = queryParameters[FBSDKBridgeAPICryptoCipherKey];
|
||||
if (!cipher) {
|
||||
return queryParameters ?: @{};
|
||||
}
|
||||
NSString *version = queryParameters[FBSDKBridgeAPIVersionKey];
|
||||
NSString *cipherKey = [self _cipherKey];
|
||||
if (!version || !cipherKey) {
|
||||
if (errorRef != NULL) {
|
||||
NSDictionary *userInfo = @{
|
||||
FBSDKErrorArgumentValueKey: queryParameters,
|
||||
};
|
||||
*errorRef = [FBSDKError errorWithCode:FBSDKEncryptionErrorCode
|
||||
userInfo:userInfo
|
||||
message:@"Error decrypting incoming query parameters."
|
||||
underlyingError:nil];
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
NSArray *additionalSignedDataArray = @[
|
||||
[[NSBundle mainBundle] bundleIdentifier],
|
||||
[FBSDKSettings appID] ?: @"",
|
||||
@"bridge",
|
||||
request.methodName ?: @"",
|
||||
version,
|
||||
];
|
||||
NSString *additionalSignedDataString = [additionalSignedDataArray componentsJoinedByString:@":"];
|
||||
NSData *additionalSignedData = [additionalSignedDataString dataUsingEncoding:NSUTF8StringEncoding];
|
||||
FBSDKCrypto *crypto = [[FBSDKCrypto alloc] initWithMasterKey:cipherKey];
|
||||
NSData *decryptedData = [crypto decrypt:cipher additionalSignedData:additionalSignedData];
|
||||
if (!decryptedData) {
|
||||
if (errorRef != NULL) {
|
||||
NSDictionary *userInfo = @{
|
||||
FBSDKErrorArgumentValueKey: @{
|
||||
@"cipher": cipher,
|
||||
@"bundleIdentifier": additionalSignedDataArray[0],
|
||||
@"appID": additionalSignedDataArray[1],
|
||||
@"host": additionalSignedDataArray[2],
|
||||
@"methodName": additionalSignedDataArray[3],
|
||||
@"version": additionalSignedDataArray[4],
|
||||
},
|
||||
};
|
||||
*errorRef = [FBSDKError errorWithCode:FBSDKEncryptionErrorCode
|
||||
userInfo:userInfo
|
||||
message:@"Error decrypting incoming query parameters."
|
||||
underlyingError:nil];
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
NSString *decryptedString = [[NSString alloc] initWithData:decryptedData encoding:NSUTF8StringEncoding];
|
||||
NSDictionary *decryptedDictionary = [FBSDKUtility dictionaryWithQueryString:decryptedString];
|
||||
NSMutableDictionary *decryptedQueryParameters = [[NSMutableDictionary alloc] initWithDictionary:decryptedDictionary];
|
||||
decryptedQueryParameters[FBSDKBridgeAPIVersionKey] = version;
|
||||
return [decryptedQueryParameters copy];
|
||||
}
|
||||
|
||||
+ (void)reset
|
||||
{
|
||||
[self _resetCipherKey];
|
||||
}
|
||||
|
||||
#pragma mark - Object Lifecycle
|
||||
|
||||
- (instancetype)init
|
||||
{
|
||||
FBSDK_NO_DESIGNATED_INITIALIZER();
|
||||
return nil;
|
||||
}
|
||||
|
||||
#pragma mark - Helper Methods
|
||||
|
||||
+ (NSString *)_cipherKey
|
||||
{
|
||||
if (g_cipherKey) {
|
||||
return g_cipherKey;
|
||||
}
|
||||
g_cipherKey = [[[NSUserDefaults standardUserDefaults] stringForKey:FBSDKBridgeAPICryptoCipherKeyKey] copy];
|
||||
if (g_cipherKey) {
|
||||
return g_cipherKey;
|
||||
}
|
||||
return [self _resetCipherKey];
|
||||
}
|
||||
|
||||
+ (NSString *)_resetCipherKey
|
||||
{
|
||||
g_cipherKey = [[FBSDKCrypto makeMasterKey] copy];
|
||||
[[NSUserDefaults standardUserDefaults] setObject:g_cipherKey forKey:FBSDKBridgeAPICryptoCipherKeyKey];
|
||||
return g_cipherKey;
|
||||
}
|
||||
|
||||
@end
|
||||
Generated
+44
@@ -0,0 +1,44 @@
|
||||
// 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/FBSDKMacros.h>
|
||||
|
||||
#import "FBSDKBridgeAPIProtocolType.h"
|
||||
|
||||
@class FBSDKBridgeAPIRequest;
|
||||
|
||||
FBSDK_EXTERN NSString *const FBSDKBridgeAPIAppIDKey;
|
||||
FBSDK_EXTERN NSString *const FBSDKBridgeAPISchemeSuffixKey;
|
||||
FBSDK_EXTERN NSString *const FBSDKBridgeAPIVersionKey;
|
||||
|
||||
@protocol FBSDKBridgeAPIProtocol <NSObject>
|
||||
|
||||
- (NSURL *)requestURLWithActionID:(NSString *)actionID
|
||||
scheme:(NSString *)scheme
|
||||
methodName:(NSString *)methodName
|
||||
methodVersion:(NSString *)methodVersion
|
||||
parameters:(NSDictionary *)parameters
|
||||
error:(NSError *__autoreleasing *)errorRef;
|
||||
- (NSDictionary *)responseParametersForActionID:(NSString *)actionID
|
||||
queryParameters:(NSDictionary *)queryParameters
|
||||
cancelled:(BOOL *)cancelledRef
|
||||
error:(NSError *__autoreleasing *)errorRef;
|
||||
|
||||
@end
|
||||
Generated
+25
@@ -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>
|
||||
|
||||
typedef NS_ENUM(NSUInteger, FBSDKBridgeAPIProtocolType)
|
||||
{
|
||||
FBSDKBridgeAPIProtocolTypeNative,
|
||||
FBSDKBridgeAPIProtocolTypeWeb,
|
||||
};
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
// 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 "FBSDKBridgeAPIProtocol.h"
|
||||
#import "FBSDKBridgeAPIRequest.h"
|
||||
|
||||
@interface FBSDKBridgeAPIRequest ()
|
||||
|
||||
- (instancetype)initWithProtocol:(id<FBSDKBridgeAPIProtocol>)protocol
|
||||
protocolType:(FBSDKBridgeAPIProtocolType)protocolType
|
||||
scheme:(NSString *)scheme
|
||||
methodName:(NSString *)methodName
|
||||
methodVersion:(NSString *)methodVersion
|
||||
parameters:(NSDictionary *)parameters
|
||||
userInfo:(NSDictionary *)userInfo
|
||||
NS_DESIGNATED_INITIALIZER;
|
||||
|
||||
@property (nonatomic, strong, readonly) id<FBSDKBridgeAPIProtocol> protocol;
|
||||
|
||||
@end
|
||||
Generated
+44
@@ -0,0 +1,44 @@
|
||||
// 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/FBSDKCopying.h>
|
||||
|
||||
#import "FBSDKBridgeAPIProtocolType.h"
|
||||
|
||||
@interface FBSDKBridgeAPIRequest : NSObject <FBSDKCopying>
|
||||
|
||||
+ (instancetype)bridgeAPIRequestWithProtocolType:(FBSDKBridgeAPIProtocolType)protocolType
|
||||
scheme:(NSString *)scheme
|
||||
methodName:(NSString *)methodName
|
||||
methodVersion:(NSString *)methodVersion
|
||||
parameters:(NSDictionary *)parameters
|
||||
userInfo:(NSDictionary *)userInfo;
|
||||
|
||||
@property (nonatomic, copy, readonly) NSString *actionID;
|
||||
@property (nonatomic, copy, readonly) NSString *methodName;
|
||||
@property (nonatomic, copy, readonly) NSString *methodVersion;
|
||||
@property (nonatomic, copy, readonly) NSDictionary *parameters;
|
||||
@property (nonatomic, assign, readonly) FBSDKBridgeAPIProtocolType protocolType;
|
||||
@property (nonatomic, copy, readonly) NSString *scheme;
|
||||
@property (nonatomic, copy, readonly) NSDictionary *userInfo;
|
||||
|
||||
- (NSURL *)requestURL:(NSError *__autoreleasing *)errorRef;
|
||||
|
||||
@end
|
||||
Generated
+166
@@ -0,0 +1,166 @@
|
||||
// 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 "FBSDKBridgeAPIRequest.h"
|
||||
#import "FBSDKBridgeAPIRequest+Private.h"
|
||||
|
||||
#import "FBSDKBridgeAPICrypto.h"
|
||||
#import "FBSDKBridgeAPIProtocolNativeV1.h"
|
||||
#import "FBSDKBridgeAPIProtocolWebV1.h"
|
||||
#import "FBSDKBridgeAPIProtocolWebV2.h"
|
||||
#import "FBSDKInternalUtility.h"
|
||||
#import "FBSDKMacros.h"
|
||||
#import "FBSDKSettings.h"
|
||||
#import "FBSDKUtility.h"
|
||||
|
||||
NSString *const FBSDKBridgeAPIAppIDKey = @"app_id";
|
||||
NSString *const FBSDKBridgeAPISchemeSuffixKey = @"scheme_suffix";
|
||||
NSString *const FBSDKBridgeAPIVersionKey = @"version";
|
||||
|
||||
@implementation FBSDKBridgeAPIRequest
|
||||
|
||||
#pragma mark - Class Methods
|
||||
|
||||
+ (instancetype)bridgeAPIRequestWithProtocolType:(FBSDKBridgeAPIProtocolType)protocolType
|
||||
scheme:(NSString *)scheme
|
||||
methodName:(NSString *)methodName
|
||||
methodVersion:(NSString *)methodVersion
|
||||
parameters:(NSDictionary *)parameters
|
||||
userInfo:(NSDictionary *)userInfo
|
||||
{
|
||||
return [[self alloc] initWithProtocol:[self _protocolForType:protocolType scheme:scheme]
|
||||
protocolType:protocolType
|
||||
scheme:scheme
|
||||
methodName:methodName
|
||||
methodVersion:methodVersion
|
||||
parameters:parameters
|
||||
userInfo:userInfo];
|
||||
}
|
||||
|
||||
+ (NSDictionary *)protocolMap
|
||||
{
|
||||
static NSDictionary *_protocolMap;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
_protocolMap = @{
|
||||
@(FBSDKBridgeAPIProtocolTypeNative): @{
|
||||
FBSDK_CANOPENURL_FACEBOOK:[[FBSDKBridgeAPIProtocolNativeV1 alloc] initWithAppScheme:@"fbapi20130214"],
|
||||
FBSDK_CANOPENURL_MESSENGER:[[FBSDKBridgeAPIProtocolNativeV1 alloc] initWithAppScheme:@"fb-messenger-api20140430"]
|
||||
},
|
||||
@(FBSDKBridgeAPIProtocolTypeWeb): @{
|
||||
@"https": [[FBSDKBridgeAPIProtocolWebV1 alloc] init],
|
||||
@"web": [[FBSDKBridgeAPIProtocolWebV2 alloc] init]
|
||||
},
|
||||
};
|
||||
});
|
||||
return _protocolMap;
|
||||
}
|
||||
|
||||
#pragma mark - Object Lifecycle
|
||||
|
||||
- (instancetype)initWithProtocol:(id<FBSDKBridgeAPIProtocol>)protocol
|
||||
protocolType:(FBSDKBridgeAPIProtocolType)protocolType
|
||||
scheme:(NSString *)scheme
|
||||
methodName:(NSString *)methodName
|
||||
methodVersion:(NSString *)methodVersion
|
||||
parameters:(NSDictionary *)parameters
|
||||
userInfo:(NSDictionary *)userInfo
|
||||
{
|
||||
if (!protocol) {
|
||||
return nil;
|
||||
}
|
||||
if ((self = [super init])) {
|
||||
_protocol = protocol;
|
||||
_protocolType = protocolType;
|
||||
_scheme = [scheme copy];
|
||||
_methodName = [methodName copy];
|
||||
_methodVersion = [methodVersion copy];
|
||||
_parameters = [parameters copy];
|
||||
_userInfo = [userInfo copy];
|
||||
|
||||
_actionID = [[NSUUID UUID] UUIDString];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (instancetype)init
|
||||
{
|
||||
FBSDK_NOT_DESIGNATED_INITIALIZER(initWithProtocol:protocolType:scheme:methodName:methodVersion:parameters:userInfo:);
|
||||
return [self initWithProtocol:nil
|
||||
protocolType:FBSDKBridgeAPIProtocolTypeWeb
|
||||
scheme:nil
|
||||
methodName:nil
|
||||
methodVersion:nil
|
||||
parameters:nil
|
||||
userInfo:nil];
|
||||
}
|
||||
|
||||
#pragma mark - Public Methods
|
||||
|
||||
- (NSURL *)requestURL:(NSError *__autoreleasing *)errorRef
|
||||
{
|
||||
NSURL *requestURL = [_protocol requestURLWithActionID:self.actionID
|
||||
scheme:self.scheme
|
||||
methodName:self.methodName
|
||||
methodVersion:self.methodVersion
|
||||
parameters:self.parameters
|
||||
error:errorRef];
|
||||
if (!requestURL) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
[FBSDKInternalUtility validateURLSchemes];
|
||||
|
||||
NSDictionary *requestQueryParameters = [FBSDKUtility dictionaryWithQueryString:requestURL.query];
|
||||
NSMutableDictionary *queryParameters = [[NSMutableDictionary alloc] initWithDictionary:requestQueryParameters];
|
||||
[FBSDKBridgeAPICrypto addCipherKeyToQueryParameters:queryParameters];
|
||||
[FBSDKInternalUtility dictionary:queryParameters setObject:[FBSDKSettings appID] forKey:FBSDKBridgeAPIAppIDKey];
|
||||
[FBSDKInternalUtility dictionary:queryParameters
|
||||
setObject:[FBSDKSettings appURLSchemeSuffix]
|
||||
forKey:FBSDKBridgeAPISchemeSuffixKey];
|
||||
requestURL = [FBSDKInternalUtility URLWithScheme:requestURL.scheme
|
||||
host:requestURL.host
|
||||
path:requestURL.path
|
||||
queryParameters:queryParameters
|
||||
error:errorRef];
|
||||
return requestURL;
|
||||
}
|
||||
|
||||
#pragma mark - NSCopying
|
||||
|
||||
- (id)copyWithZone:(NSZone *)zone
|
||||
{
|
||||
return self;
|
||||
}
|
||||
|
||||
+ (id<FBSDKBridgeAPIProtocol>)_protocolForType:(FBSDKBridgeAPIProtocolType)type scheme:(NSString *)scheme
|
||||
{
|
||||
id<FBSDKBridgeAPIProtocol> protocol = [self protocolMap][@(type)][scheme];
|
||||
if (type == FBSDKBridgeAPIProtocolTypeWeb) {
|
||||
return protocol;
|
||||
}
|
||||
NSURLComponents *components = [[NSURLComponents alloc] init];
|
||||
components.scheme = scheme;
|
||||
components.path = @"/";
|
||||
if ([[UIApplication sharedApplication] canOpenURL:components.URL]) {
|
||||
return protocol;
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
@end
|
||||
Generated
+39
@@ -0,0 +1,39 @@
|
||||
// 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/FBSDKCopying.h>
|
||||
|
||||
#import "FBSDKBridgeAPIRequest.h"
|
||||
|
||||
@interface FBSDKBridgeAPIResponse : NSObject <FBSDKCopying>
|
||||
|
||||
+ (instancetype)bridgeAPIResponseWithRequest:(FBSDKBridgeAPIRequest *)request error:(NSError *)error;
|
||||
+ (instancetype)bridgeAPIResponseWithRequest:(FBSDKBridgeAPIRequest *)request
|
||||
responseURL:(NSURL *)responseURL
|
||||
sourceApplication:(NSString *)sourceApplication
|
||||
error:(NSError *__autoreleasing *)errorRef;
|
||||
+ (instancetype)bridgeAPIResponseCancelledWithRequest:(FBSDKBridgeAPIRequest *)request;
|
||||
|
||||
@property (nonatomic, assign, readonly, getter=isCancelled) BOOL cancelled;
|
||||
@property (nonatomic, copy, readonly) NSError *error;
|
||||
@property (nonatomic, copy, readonly) FBSDKBridgeAPIRequest *request;
|
||||
@property (nonatomic, copy, readonly) NSDictionary *responseParameters;
|
||||
|
||||
@end
|
||||
Generated
+135
@@ -0,0 +1,135 @@
|
||||
// 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 "FBSDKBridgeAPIResponse.h"
|
||||
|
||||
#import "FBSDKBridgeAPICrypto.h"
|
||||
#import "FBSDKBridgeAPIProtocol.h"
|
||||
#import "FBSDKBridgeAPIProtocolType.h"
|
||||
#import "FBSDKBridgeAPIRequest+Private.h"
|
||||
#import "FBSDKInternalUtility.h"
|
||||
#import "FBSDKMacros.h"
|
||||
#import "FBSDKTypeUtility.h"
|
||||
#import "FBSDKUtility.h"
|
||||
|
||||
@interface FBSDKBridgeAPIResponse ()
|
||||
- (instancetype)initWithRequest:(FBSDKBridgeAPIRequest *)request
|
||||
responseParameters:(NSDictionary *)responseParameters
|
||||
cancelled:(BOOL)cancelled
|
||||
error:(NSError *)error
|
||||
NS_DESIGNATED_INITIALIZER;
|
||||
@end
|
||||
|
||||
@implementation FBSDKBridgeAPIResponse
|
||||
|
||||
#pragma mark - Class Methods
|
||||
|
||||
+ (instancetype)bridgeAPIResponseWithRequest:(FBSDKBridgeAPIRequest *)request error:(NSError *)error
|
||||
{
|
||||
return [[self alloc] initWithRequest:request
|
||||
responseParameters:nil
|
||||
cancelled:NO
|
||||
error:error];
|
||||
}
|
||||
|
||||
+ (instancetype)bridgeAPIResponseWithRequest:(FBSDKBridgeAPIRequest *)request
|
||||
responseURL:(NSURL *)responseURL
|
||||
sourceApplication:(NSString *)sourceApplication
|
||||
error:(NSError *__autoreleasing *)errorRef
|
||||
{
|
||||
FBSDKBridgeAPIProtocolType protocolType = request.protocolType;
|
||||
switch (protocolType) {
|
||||
case FBSDKBridgeAPIProtocolTypeNative:{
|
||||
if (![FBSDKInternalUtility isFacebookBundleIdentifier:sourceApplication]) {
|
||||
[FBSDKBridgeAPICrypto reset];
|
||||
return nil;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case FBSDKBridgeAPIProtocolTypeWeb:{
|
||||
if (![FBSDKInternalUtility isSafariBundleIdentifier:sourceApplication]) {
|
||||
[FBSDKBridgeAPICrypto reset];
|
||||
return nil;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
NSDictionary *queryParameters = [FBSDKUtility dictionaryWithQueryString:responseURL.query];
|
||||
queryParameters = [FBSDKBridgeAPICrypto decryptResponseForRequest:request
|
||||
queryParameters:queryParameters
|
||||
error:errorRef];
|
||||
if (!queryParameters) {
|
||||
return nil;
|
||||
}
|
||||
id<FBSDKBridgeAPIProtocol> protocol = request.protocol;
|
||||
BOOL cancelled;
|
||||
NSError *error;
|
||||
NSDictionary *responseParameters = [protocol responseParametersForActionID:request.actionID
|
||||
queryParameters:queryParameters
|
||||
cancelled:&cancelled
|
||||
error:&error];
|
||||
if (errorRef != NULL) {
|
||||
*errorRef = error;
|
||||
}
|
||||
if (!responseParameters) {
|
||||
return nil;
|
||||
}
|
||||
return [[self alloc] initWithRequest:request
|
||||
responseParameters:responseParameters
|
||||
cancelled:cancelled
|
||||
error:error];
|
||||
}
|
||||
|
||||
+ (instancetype)bridgeAPIResponseCancelledWithRequest:(FBSDKBridgeAPIRequest *)request
|
||||
{
|
||||
return [[self alloc] initWithRequest:request
|
||||
responseParameters:nil
|
||||
cancelled:YES
|
||||
error:nil];
|
||||
}
|
||||
|
||||
#pragma mark - Object Lifecycle
|
||||
|
||||
- (instancetype)initWithRequest:(FBSDKBridgeAPIRequest *)request
|
||||
responseParameters:(NSDictionary *)responseParameters
|
||||
cancelled:(BOOL)cancelled
|
||||
error:(NSError *)error
|
||||
{
|
||||
if ((self = [super init])) {
|
||||
_request = [request copy];
|
||||
_responseParameters = [responseParameters copy];
|
||||
_cancelled = cancelled;
|
||||
_error = [error copy];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (instancetype)init
|
||||
{
|
||||
FBSDK_NOT_DESIGNATED_INITIALIZER(initWithRequest:responseParameters:cancelled:error:);
|
||||
return [self initWithRequest:nil responseParameters:nil cancelled:NO error:nil];
|
||||
}
|
||||
|
||||
#pragma mark - NSCopying
|
||||
|
||||
- (id)copyWithZone:(NSZone *)zone
|
||||
{
|
||||
return self;
|
||||
}
|
||||
|
||||
@end
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
// 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.
|
||||
|
||||
@protocol FBSDKURLOpening <NSObject>
|
||||
|
||||
// Implementations should make sure they can handle nil parameters
|
||||
// which is possible in SafariViewController.
|
||||
- (BOOL)application:(UIApplication *)application
|
||||
openURL:(NSURL *)url
|
||||
sourceApplication:(NSString *)sourceApplication
|
||||
annotation:(id)annotation;
|
||||
|
||||
- (void)applicationDidBecomeActive:(UIApplication *)application;
|
||||
|
||||
@end
|
||||
+70
@@ -0,0 +1,70 @@
|
||||
// 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 <UIKit/UIKit.h>
|
||||
|
||||
#import <FBSDKCoreKit/FBSDKMacros.h>
|
||||
|
||||
#import "FBSDKBridgeAPIProtocol.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
__unsafe_unretained NSString *bridgeArgs;
|
||||
__unsafe_unretained NSString *methodArgs;
|
||||
__unsafe_unretained NSString *methodVersion;
|
||||
} FBSDKBridgeAPIProtocolNativeV1OutputKeysStruct;
|
||||
FBSDK_EXTERN const FBSDKBridgeAPIProtocolNativeV1OutputKeysStruct FBSDKBridgeAPIProtocolNativeV1OutputKeys;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
__unsafe_unretained NSString *actionID;
|
||||
__unsafe_unretained NSString *appIcon;
|
||||
__unsafe_unretained NSString *appName;
|
||||
__unsafe_unretained NSString *sdkVersion;
|
||||
} FBSDKBridgeAPIProtocolNativeV1BridgeParameterOutputKeysStruct;
|
||||
FBSDK_EXTERN const FBSDKBridgeAPIProtocolNativeV1BridgeParameterOutputKeysStruct FBSDKBridgeAPIProtocolNativeV1BridgeParameterOutputKeys;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
__unsafe_unretained NSString *bridgeArgs;
|
||||
__unsafe_unretained NSString *methodResults;
|
||||
} FBSDKBridgeAPIProtocolNativeV1InputKeysStruct;
|
||||
FBSDK_EXTERN const FBSDKBridgeAPIProtocolNativeV1InputKeysStruct FBSDKBridgeAPIProtocolNativeV1InputKeys;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
__unsafe_unretained NSString *actionID;
|
||||
__unsafe_unretained NSString *error;
|
||||
} FBSDKBridgeAPIProtocolNativeV1BridgeParameterInputKeysStruct;
|
||||
FBSDK_EXTERN const FBSDKBridgeAPIProtocolNativeV1BridgeParameterInputKeysStruct FBSDKBridgeAPIProtocolNativeV1BridgeParameterInputKeys;
|
||||
|
||||
@interface FBSDKBridgeAPIProtocolNativeV1 : NSObject <FBSDKBridgeAPIProtocol>
|
||||
|
||||
- (instancetype)initWithAppScheme:(NSString *)appScheme;
|
||||
- (instancetype)initWithAppScheme:(NSString *)appScheme
|
||||
pasteboard:(UIPasteboard *)pasteboard
|
||||
dataLengthThreshold:(NSUInteger)dataLengthThreshold
|
||||
includeAppIcon:(BOOL)includeAppIcon
|
||||
NS_DESIGNATED_INITIALIZER;
|
||||
|
||||
@property (nonatomic, copy, readonly) NSString *appScheme;
|
||||
@property (nonatomic, assign, readonly) NSUInteger dataLengthThreshold;
|
||||
@property (nonatomic, assign, readonly) BOOL includeAppIcon;
|
||||
@property (nonatomic, strong, readonly) UIPasteboard *pasteboard;
|
||||
|
||||
@end
|
||||
+338
@@ -0,0 +1,338 @@
|
||||
// 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 "FBSDKBridgeAPIProtocolNativeV1.h"
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
#import <FBSDKCoreKit/FBSDKMacros.h>
|
||||
|
||||
#import "FBSDKApplicationDelegate+Internal.h"
|
||||
#import "FBSDKBase64.h"
|
||||
#import "FBSDKBridgeAPIRequest.h"
|
||||
#import "FBSDKConstants.h"
|
||||
#import "FBSDKError.h"
|
||||
#import "FBSDKInternalUtility.h"
|
||||
#import "FBSDKSettings.h"
|
||||
#import "FBSDKTypeUtility.h"
|
||||
|
||||
#define FBSDKBridgeAPIProtocolNativeV1BridgeMaxBase64DataLengthThreshold (1024 * 16)
|
||||
|
||||
const FBSDKBridgeAPIProtocolNativeV1OutputKeysStruct FBSDKBridgeAPIProtocolNativeV1OutputKeys =
|
||||
{
|
||||
.bridgeArgs = @"bridge_args",
|
||||
.methodArgs = @"method_args",
|
||||
.methodVersion = @"version",
|
||||
};
|
||||
|
||||
const FBSDKBridgeAPIProtocolNativeV1BridgeParameterOutputKeysStruct FBSDKBridgeAPIProtocolNativeV1BridgeParameterOutputKeys =
|
||||
{
|
||||
.actionID = @"action_id",
|
||||
.appIcon = @"app_icon",
|
||||
.appName = @"app_name",
|
||||
.sdkVersion = @"sdk_version",
|
||||
};
|
||||
|
||||
const FBSDKBridgeAPIProtocolNativeV1InputKeysStruct FBSDKBridgeAPIProtocolNativeV1InputKeys =
|
||||
{
|
||||
.bridgeArgs = @"bridge_args",
|
||||
.methodResults = @"method_results",
|
||||
};
|
||||
|
||||
const FBSDKBridgeAPIProtocolNativeV1BridgeParameterInputKeysStruct FBSDKBridgeAPIProtocolNativeV1BridgeParameterInputKeys =
|
||||
{
|
||||
.actionID = @"action_id",
|
||||
.error = @"error",
|
||||
};
|
||||
|
||||
static const struct
|
||||
{
|
||||
__unsafe_unretained NSString *isBase64;
|
||||
__unsafe_unretained NSString *isPasteboard;
|
||||
__unsafe_unretained NSString *tag;
|
||||
__unsafe_unretained NSString *value;
|
||||
} FBSDKBridgeAPIProtocolNativeV1DataKeys =
|
||||
{
|
||||
.isBase64 = @"isBase64",
|
||||
.isPasteboard = @"isPasteboard",
|
||||
.tag = @"tag",
|
||||
.value = @"fbAppBridgeType_jsonReadyValue",
|
||||
};
|
||||
|
||||
static NSString *const FBSDKBridgeAPIProtocolNativeV1DataPasteboardKey = @"com.facebook.Facebook.FBAppBridgeType";
|
||||
|
||||
static const struct
|
||||
{
|
||||
__unsafe_unretained NSString *data;
|
||||
__unsafe_unretained NSString *image;
|
||||
} FBSDKBridgeAPIProtocolNativeV1DataTypeTags =
|
||||
{
|
||||
.data = @"data",
|
||||
// we serialize jpegs but use png for backward compatibility - it is any image format that UIImage can handle
|
||||
.image = @"png",
|
||||
};
|
||||
|
||||
static const struct
|
||||
{
|
||||
__unsafe_unretained NSString *code;
|
||||
__unsafe_unretained NSString *domain;
|
||||
__unsafe_unretained NSString *userInfo;
|
||||
} FBSDKBridgeAPIProtocolNativeV1ErrorKeys =
|
||||
{
|
||||
.code = @"code",
|
||||
.domain = @"domain",
|
||||
.userInfo = @"user_info",
|
||||
};
|
||||
|
||||
@implementation FBSDKBridgeAPIProtocolNativeV1
|
||||
|
||||
#pragma mark - Object Lifecycle
|
||||
|
||||
- (instancetype)initWithAppScheme:(NSString *)appScheme
|
||||
{
|
||||
return [self initWithAppScheme:appScheme
|
||||
pasteboard:[UIPasteboard generalPasteboard]
|
||||
dataLengthThreshold:FBSDKBridgeAPIProtocolNativeV1BridgeMaxBase64DataLengthThreshold
|
||||
includeAppIcon:YES];
|
||||
}
|
||||
|
||||
- (instancetype)initWithAppScheme:(NSString *)appScheme
|
||||
pasteboard:(UIPasteboard *)pasteboard
|
||||
dataLengthThreshold:(NSUInteger)dataLengthThreshold
|
||||
includeAppIcon:(BOOL)includeAppIcon
|
||||
{
|
||||
if ((self = [super init])) {
|
||||
_appScheme = [appScheme copy];
|
||||
_pasteboard = pasteboard;
|
||||
_dataLengthThreshold = dataLengthThreshold;
|
||||
_includeAppIcon = includeAppIcon;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (instancetype)init
|
||||
{
|
||||
FBSDK_NOT_DESIGNATED_INITIALIZER(initWithAppScheme:);
|
||||
return [self initWithAppScheme:nil];
|
||||
}
|
||||
|
||||
#pragma mark - FBSDKBridgeAPIProtocol
|
||||
|
||||
- (NSURL *)requestURLWithActionID:(NSString *)actionID
|
||||
scheme:(NSString *)scheme
|
||||
methodName:(NSString *)methodName
|
||||
methodVersion:(NSString *)methodVersion
|
||||
parameters:(NSDictionary *)parameters
|
||||
error:(NSError *__autoreleasing *)errorRef
|
||||
{
|
||||
NSString *host = @"dialog";
|
||||
NSString *path = [@"/" stringByAppendingString:methodName];
|
||||
|
||||
NSMutableDictionary *queryParameters = [[NSMutableDictionary alloc] init];
|
||||
[FBSDKInternalUtility dictionary:queryParameters setObject:methodVersion
|
||||
forKey:FBSDKBridgeAPIProtocolNativeV1OutputKeys.methodVersion];
|
||||
|
||||
if ([parameters count]) {
|
||||
NSString *parametersString = [self _JSONStringForObject:parameters enablePasteboard:YES error:errorRef];
|
||||
if (!parametersString) {
|
||||
return nil;
|
||||
}
|
||||
[FBSDKInternalUtility dictionary:queryParameters
|
||||
setObject:parametersString
|
||||
forKey:FBSDKBridgeAPIProtocolNativeV1OutputKeys.methodArgs];
|
||||
}
|
||||
|
||||
NSDictionary *bridgeParameters = [self _bridgeParametersWithActionID:actionID error:errorRef];
|
||||
if (!bridgeParameters) {
|
||||
return nil;
|
||||
}
|
||||
NSString *bridgeParametersString = [self _JSONStringForObject:bridgeParameters enablePasteboard:NO error:errorRef];
|
||||
if (!bridgeParametersString) {
|
||||
return nil;
|
||||
}
|
||||
[FBSDKInternalUtility dictionary:queryParameters
|
||||
setObject:bridgeParametersString
|
||||
forKey:FBSDKBridgeAPIProtocolNativeV1OutputKeys.bridgeArgs];
|
||||
|
||||
|
||||
return [FBSDKInternalUtility URLWithScheme:self.appScheme
|
||||
host:host
|
||||
path:path
|
||||
queryParameters:queryParameters
|
||||
error:errorRef];
|
||||
}
|
||||
|
||||
- (NSDictionary *)responseParametersForActionID:(NSString *)actionID
|
||||
queryParameters:(NSDictionary *)queryParameters
|
||||
cancelled:(BOOL *)cancelledRef
|
||||
error:(NSError *__autoreleasing *)errorRef
|
||||
{
|
||||
if (cancelledRef != NULL) {
|
||||
*cancelledRef = NO;
|
||||
}
|
||||
if (errorRef != NULL) {
|
||||
*errorRef = nil;
|
||||
}
|
||||
NSError *error;
|
||||
NSString *bridgeParametersJSON = queryParameters[FBSDKBridgeAPIProtocolNativeV1InputKeys.bridgeArgs];
|
||||
NSDictionary *bridgeParameters = [FBSDKInternalUtility objectForJSONString:bridgeParametersJSON error:&error];
|
||||
bridgeParameters = [FBSDKTypeUtility dictionaryValue:bridgeParameters];
|
||||
if (!bridgeParameters) {
|
||||
if (error && (errorRef != NULL)) {
|
||||
*errorRef = [FBSDKError invalidArgumentErrorWithName:FBSDKBridgeAPIProtocolNativeV1InputKeys.bridgeArgs
|
||||
value:bridgeParametersJSON
|
||||
message:@"Invalid bridge_args."
|
||||
underlyingError:error];
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
NSString *responseActionID = bridgeParameters[FBSDKBridgeAPIProtocolNativeV1BridgeParameterInputKeys.actionID];
|
||||
responseActionID = [FBSDKTypeUtility stringValue:responseActionID];
|
||||
if (![responseActionID isEqualToString:actionID]) {
|
||||
return nil;
|
||||
}
|
||||
NSDictionary *errorDictionary = bridgeParameters[FBSDKBridgeAPIProtocolNativeV1BridgeParameterInputKeys.error];
|
||||
errorDictionary = [FBSDKTypeUtility dictionaryValue:errorDictionary];
|
||||
if (errorDictionary) {
|
||||
error = [self _errorWithDictionary:errorDictionary];
|
||||
if (errorRef != NULL) {
|
||||
*errorRef = error;
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
NSString *resultParametersJSON = queryParameters[FBSDKBridgeAPIProtocolNativeV1InputKeys.methodResults];
|
||||
NSDictionary *resultParameters = [FBSDKInternalUtility objectForJSONString:resultParametersJSON error:&error];
|
||||
if (!resultParameters) {
|
||||
if (errorRef != NULL) {
|
||||
*errorRef = [FBSDKError invalidArgumentErrorWithName:FBSDKBridgeAPIProtocolNativeV1InputKeys.methodResults
|
||||
value:resultParametersJSON
|
||||
message:@"Invalid method_results."
|
||||
underlyingError:error];
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
if (cancelledRef != NULL) {
|
||||
NSString *completionGesture = [FBSDKTypeUtility stringValue:resultParameters[@"completionGesture"]];
|
||||
*cancelledRef = [completionGesture isEqualToString:@"cancel"];
|
||||
}
|
||||
return resultParameters;
|
||||
}
|
||||
|
||||
#pragma mark - Helper Methods
|
||||
|
||||
- (UIImage *)_appIcon
|
||||
{
|
||||
if (!_includeAppIcon) {
|
||||
return nil;
|
||||
}
|
||||
NSArray *files = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleIcons"]
|
||||
[@"CFBundlePrimaryIcon"]
|
||||
[@"CFBundleIconFiles"];
|
||||
if (![files count]) {
|
||||
return nil;
|
||||
}
|
||||
return [UIImage imageNamed:files[0]];
|
||||
}
|
||||
|
||||
- (NSDictionary *)_bridgeParametersWithActionID:(NSString *)actionID error:(NSError *__autoreleasing *)errorRef
|
||||
{
|
||||
NSMutableDictionary *bridgeParameters = [[NSMutableDictionary alloc] init];
|
||||
[FBSDKInternalUtility dictionary:bridgeParameters setObject:actionID
|
||||
forKey:FBSDKBridgeAPIProtocolNativeV1BridgeParameterOutputKeys.actionID];
|
||||
[FBSDKInternalUtility dictionary:bridgeParameters setObject:[self _appIcon]
|
||||
forKey:FBSDKBridgeAPIProtocolNativeV1BridgeParameterOutputKeys.appIcon];
|
||||
[FBSDKInternalUtility dictionary:bridgeParameters setObject:[FBSDKSettings displayName]
|
||||
forKey:FBSDKBridgeAPIProtocolNativeV1BridgeParameterOutputKeys.appName];
|
||||
[FBSDKInternalUtility dictionary:bridgeParameters setObject:[FBSDKSettings sdkVersion]
|
||||
forKey:FBSDKBridgeAPIProtocolNativeV1BridgeParameterOutputKeys.sdkVersion];
|
||||
return bridgeParameters;
|
||||
}
|
||||
|
||||
- (NSError *)_errorWithDictionary:(NSDictionary *)dictionary
|
||||
{
|
||||
if (!dictionary) {
|
||||
return nil;
|
||||
}
|
||||
NSString *domain = [FBSDKTypeUtility stringValue:dictionary[FBSDKBridgeAPIProtocolNativeV1ErrorKeys.domain]] ?:
|
||||
FBSDKErrorDomain;
|
||||
NSInteger code = [FBSDKTypeUtility integerValue:dictionary[FBSDKBridgeAPIProtocolNativeV1ErrorKeys.code]] ?:
|
||||
FBSDKUnknownErrorCode;
|
||||
NSDictionary *userInfo = [FBSDKTypeUtility dictionaryValue:dictionary[FBSDKBridgeAPIProtocolNativeV1ErrorKeys.userInfo]];
|
||||
return [NSError errorWithDomain:domain code:code userInfo:userInfo];
|
||||
}
|
||||
|
||||
- (NSString *)_JSONStringForObject:(id)object enablePasteboard:(BOOL)enablePasteboard error:(NSError **)errorRef
|
||||
{
|
||||
__block BOOL didAddToPasteboard = NO;
|
||||
return [FBSDKInternalUtility JSONStringForObject:object error:errorRef invalidObjectHandler:^id(id invalidObject, BOOL *stop) {
|
||||
NSString *dataTag = FBSDKBridgeAPIProtocolNativeV1DataTypeTags.data;
|
||||
if ([invalidObject isKindOfClass:[UIImage class]]) {
|
||||
UIImage *image = (UIImage *)invalidObject;
|
||||
// due to backward compatibility, we must send UIImage as NSData even though UIPasteboard can handle UIImage
|
||||
invalidObject = UIImageJPEGRepresentation(image, [FBSDKSettings JPEGCompressionQuality]);
|
||||
dataTag = FBSDKBridgeAPIProtocolNativeV1DataTypeTags.image;
|
||||
}
|
||||
if ([invalidObject isKindOfClass:[NSData class]]) {
|
||||
NSData *data = (NSData *)invalidObject;
|
||||
NSMutableDictionary *dictionary = [[NSMutableDictionary alloc] init];
|
||||
if (didAddToPasteboard || !enablePasteboard || !_pasteboard || (data.length < _dataLengthThreshold)) {
|
||||
dictionary[FBSDKBridgeAPIProtocolNativeV1DataKeys.isBase64] = @YES;
|
||||
dictionary[FBSDKBridgeAPIProtocolNativeV1DataKeys.tag] = dataTag;
|
||||
[FBSDKInternalUtility dictionary:dictionary
|
||||
setObject:[FBSDKBase64 encodeData:data]
|
||||
forKey:FBSDKBridgeAPIProtocolNativeV1DataKeys.value];
|
||||
} else {
|
||||
dictionary[FBSDKBridgeAPIProtocolNativeV1DataKeys.isPasteboard] = @YES;
|
||||
dictionary[FBSDKBridgeAPIProtocolNativeV1DataKeys.tag] = dataTag;
|
||||
dictionary[FBSDKBridgeAPIProtocolNativeV1DataKeys.value] = _pasteboard.name;
|
||||
[_pasteboard setData:data forPasteboardType:FBSDKBridgeAPIProtocolNativeV1DataPasteboardKey];
|
||||
// this version of the protocol only supports a single item on the pasteboard, so if when we add an item, make
|
||||
// sure we don't add another item
|
||||
didAddToPasteboard = YES;
|
||||
// if we are adding this to the general pasteboard, then we want to remove it when we are done with the share.
|
||||
// the Facebook app will not clear the value with this version of the protocol, so we should do it when the app
|
||||
// becomes active again
|
||||
NSString *pasteboardName = _pasteboard.name;
|
||||
if ([pasteboardName isEqualToString:UIPasteboardNameGeneral] ||
|
||||
[pasteboardName isEqualToString:UIPasteboardNameFind]) {
|
||||
[[self class] clearData:data fromPasteboardOnApplicationDidBecomeActive:_pasteboard];
|
||||
}
|
||||
}
|
||||
return dictionary;
|
||||
} else if ([invalidObject isKindOfClass:[NSURL class]]) {
|
||||
return [(NSURL *)invalidObject absoluteString];
|
||||
}
|
||||
return invalidObject;
|
||||
}];
|
||||
}
|
||||
|
||||
+ (void)clearData:(NSData *)data fromPasteboardOnApplicationDidBecomeActive:(UIPasteboard *)pasteboard
|
||||
{
|
||||
void(^notificationBlock)(NSNotification *) = ^(NSNotification *note){
|
||||
NSData *pasteboardData = [pasteboard dataForPasteboardType:FBSDKBridgeAPIProtocolNativeV1DataPasteboardKey];
|
||||
if ([data isEqualToData:pasteboardData]) {
|
||||
[pasteboard setData:[NSData data] forPasteboardType:FBSDKBridgeAPIProtocolNativeV1DataPasteboardKey];
|
||||
}
|
||||
};
|
||||
[[NSNotificationCenter defaultCenter] addObserverForName:FBSDKApplicationDidBecomeActiveNotification
|
||||
object:[FBSDKApplicationDelegate sharedInstance]
|
||||
queue:nil
|
||||
usingBlock:notificationBlock];
|
||||
}
|
||||
|
||||
@end
|
||||
+25
@@ -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 <UIKit/UIKit.h>
|
||||
|
||||
#import "FBSDKBridgeAPIProtocol.h"
|
||||
|
||||
@interface FBSDKBridgeAPIProtocolWebV1 : NSObject <FBSDKBridgeAPIProtocol>
|
||||
|
||||
@end
|
||||
+116
@@ -0,0 +1,116 @@
|
||||
// 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 "FBSDKBridgeAPIProtocolWebV1.h"
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
#import "FBSDKBase64.h"
|
||||
#import "FBSDKBridgeAPIRequest.h"
|
||||
#import "FBSDKError.h"
|
||||
#import "FBSDKInternalUtility.h"
|
||||
#import "FBSDKMacros.h"
|
||||
#import "FBSDKSettings.h"
|
||||
#import "FBSDKTypeUtility.h"
|
||||
|
||||
#define FBSDK_BRIDGE_API_PROTOCOL_WEB_V1_ACTION_ID_KEY @"action_id"
|
||||
#define FBSDK_BRIDGE_API_PROTOCOL_WEB_V1_BRIDGE_ARGS_KEY @"bridge_args"
|
||||
|
||||
@implementation FBSDKBridgeAPIProtocolWebV1
|
||||
|
||||
#pragma mark - FBSDKBridgeAPIProtocol
|
||||
|
||||
- (NSURL *)requestURLWithActionID:(NSString *)actionID
|
||||
scheme:(NSString *)scheme
|
||||
methodName:(NSString *)methodName
|
||||
methodVersion:(NSString *)methodVersion
|
||||
parameters:(NSDictionary *)parameters
|
||||
error:(NSError *__autoreleasing *)errorRef
|
||||
{
|
||||
NSMutableDictionary *queryParameters = [[NSMutableDictionary alloc] initWithDictionary:parameters];
|
||||
queryParameters[@"display"] = @"touch";
|
||||
NSString *bridgeArgs = [FBSDKInternalUtility JSONStringForObject:@{ FBSDK_BRIDGE_API_PROTOCOL_WEB_V1_ACTION_ID_KEY: actionID }
|
||||
error:NULL
|
||||
invalidObjectHandler:NULL];
|
||||
NSDictionary *redirectQueryParameters = @{ FBSDK_BRIDGE_API_PROTOCOL_WEB_V1_BRIDGE_ARGS_KEY: bridgeArgs };
|
||||
NSURL *redirectURL = [FBSDKInternalUtility appURLWithHost:@"bridge"
|
||||
path:methodName
|
||||
queryParameters:redirectQueryParameters
|
||||
error:NULL];
|
||||
[FBSDKInternalUtility dictionary:queryParameters setObject:redirectURL forKey:@"redirect_uri"];
|
||||
[queryParameters addEntriesFromDictionary:parameters];
|
||||
return [FBSDKInternalUtility facebookURLWithHostPrefix:@"m"
|
||||
path:[@"/dialog/" stringByAppendingString:methodName]
|
||||
queryParameters:queryParameters
|
||||
error:NULL];
|
||||
}
|
||||
|
||||
- (NSDictionary *)responseParametersForActionID:(NSString *)actionID
|
||||
queryParameters:(NSDictionary *)queryParameters
|
||||
cancelled:(BOOL *)cancelledRef
|
||||
error:(NSError *__autoreleasing *)errorRef
|
||||
{
|
||||
if (errorRef != NULL) {
|
||||
*errorRef = nil;
|
||||
}
|
||||
NSInteger errorCode = [FBSDKTypeUtility integerValue:queryParameters[@"error_code"]];
|
||||
switch (errorCode) {
|
||||
case 0:{
|
||||
// good to go, handle the other codes and bail
|
||||
break;
|
||||
}
|
||||
case 4201:{
|
||||
return @{
|
||||
@"completionGesture": @"cancel",
|
||||
};
|
||||
break;
|
||||
}
|
||||
default:{
|
||||
if (errorRef != NULL) {
|
||||
*errorRef = [FBSDKError errorWithCode:errorCode
|
||||
message:[FBSDKTypeUtility stringValue:queryParameters[@"error_message"]]];
|
||||
}
|
||||
return nil;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
NSError *error;
|
||||
NSString *bridgeParametersJSON = [FBSDKTypeUtility stringValue:queryParameters[FBSDK_BRIDGE_API_PROTOCOL_WEB_V1_BRIDGE_ARGS_KEY]];
|
||||
NSDictionary *bridgeParameters = [FBSDKInternalUtility objectForJSONString:bridgeParametersJSON error:&error];
|
||||
if (!bridgeParameters) {
|
||||
if (error && (errorRef != NULL)) {
|
||||
*errorRef = [FBSDKError invalidArgumentErrorWithName:FBSDK_BRIDGE_API_PROTOCOL_WEB_V1_BRIDGE_ARGS_KEY
|
||||
value:bridgeParametersJSON
|
||||
message:nil
|
||||
underlyingError:error];
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
NSString *responseActionID = bridgeParameters[FBSDK_BRIDGE_API_PROTOCOL_WEB_V1_ACTION_ID_KEY];
|
||||
responseActionID = [FBSDKTypeUtility stringValue:responseActionID];
|
||||
if (![responseActionID isEqualToString:actionID]) {
|
||||
return nil;
|
||||
}
|
||||
NSMutableDictionary *resultParameters = [queryParameters mutableCopy];
|
||||
[resultParameters removeObjectForKey:FBSDK_BRIDGE_API_PROTOCOL_WEB_V1_BRIDGE_ARGS_KEY];
|
||||
resultParameters[@"didComplete"] = @YES;
|
||||
return resultParameters;
|
||||
}
|
||||
|
||||
@end
|
||||
+25
@@ -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 <UIKit/UIKit.h>
|
||||
|
||||
#import "FBSDKBridgeAPIProtocol.h"
|
||||
|
||||
@interface FBSDKBridgeAPIProtocolWebV2 : NSObject <FBSDKBridgeAPIProtocol>
|
||||
|
||||
@end
|
||||
+130
@@ -0,0 +1,130 @@
|
||||
// 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 "FBSDKBridgeAPIProtocolWebV2.h"
|
||||
|
||||
#import "FBSDKBridgeAPIProtocolNativeV1.h"
|
||||
#import "FBSDKDialogConfiguration.h"
|
||||
#import "FBSDKError.h"
|
||||
#import "FBSDKInternalUtility.h"
|
||||
#import "FBSDKServerConfiguration.h"
|
||||
#import "FBSDKServerConfigurationManager.h"
|
||||
#import "FBSDKUtility.h"
|
||||
|
||||
@implementation FBSDKBridgeAPIProtocolWebV2
|
||||
{
|
||||
FBSDKBridgeAPIProtocolNativeV1 *_nativeProtocol;
|
||||
}
|
||||
|
||||
#pragma mark - Object Lifecycle
|
||||
|
||||
- (instancetype)init
|
||||
{
|
||||
if ((self = [super init])) {
|
||||
_nativeProtocol = [[FBSDKBridgeAPIProtocolNativeV1 alloc] initWithAppScheme:nil
|
||||
pasteboard:nil
|
||||
dataLengthThreshold:0
|
||||
includeAppIcon:NO];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
#pragma mark - FBSDKBridgeAPIProtocol
|
||||
|
||||
- (NSURL *)_redirectURLWithActionID:(NSString *)actionID methodName:(NSString *)methodName error:(NSError **)errorRef
|
||||
{
|
||||
NSDictionary *queryParameters = nil;
|
||||
if (actionID) {
|
||||
NSDictionary *bridgeArgs = @{ FBSDKBridgeAPIProtocolNativeV1BridgeParameterInputKeys.actionID: actionID };
|
||||
NSString *bridgeArgsString = [FBSDKInternalUtility JSONStringForObject:bridgeArgs
|
||||
error:NULL
|
||||
invalidObjectHandler:NULL];
|
||||
queryParameters = @{ FBSDKBridgeAPIProtocolNativeV1InputKeys.bridgeArgs: bridgeArgsString };
|
||||
}
|
||||
return [FBSDKInternalUtility appURLWithHost:@"bridge" path:methodName queryParameters:queryParameters error:errorRef];
|
||||
}
|
||||
|
||||
- (NSURL *)_requestURLForDialogConfiguration:(FBSDKDialogConfiguration *)dialogConfiguration error:(NSError **)errorRef
|
||||
{
|
||||
NSURL *requestURL = dialogConfiguration.URL;
|
||||
if (!requestURL.scheme) {
|
||||
requestURL = [FBSDKInternalUtility facebookURLWithHostPrefix:@"m"
|
||||
path:requestURL.path
|
||||
queryParameters:nil
|
||||
defaultVersion:@""
|
||||
error:errorRef];
|
||||
}
|
||||
return requestURL;
|
||||
}
|
||||
|
||||
- (NSURL *)requestURLWithActionID:(NSString *)actionID
|
||||
scheme:(NSString *)scheme
|
||||
methodName:(NSString *)methodName
|
||||
methodVersion:(NSString *)methodVersion
|
||||
parameters:(NSDictionary *)parameters
|
||||
error:(NSError *__autoreleasing *)errorRef
|
||||
{
|
||||
FBSDKServerConfiguration *serverConfiguration = [FBSDKServerConfigurationManager cachedServerConfiguration];
|
||||
FBSDKDialogConfiguration *dialogConfiguration = [serverConfiguration dialogConfigurationForDialogName:methodName];
|
||||
if (!dialogConfiguration) {
|
||||
if (errorRef != NULL) {
|
||||
*errorRef = [FBSDKError errorWithCode:FBSDKDialogUnavailableErrorCode message:nil];
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
NSURL *requestURL = [_nativeProtocol requestURLWithActionID:actionID
|
||||
scheme:scheme
|
||||
methodName:methodName
|
||||
methodVersion:methodVersion
|
||||
parameters:parameters error:errorRef];
|
||||
if (!requestURL) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
NSMutableDictionary *queryParameters = [[FBSDKUtility dictionaryWithQueryString:requestURL.query] mutableCopy];
|
||||
queryParameters[@"ios_bundle_id"] = [[NSBundle mainBundle] bundleIdentifier];
|
||||
NSURL *redirectURL = [self _redirectURLWithActionID:nil methodName:methodName error:errorRef];
|
||||
if (!redirectURL) {
|
||||
return nil;
|
||||
}
|
||||
queryParameters[@"redirect_url"] = redirectURL;
|
||||
|
||||
requestURL = [self _requestURLForDialogConfiguration:dialogConfiguration error:errorRef];
|
||||
if (!requestURL) {
|
||||
return nil;
|
||||
}
|
||||
return [FBSDKInternalUtility URLWithScheme:requestURL.scheme
|
||||
host:requestURL.host
|
||||
path:requestURL.path
|
||||
queryParameters:queryParameters
|
||||
error:errorRef];
|
||||
}
|
||||
|
||||
- (NSDictionary *)responseParametersForActionID:(NSString *)actionID
|
||||
queryParameters:(NSDictionary *)queryParameters
|
||||
cancelled:(BOOL *)cancelledRef
|
||||
error:(NSError *__autoreleasing *)errorRef
|
||||
{
|
||||
return [_nativeProtocol responseParametersForActionID:actionID
|
||||
queryParameters:queryParameters
|
||||
cancelled:cancelledRef
|
||||
error:errorRef];
|
||||
}
|
||||
|
||||
@end
|
||||
+63
@@ -0,0 +1,63 @@
|
||||
// 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>
|
||||
|
||||
@interface FBSDKCrypto : NSObject
|
||||
|
||||
/*!
|
||||
@abstract Generate numOfBytes random data.
|
||||
@discussion This calls the system-provided function SecRandomCopyBytes, based on /dev/random.
|
||||
*/
|
||||
+ (NSData *)randomBytes:(NSUInteger)numOfBytes;
|
||||
|
||||
/**
|
||||
* Generate numOfBytes random data, base64-encoded.
|
||||
* This calls the system-provided function SecRandomCopyBytes, based on /dev/random.
|
||||
*/
|
||||
+ (NSString *)randomString:(NSUInteger)numOfBytes;
|
||||
|
||||
/*!
|
||||
@abstract Generate a fresh master key using SecRandomCopyBytes, the result is encoded in base64/.
|
||||
*/
|
||||
+ (NSString *)makeMasterKey;
|
||||
|
||||
/*!
|
||||
@abstract Initialize with a base64-encoded master key.
|
||||
@discussion This key and the current derivation function will be used to generate the encryption key and the mac key.
|
||||
*/
|
||||
- (instancetype)initWithMasterKey:(NSString *)masterKey;
|
||||
|
||||
/*!
|
||||
@abstract Initialize with base64-encoded encryption key and mac key.
|
||||
*/
|
||||
- (instancetype)initWithEncryptionKey:(NSString *)encryptionKey macKey:(NSString *)macKey;
|
||||
|
||||
/*!
|
||||
@abstract Encrypt plainText and return the base64 encoded result.
|
||||
@discussion MAC computation involves additionalDataToSign.
|
||||
*/
|
||||
- (NSString *)encrypt:(NSData *)plainText additionalDataToSign:(NSData *)additionalDataToSign;
|
||||
|
||||
/*!
|
||||
@abstract Decrypt base64EncodedCipherText.
|
||||
@discussion MAC computation involves additionalSignedData.
|
||||
*/
|
||||
- (NSData *)decrypt:(NSString *)base64EncodedCipherText additionalSignedData:(NSData *)additionalSignedData;
|
||||
|
||||
@end
|
||||
+287
@@ -0,0 +1,287 @@
|
||||
// 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 "FBSDKCrypto.h"
|
||||
|
||||
#import <CommonCrypto/CommonCryptor.h>
|
||||
#import <CommonCrypto/CommonDigest.h>
|
||||
#import <CommonCrypto/CommonHMAC.h>
|
||||
|
||||
#import "FBSDKBase64.h"
|
||||
#import "FBSDKDynamicFrameworkLoader.h"
|
||||
|
||||
static const uint8_t kFBSDK_CRYPTO_CURRENT_VERSION = 1;
|
||||
static const uint8_t kFBSDK_CRYPTO_CURRENT_MASTER_KEY_LENGTH = 16;
|
||||
|
||||
FBSDK_STATIC_INLINE void FBSDKCryptoWriteIntBigEndian(uint8_t *buffer, uint32_t value)
|
||||
{
|
||||
buffer[3] = (uint8_t)(value & 0xff);
|
||||
buffer[2] = (uint8_t)((value >> 8) & 0xff);
|
||||
buffer[1] = (uint8_t)((value >> 16) & 0xff);
|
||||
buffer[0] = (uint8_t)((value >> 24) & 0xff);
|
||||
}
|
||||
|
||||
FBSDK_STATIC_INLINE void FBSDKCryptoBlankData(NSData *data)
|
||||
{
|
||||
if (!data) {
|
||||
return;
|
||||
}
|
||||
bzero((void *) [data bytes], [data length]);
|
||||
}
|
||||
|
||||
// Note: the following simple derivation function is NOT suitable for passwords or weak keys
|
||||
FBSDK_STATIC_INLINE NSData *FBSDKCryptoMakeSubKey(uint8_t *key, size_t len, uint32_t idx)
|
||||
{
|
||||
if (!key || len < 10) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
size_t macBufferLength = 4;
|
||||
uint8_t macBuffer[4];
|
||||
FBSDKCryptoWriteIntBigEndian(macBuffer, idx);
|
||||
|
||||
uint8_t *result = malloc(CC_SHA256_DIGEST_LENGTH);
|
||||
if (!result) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
CCHmac(kCCHmacAlgSHA256, key, len, macBuffer, macBufferLength, result);
|
||||
|
||||
return [NSData dataWithBytesNoCopy:result length:CC_SHA256_DIGEST_LENGTH];
|
||||
}
|
||||
|
||||
@implementation FBSDKCrypto
|
||||
{
|
||||
NSData *_encryptionKeyData;
|
||||
NSData *_macKeyData;
|
||||
}
|
||||
|
||||
#pragma mark - Class Methods
|
||||
|
||||
+ (NSString *)makeMasterKey
|
||||
{
|
||||
NSData *masterKeyData = [FBSDKCrypto randomBytes:kFBSDK_CRYPTO_CURRENT_MASTER_KEY_LENGTH + 1];
|
||||
|
||||
// force the first byte to be the crypto version
|
||||
uint8_t *first = (uint8_t *) [masterKeyData bytes];
|
||||
*first = kFBSDK_CRYPTO_CURRENT_VERSION;
|
||||
|
||||
NSString *masterKey = [FBSDKBase64 encodeData:masterKeyData];
|
||||
FBSDKCryptoBlankData(masterKeyData);
|
||||
return masterKey;
|
||||
}
|
||||
|
||||
+ (NSData *)randomBytes:(NSUInteger)numOfBytes
|
||||
{
|
||||
uint8_t *buffer = malloc(numOfBytes);
|
||||
int result = fbsdkdfl_SecRandomCopyBytes([FBSDKDynamicFrameworkLoader loadkSecRandomDefault], numOfBytes, buffer);
|
||||
if (result != 0) {
|
||||
free(buffer);
|
||||
return nil;
|
||||
}
|
||||
return [NSData dataWithBytesNoCopy:buffer length:numOfBytes];
|
||||
}
|
||||
|
||||
+ (NSString *)randomString:(NSUInteger)numOfBytes
|
||||
{
|
||||
NSData *randomStringData = [FBSDKCrypto randomBytes:numOfBytes];
|
||||
NSString *randomString = [FBSDKBase64 encodeData:randomStringData];
|
||||
FBSDKCryptoBlankData(randomStringData);
|
||||
return randomString;
|
||||
}
|
||||
|
||||
#pragma mark - Object Lifecycle
|
||||
|
||||
- (instancetype)initWithMasterKey:(NSString *)masterKey
|
||||
{
|
||||
if ((self = [super init])) {
|
||||
NSData *masterKeyData = [FBSDKBase64 decodeAsData:masterKey];
|
||||
NSUInteger len = [masterKeyData length];
|
||||
uint8_t *first = (uint8_t *) [masterKeyData bytes];
|
||||
|
||||
if (len == 0 || first == nil || *first != kFBSDK_CRYPTO_CURRENT_VERSION) {
|
||||
// only one version supported at the moment
|
||||
return nil;
|
||||
}
|
||||
|
||||
_encryptionKeyData = FBSDKCryptoMakeSubKey(first+1, len-1, 1);
|
||||
_macKeyData = FBSDKCryptoMakeSubKey(first+1, len-1, 2);
|
||||
FBSDKCryptoBlankData(masterKeyData);
|
||||
return self;
|
||||
} else {
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
|
||||
- (instancetype)initWithEncryptionKey:(NSString *)encryptionKey macKey:(NSString *)macKey
|
||||
{
|
||||
if ((self = [super init])) {
|
||||
_macKeyData = [FBSDKBase64 decodeAsData:macKey];
|
||||
_encryptionKeyData = [FBSDKBase64 decodeAsData:encryptionKey];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
FBSDKCryptoBlankData(_encryptionKeyData);
|
||||
FBSDKCryptoBlankData(_macKeyData);
|
||||
}
|
||||
|
||||
#pragma mark - Public Methods
|
||||
|
||||
/**
|
||||
* return base64_encode([VERSION 1 byte] + [MAC 32 bytes] + [IV 16 bytes] + [AES256(Padded Data, multiples of 16)]
|
||||
*/
|
||||
- (NSString *)encrypt:(NSData *)plainText additionalDataToSign:(NSData *)additionalDataToSign
|
||||
{
|
||||
NSAssert(plainText.length <= INT_MAX, @"");
|
||||
int plainTextLength = (int)plainText.length;
|
||||
|
||||
uint8_t numPaddingBytes = kCCBlockSizeAES128 - (plainText.length % kCCBlockSizeAES128); // Pad 1 .. 16 bytes
|
||||
int cipherDataLength = plainTextLength + numPaddingBytes;
|
||||
size_t bufferSize = 1 + CC_SHA256_DIGEST_LENGTH + kCCBlockSizeAES128 + cipherDataLength;
|
||||
int offsetMAC = 1;
|
||||
int offsetIV = offsetMAC + CC_SHA256_DIGEST_LENGTH;
|
||||
int offsetCipherData = offsetIV + kCCBlockSizeAES128;
|
||||
|
||||
uint8_t *buffer = calloc(bufferSize, sizeof(uint8_t));
|
||||
buffer[0] = kFBSDK_CRYPTO_CURRENT_VERSION; // First byte is the version number
|
||||
NSData *IV = [[self class] randomBytes:kCCBlockSizeAES128];
|
||||
memcpy(buffer + offsetIV, IV.bytes, IV.length);
|
||||
|
||||
memcpy(buffer + offsetCipherData, plainText.bytes, plainTextLength); // Copy input in
|
||||
fbsdkdfl_SecRandomCopyBytes([FBSDKDynamicFrameworkLoader loadkSecRandomDefault],
|
||||
numPaddingBytes,
|
||||
buffer + offsetCipherData + plainTextLength); // Random pad
|
||||
buffer[offsetCipherData + cipherDataLength - 1] = numPaddingBytes; // Record the number of padded bytes at the end
|
||||
|
||||
size_t numOutputBytes = 0;
|
||||
CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt, kCCAlgorithmAES128, 0,
|
||||
_encryptionKeyData.bytes, kCCKeySizeAES256,
|
||||
IV.bytes,
|
||||
buffer + offsetCipherData, cipherDataLength,
|
||||
buffer + offsetCipherData, cipherDataLength,
|
||||
&numOutputBytes);
|
||||
|
||||
NSData *mac = [self _macForIV:IV
|
||||
cipherData:[NSData dataWithBytesNoCopy:buffer + offsetCipherData length:cipherDataLength freeWhenDone:NO]
|
||||
additionalDataToSign:additionalDataToSign];
|
||||
memcpy(buffer + offsetMAC, mac.bytes, CC_SHA256_DIGEST_LENGTH);
|
||||
|
||||
if (cryptStatus == kCCSuccess) {
|
||||
return [FBSDKBase64 encodeData:[NSData dataWithBytesNoCopy:buffer length:bufferSize]];
|
||||
}
|
||||
free(buffer);
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (NSData *)decrypt:(NSString *)base64EncodedCipherText additionalSignedData:(NSData *)additionalSignedData
|
||||
{
|
||||
NSData *cipherText = [FBSDKBase64 decodeAsData:base64EncodedCipherText];
|
||||
NSAssert(cipherText.length <= INT_MAX, @"");
|
||||
int cipherTextLength = (int)cipherText.length;
|
||||
|
||||
if (!cipherText || cipherTextLength < 1 + CC_SHA256_DIGEST_LENGTH + kCCBlockSizeAES128) {
|
||||
return nil;
|
||||
}
|
||||
int cipherDataLength = cipherTextLength - (1 + CC_SHA256_DIGEST_LENGTH + kCCBlockSizeAES128);
|
||||
if (cipherDataLength % kCCBlockSizeAES128 != 0) {
|
||||
return nil;
|
||||
}
|
||||
uint8_t *buffer = (uint8_t *)cipherText.bytes;
|
||||
|
||||
int offsetMAC = 1;
|
||||
int offsetIV = offsetMAC + CC_SHA256_DIGEST_LENGTH;
|
||||
int offsetCipherData = offsetIV + kCCBlockSizeAES128;
|
||||
|
||||
if (buffer[0] != kFBSDK_CRYPTO_CURRENT_VERSION) {
|
||||
return nil; // Version does not match
|
||||
}
|
||||
|
||||
NSData *IV = [NSData dataWithBytesNoCopy:buffer + offsetIV length:kCCBlockSizeAES128 freeWhenDone:NO];
|
||||
NSData *cipherData = [NSData dataWithBytesNoCopy:buffer + offsetCipherData length:cipherDataLength freeWhenDone:NO];
|
||||
NSData *mac = [self _macForIV:IV cipherData:cipherData additionalDataToSign:additionalSignedData];
|
||||
NSData *macFromStream = [NSData dataWithBytesNoCopy:buffer + offsetMAC length:CC_SHA256_DIGEST_LENGTH freeWhenDone:NO];
|
||||
if (![mac isEqualToData:macFromStream]) {
|
||||
return nil; // MAC does not match
|
||||
}
|
||||
|
||||
|
||||
uint8_t *outputBuffer = malloc(cipherDataLength);
|
||||
size_t numOutputBytes = 0;
|
||||
CCCryptorStatus cryptStatus = CCCrypt(kCCDecrypt, kCCAlgorithmAES128, 0,
|
||||
_encryptionKeyData.bytes, kCCKeySizeAES256,
|
||||
IV.bytes,
|
||||
buffer + offsetCipherData, cipherDataLength,
|
||||
outputBuffer, cipherDataLength,
|
||||
&numOutputBytes);
|
||||
if (cryptStatus == kCCSuccess) {
|
||||
int numPaddingBytes = outputBuffer[cipherDataLength - 1];
|
||||
if (!(numPaddingBytes >= 1 && numPaddingBytes <= kCCBlockSizeAES128)) {
|
||||
numPaddingBytes = 0;
|
||||
}
|
||||
return [NSData dataWithBytesNoCopy:outputBuffer length:cipherDataLength - numPaddingBytes];
|
||||
}
|
||||
free(outputBuffer);
|
||||
return nil;
|
||||
}
|
||||
|
||||
#pragma mark - Helper Methods
|
||||
|
||||
/**
|
||||
*
|
||||
* [IV 16 bytes] . [length of ciphertext 4 bytes] . [ciphertext] . [length of additionalDataToSign, 4 bytes] . [additionalDataToSign])
|
||||
* length is written in big-endian
|
||||
*/
|
||||
- (NSData *)_macForIV:(NSData *)IV cipherData:(NSData *)cipherData additionalDataToSign:(NSData *)additionalDataToSign
|
||||
{
|
||||
NSAssert(cipherData.length <= INT_MAX, @"");
|
||||
int cipherDataLength = (int)cipherData.length;
|
||||
|
||||
NSAssert(additionalDataToSign.length <= INT_MAX, @"");
|
||||
int additionalDataToSignLength = (int)additionalDataToSign.length;
|
||||
|
||||
size_t macBufferLength = kCCBlockSizeAES128 + 4 + cipherData.length + 4 + additionalDataToSign.length;
|
||||
uint8_t *macBuffer = malloc(macBufferLength);
|
||||
int offsetIV = 0;
|
||||
int offsetCipherTextLength = offsetIV + kCCBlockSizeAES128;
|
||||
int offsetCipherText = offsetCipherTextLength + 4;
|
||||
|
||||
int offsetAdditionalDataLength = offsetCipherText + cipherDataLength;
|
||||
int offsetAdditionalData = offsetAdditionalDataLength + 4;
|
||||
|
||||
// [IV 16 bytes]
|
||||
memcpy(macBuffer + offsetIV, IV.bytes, kCCBlockSizeAES128);
|
||||
// [length of ciphertext 4 bytes]
|
||||
FBSDKCryptoWriteIntBigEndian(macBuffer + offsetCipherTextLength, cipherDataLength);
|
||||
// [ciphertext]
|
||||
memcpy(macBuffer + offsetCipherText, cipherData.bytes, cipherDataLength);
|
||||
// [length of additionalDataToSign, 4 bytes]
|
||||
FBSDKCryptoWriteIntBigEndian(macBuffer + offsetAdditionalDataLength, additionalDataToSignLength);
|
||||
memcpy(macBuffer + offsetAdditionalData, additionalDataToSign.bytes, additionalDataToSignLength);
|
||||
|
||||
uint8_t *result = malloc(CC_SHA256_DIGEST_LENGTH);
|
||||
|
||||
CCHmac(kCCHmacAlgSHA256, _macKeyData.bytes, _macKeyData.length, macBuffer, macBufferLength, result);
|
||||
free(macBuffer);
|
||||
|
||||
return [NSData dataWithBytesNoCopy:result length:CC_SHA256_DIGEST_LENGTH];
|
||||
}
|
||||
|
||||
@end
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
// 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/FBSDKConstants.h>
|
||||
|
||||
@class FBSDKErrorRecoveryConfiguration;
|
||||
|
||||
@interface FBSDKErrorRecoveryAttempter : NSObject<FBSDKErrorRecoveryAttempting>
|
||||
|
||||
// can return nil if configuration is not supported.
|
||||
+ (instancetype)recoveryAttempterFromConfiguration:(FBSDKErrorRecoveryConfiguration *)configuration;
|
||||
|
||||
@end
|
||||
|
||||
@interface FBSDKErrorRecoveryAttempter (Protected)
|
||||
- (void)completeRecovery:(BOOL)didRecover delegate:(id)delegate didRecoverSelector:(SEL)didRecoverSelector contextInfo:(void *)contextInfo;
|
||||
@end
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
// 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 "FBSDKErrorRecoveryAttempter.h"
|
||||
|
||||
#import "_FBSDKTemporaryErrorRecoveryAttempter.h"
|
||||
#import "FBSDKErrorRecoveryConfiguration.h"
|
||||
|
||||
@implementation FBSDKErrorRecoveryAttempter
|
||||
|
||||
+ (instancetype)recoveryAttempterFromConfiguration:(FBSDKErrorRecoveryConfiguration *)configuration
|
||||
{
|
||||
if (configuration.errorCategory == FBSDKGraphRequestErrorCategoryTransient) {
|
||||
return [[_FBSDKTemporaryErrorRecoveryAttempter alloc] init];
|
||||
} else if (configuration.errorCategory == FBSDKGraphRequestErrorCategoryOther) {
|
||||
return nil;
|
||||
}
|
||||
if ([configuration.recoveryActionName isEqualToString:@"login"]) {
|
||||
Class loginRecoveryAttmpterClass = NSClassFromString(@"_FBSDKLoginRecoveryAttempter");
|
||||
if (loginRecoveryAttmpterClass) {
|
||||
return [[loginRecoveryAttmpterClass alloc] init];
|
||||
}
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (void)attemptRecoveryFromError:(NSError *)error optionIndex:(NSUInteger)recoveryOptionIndex delegate:(id)delegate didRecoverSelector:(SEL)didRecoverSelector contextInfo:(void *)contextInfo
|
||||
{
|
||||
// should be implemented by subclasses.
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation FBSDKErrorRecoveryAttempter(Protected)
|
||||
|
||||
- (void)completeRecovery:(BOOL)didRecover delegate:(id)delegate didRecoverSelector:(SEL)didRecoverSelector contextInfo:(void *)contextInfo
|
||||
{
|
||||
void (*callback)(id, SEL, BOOL, void *) = (void *)[delegate methodForSelector:didRecoverSelector];
|
||||
(*callback)(delegate, didRecoverSelector, didRecover, contextInfo);
|
||||
}
|
||||
|
||||
@end
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
// 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 "FBSDKErrorRecoveryAttempter.h"
|
||||
|
||||
@interface _FBSDKTemporaryErrorRecoveryAttempter : FBSDKErrorRecoveryAttempter
|
||||
|
||||
@end
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
// 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 "_FBSDKTemporaryErrorRecoveryAttempter.h"
|
||||
|
||||
@implementation _FBSDKTemporaryErrorRecoveryAttempter
|
||||
|
||||
- (void)attemptRecoveryFromError:(NSError *)error optionIndex:(NSUInteger)recoveryOptionIndex delegate:(id)delegate didRecoverSelector:(SEL)didRecoverSelector contextInfo:(void *)contextInfo
|
||||
{
|
||||
[super completeRecovery:YES delegate:delegate didRecoverSelector:didRecoverSelector contextInfo:contextInfo];
|
||||
}
|
||||
|
||||
@end
|
||||
Generated
+53
@@ -0,0 +1,53 @@
|
||||
// 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/FBSDKApplicationDelegate.h>
|
||||
#import <FBSDKCoreKit/FBSDKMacros.h>
|
||||
|
||||
#import "FBSDKCoreKit+Internal.h"
|
||||
|
||||
FBSDK_EXTERN NSString *const FBSDKApplicationDidBecomeActiveNotification;
|
||||
|
||||
@class FBSDKApplicationCall;
|
||||
|
||||
#if !TARGET_OS_TV
|
||||
typedef void(^FBSDKBridgeAPICallbackBlock)(FBSDKBridgeAPIResponse *response);
|
||||
#endif
|
||||
|
||||
@interface FBSDKApplicationDelegate ()
|
||||
#if !TARGET_OS_TV
|
||||
<FBSDKContainerViewControllerDelegate>
|
||||
|
||||
- (void)openBridgeAPIRequest:(FBSDKBridgeAPIRequest *)request
|
||||
useSafariViewController:(BOOL)useSafariViewController
|
||||
fromViewController:(UIViewController *)fromViewController
|
||||
completionBlock:(FBSDKBridgeAPICallbackBlock)completionBlock;
|
||||
|
||||
- (void)openURLWithSafariViewController:(NSURL *)url
|
||||
sender:(id<FBSDKURLOpening>)sender
|
||||
fromViewController:(UIViewController *)fromViewController
|
||||
handler:(void(^)(BOOL))handler;
|
||||
|
||||
- (void)openURL:(NSURL *)url sender:(id<FBSDKURLOpening>)sender handler:(void(^)(BOOL))handler;
|
||||
#endif
|
||||
|
||||
@property (nonatomic, readonly, getter=isActive) BOOL active;
|
||||
|
||||
@end
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
// 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>
|
||||
|
||||
@interface FBSDKAudioResourceLoader : NSObject
|
||||
|
||||
+ (instancetype)sharedLoader;
|
||||
|
||||
- (BOOL)loadSound:(NSError **)error;
|
||||
- (void)playSound;
|
||||
|
||||
@end
|
||||
|
||||
@interface FBSDKAudioResourceLoader (Subclass)
|
||||
|
||||
+ (NSString *)name;
|
||||
+ (NSUInteger)version;
|
||||
+ (NSData *)data;
|
||||
|
||||
@end
|
||||
+151
@@ -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 "FBSDKAudioResourceLoader.h"
|
||||
|
||||
#import "FBSDKDynamicFrameworkLoader.h"
|
||||
#import "FBSDKLogger.h"
|
||||
#import "FBSDKSettings.h"
|
||||
|
||||
@implementation FBSDKAudioResourceLoader
|
||||
{
|
||||
NSFileManager *_fileManager;
|
||||
NSURL *_fileURL;
|
||||
SystemSoundID _systemSoundID;
|
||||
}
|
||||
|
||||
#pragma mark - Class Methods
|
||||
|
||||
+ (instancetype)sharedLoader
|
||||
{
|
||||
static NSMutableDictionary *_loaderCache = nil;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
_loaderCache = [[NSMutableDictionary alloc] init];
|
||||
});
|
||||
|
||||
NSString *name = [self name];
|
||||
FBSDKAudioResourceLoader *loader;
|
||||
@synchronized(_loaderCache) {
|
||||
loader = _loaderCache[name];
|
||||
if (!loader) {
|
||||
loader = [[self alloc] init];
|
||||
NSError *error = nil;
|
||||
if ([loader loadSound:&error]) {
|
||||
_loaderCache[name] = loader;
|
||||
} else {
|
||||
[FBSDKLogger singleShotLogEntry:FBSDKLoggingBehaviorDeveloperErrors
|
||||
formatString:@"%@ error: %@", self, error];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return loader;
|
||||
}
|
||||
|
||||
#pragma mark - Object Lifecycle
|
||||
|
||||
- (instancetype)init
|
||||
{
|
||||
if ((self = [super init])) {
|
||||
_fileManager = [[NSFileManager alloc] init];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
fbsdkdfl_AudioServicesDisposeSystemSoundID(_systemSoundID);
|
||||
}
|
||||
|
||||
#pragma mark - Public API
|
||||
|
||||
- (BOOL)loadSound:(NSError **)errorRef
|
||||
{
|
||||
NSURL *fileURL = [self _fileURL:errorRef];
|
||||
|
||||
if (![_fileManager fileExistsAtPath:[fileURL path]]) {
|
||||
NSData *data = [[self class] data];
|
||||
if (![data writeToURL:fileURL options:NSDataWritingAtomic error:errorRef]) {
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
|
||||
OSStatus status = fbsdkdfl_AudioServicesCreateSystemSoundID((__bridge CFURLRef)fileURL, &_systemSoundID);
|
||||
return (status == kAudioServicesNoError);
|
||||
}
|
||||
|
||||
- (void)playSound
|
||||
{
|
||||
if ((_systemSoundID == 0) && ![self loadSound:NULL]) {
|
||||
return;
|
||||
}
|
||||
fbsdkdfl_AudioServicesPlaySystemSound(_systemSoundID);
|
||||
}
|
||||
|
||||
#pragma mark - Helper Methods
|
||||
|
||||
- (NSURL *)_fileURL:(NSError **)errorRef
|
||||
{
|
||||
if (_fileURL) {
|
||||
return _fileURL;
|
||||
}
|
||||
|
||||
NSURL *baseURL = [_fileManager URLForDirectory:NSCachesDirectory
|
||||
inDomain:NSUserDomainMask
|
||||
appropriateForURL:nil
|
||||
create:YES
|
||||
error:errorRef];
|
||||
if (!baseURL) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
NSURL *directoryURL = [baseURL URLByAppendingPathComponent:@"fb_audio" isDirectory:YES];
|
||||
NSURL *versionURL = [directoryURL URLByAppendingPathComponent:[NSString stringWithFormat:@"%lu", (unsigned long)[[self class] version]]
|
||||
isDirectory:YES];
|
||||
if (![_fileManager createDirectoryAtURL:versionURL withIntermediateDirectories:YES attributes:nil error:errorRef]) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
_fileURL = [[versionURL URLByAppendingPathComponent:[[self class] name]] copy];
|
||||
|
||||
return _fileURL;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation FBSDKAudioResourceLoader (Subclass)
|
||||
|
||||
#pragma mark - Subclass Methods
|
||||
|
||||
+ (NSString *)name
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
+ (NSUInteger)version
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
+ (NSData *)data
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
@end
|
||||
Generated
+35
@@ -0,0 +1,35 @@
|
||||
// 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 <UIKit/UIKit.h>
|
||||
|
||||
@class FBSDKContainerViewController;
|
||||
|
||||
@protocol FBSDKContainerViewControllerDelegate <NSObject>
|
||||
|
||||
- (void)viewControllerDidDisappear:(FBSDKContainerViewController *)viewController animated:(BOOL)animated;
|
||||
|
||||
@end
|
||||
|
||||
@interface FBSDKContainerViewController : UIViewController
|
||||
|
||||
@property (nonatomic, weak) id<FBSDKContainerViewControllerDelegate> delegate;
|
||||
|
||||
- (void)displayChildController:(UIViewController *)childController;
|
||||
|
||||
@end
|
||||
Generated
+78
@@ -0,0 +1,78 @@
|
||||
// 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 "FBSDKContainerViewController.h"
|
||||
|
||||
@implementation FBSDKContainerViewController
|
||||
|
||||
- (void)viewDidDisappear:(BOOL)animated
|
||||
{
|
||||
[super viewDidDisappear:animated];
|
||||
if ([self.delegate respondsToSelector:@selector(viewControllerDidDisappear:animated:)]) {
|
||||
[self.delegate viewControllerDidDisappear:self animated:animated];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)displayChildController:(UIViewController *)childController
|
||||
{
|
||||
[self addChildViewController:childController];
|
||||
UIView *view = self.view;
|
||||
UIView *childView = childController.view;
|
||||
childView.translatesAutoresizingMaskIntoConstraints = NO;
|
||||
childView.frame = view.frame;
|
||||
[view addSubview:childView];
|
||||
|
||||
[view addConstraints:
|
||||
@[
|
||||
[NSLayoutConstraint constraintWithItem:childView
|
||||
attribute:NSLayoutAttributeTop
|
||||
relatedBy:NSLayoutRelationEqual
|
||||
toItem:view
|
||||
attribute:NSLayoutAttributeTop
|
||||
multiplier:1.0
|
||||
constant:0.0],
|
||||
|
||||
[NSLayoutConstraint constraintWithItem:childView
|
||||
attribute:NSLayoutAttributeBottom
|
||||
relatedBy:NSLayoutRelationEqual
|
||||
toItem:view
|
||||
attribute:NSLayoutAttributeBottom
|
||||
multiplier:1.0
|
||||
constant:0.0],
|
||||
|
||||
[NSLayoutConstraint constraintWithItem:childView
|
||||
attribute:NSLayoutAttributeLeading
|
||||
relatedBy:NSLayoutRelationEqual
|
||||
toItem:view
|
||||
attribute:NSLayoutAttributeLeading
|
||||
multiplier:1.0
|
||||
constant:0.0],
|
||||
|
||||
[NSLayoutConstraint constraintWithItem:childView
|
||||
attribute:NSLayoutAttributeTrailing
|
||||
relatedBy:NSLayoutRelationEqual
|
||||
toItem:view
|
||||
attribute:NSLayoutAttributeTrailing
|
||||
multiplier:1.0
|
||||
constant:0.0],
|
||||
]];
|
||||
|
||||
[childController didMoveToParentViewController:self];
|
||||
}
|
||||
|
||||
@end
|
||||
+72
@@ -0,0 +1,72 @@
|
||||
// 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 <UIKit/UIKit.h>
|
||||
|
||||
#import <FBSDKCoreKit/FBSDKCoreKit.h>
|
||||
|
||||
#if !TARGET_OS_TV
|
||||
#import "BridgeAPI/FBSDKBridgeAPIProtocol.h"
|
||||
#import "BridgeAPI/FBSDKBridgeAPIProtocolType.h"
|
||||
#import "BridgeAPI/FBSDKBridgeAPIRequest.h"
|
||||
#import "BridgeAPI/FBSDKBridgeAPIResponse.h"
|
||||
#import "BridgeAPI/FBSDKURLOpening.h"
|
||||
#import "Cryptography/FBSDKCrypto.h"
|
||||
#import "FBSDKAudioResourceLoader.h"
|
||||
#import "FBSDKContainerViewController.h"
|
||||
#import "FBSDKMonotonicTime.h"
|
||||
#import "FBSDKSystemAccountStoreAdapter.h"
|
||||
#import "FBSDKTriStateBOOL.h"
|
||||
#import "UI/FBSDKCloseIcon.h"
|
||||
#import "UI/FBSDKColor.h"
|
||||
#import "UI/FBSDKMaleSilhouetteIcon.h"
|
||||
#import "UI/FBSDKUIUtility.h"
|
||||
#import "UI/FBSDKViewImpressionTracker.h"
|
||||
#import "WebDialog/FBSDKWebDialog.h"
|
||||
#endif
|
||||
|
||||
#import "AppEvents/FBSDKAppEvents+Internal.h"
|
||||
#import "AppEvents/FBSDKAppEventsState.h"
|
||||
#import "AppEvents/FBSDKAppEventsStateManager.h"
|
||||
#import "AppEvents/FBSDKAppEventsUtility.h"
|
||||
#import "AppEvents/FBSDKTimeSpentData.h"
|
||||
#import "Base64/FBSDKBase64.h"
|
||||
#import "ErrorRecovery/FBSDKErrorRecoveryAttempter.h"
|
||||
#import "FBSDKDynamicFrameworkLoader.h"
|
||||
#import "FBSDKApplicationDelegate+Internal.h"
|
||||
#import "FBSDKError.h"
|
||||
#import "FBSDKInternalUtility.h"
|
||||
#import "FBSDKLogger.h"
|
||||
#import "FBSDKMath.h"
|
||||
#import "FBSDKTypeUtility.h"
|
||||
#import "Network/FBSDKGraphRequest+Internal.h"
|
||||
#import "Network/FBSDKGraphRequestConnection+Internal.h"
|
||||
#import "Network/FBSDKGraphRequestMetadata.h"
|
||||
#import "ServerConfiguration/FBSDKDialogConfiguration.h"
|
||||
#import "ServerConfiguration/FBSDKServerConfiguration+Internal.h"
|
||||
#import "ServerConfiguration/FBSDKServerConfiguration.h"
|
||||
#import "ServerConfiguration/FBSDKServerConfigurationManager+Internal.h"
|
||||
#import "ServerConfiguration/FBSDKServerConfigurationManager.h"
|
||||
#import "TokenCaching/FBSDKAccessTokenCache.h"
|
||||
#import "TokenCaching/FBSDKAccessTokenCaching.h"
|
||||
#import "TokenCaching/FBSDKKeychainStore.h"
|
||||
#import "TokenCaching/FBSDKKeychainStoreViaBundleID.h"
|
||||
#import "UI/FBSDKButton+Subclass.h"
|
||||
#import "UI/FBSDKIcon.h"
|
||||
#import "UI/FBSDKLogo.h"
|
||||
|
||||
Generated
+236
@@ -0,0 +1,236 @@
|
||||
// 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 <sqlite3.h>
|
||||
|
||||
#import <AudioToolbox/AudioToolbox.h>
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <QuartzCore/QuartzCore.h>
|
||||
|
||||
#import <FBSDKCoreKit/FBSDKMacros.h>
|
||||
|
||||
/*!
|
||||
@class FBSDKDynamicFrameworkLoader
|
||||
|
||||
@abstract
|
||||
This class provides a way to load constants and methods from Apple Frameworks in a dynamic
|
||||
fashion. It allows the SDK to be just dragged into a project without having to specify additional
|
||||
frameworks to link against. It is an internal class and not to be used by 3rd party developers.
|
||||
|
||||
As new types are needed, they should be added and strongly typed.
|
||||
*/
|
||||
@interface FBSDKDynamicFrameworkLoader : NSObject
|
||||
|
||||
#pragma mark - Security Constants
|
||||
|
||||
/*!
|
||||
@abstract
|
||||
Load the kSecRandomDefault value from the Security Framework
|
||||
|
||||
@return The kSecRandomDefault value or nil.
|
||||
*/
|
||||
+ (SecRandomRef)loadkSecRandomDefault;
|
||||
|
||||
/*!
|
||||
@abstract
|
||||
Load the kSecAttrAccessible value from the Security Framework
|
||||
|
||||
@return The kSecAttrAccessible value or nil.
|
||||
*/
|
||||
+ (CFTypeRef)loadkSecAttrAccessible;
|
||||
|
||||
/*!
|
||||
@abstract
|
||||
Load the kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly value from the Security Framework
|
||||
|
||||
@return The kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly value or nil.
|
||||
*/
|
||||
+ (CFTypeRef)loadkSecAttrAccessibleAfterFirstUnlockThisDeviceOnly;
|
||||
|
||||
/*!
|
||||
@abstract
|
||||
Load the kSecAttrAccount value from the Security Framework
|
||||
|
||||
@return The kSecAttrAccount value or nil.
|
||||
*/
|
||||
+ (CFTypeRef)loadkSecAttrAccount;
|
||||
|
||||
/*!
|
||||
@abstract
|
||||
Load the kSecAttrService value from the Security Framework
|
||||
|
||||
@return The kSecAttrService value or nil.
|
||||
*/
|
||||
+ (CFTypeRef)loadkSecAttrService;
|
||||
|
||||
/*!
|
||||
@abstract
|
||||
Load the kSecAttrGeneric value from the Security Framework
|
||||
|
||||
@return The kSecAttrGeneric value or nil.
|
||||
*/
|
||||
+ (CFTypeRef)loadkSecAttrGeneric;
|
||||
|
||||
/*!
|
||||
@abstract
|
||||
Load the kSecValueData value from the Security Framework
|
||||
|
||||
@return The kSecValueData value or nil.
|
||||
*/
|
||||
+ (CFTypeRef)loadkSecValueData;
|
||||
|
||||
/*!
|
||||
@abstract
|
||||
Load the kSecClassGenericPassword value from the Security Framework
|
||||
|
||||
@return The kSecClassGenericPassword value or nil.
|
||||
*/
|
||||
+ (CFTypeRef)loadkSecClassGenericPassword;
|
||||
|
||||
/*!
|
||||
@abstract
|
||||
Load the kSecAttrAccessGroup value from the Security Framework
|
||||
|
||||
@return The kSecAttrAccessGroup value or nil.
|
||||
*/
|
||||
+ (CFTypeRef)loadkSecAttrAccessGroup;
|
||||
|
||||
/*!
|
||||
@abstract
|
||||
Load the kSecMatchLimitOne value from the Security Framework
|
||||
|
||||
@return The kSecMatchLimitOne value or nil.
|
||||
*/
|
||||
+ (CFTypeRef)loadkSecMatchLimitOne;
|
||||
|
||||
/*!
|
||||
@abstract
|
||||
Load the kSecMatchLimit value from the Security Framework
|
||||
|
||||
@return The kSecMatchLimit value or nil.
|
||||
*/
|
||||
+ (CFTypeRef)loadkSecMatchLimit;
|
||||
|
||||
/*!
|
||||
@abstract
|
||||
Load the kSecReturnData value from the Security Framework
|
||||
|
||||
@return The kSecReturnData value or nil.
|
||||
*/
|
||||
+ (CFTypeRef)loadkSecReturnData;
|
||||
|
||||
/*!
|
||||
@abstract
|
||||
Load the kSecClass value from the Security Framework
|
||||
|
||||
@return The kSecClass value or nil.
|
||||
*/
|
||||
+ (CFTypeRef)loadkSecClass;
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark - Security APIs
|
||||
|
||||
// These are local wrappers around the corresponding methods in Security/SecRandom.h
|
||||
FBSDK_EXTERN int fbsdkdfl_SecRandomCopyBytes(SecRandomRef rnd, size_t count, uint8_t *bytes);
|
||||
|
||||
// These are local wrappers around Keychain API
|
||||
FBSDK_EXTERN OSStatus fbsdkdfl_SecItemUpdate(CFDictionaryRef query, CFDictionaryRef attributesToUpdate);
|
||||
FBSDK_EXTERN OSStatus fbsdkdfl_SecItemAdd(CFDictionaryRef attributes, CFTypeRef *result);
|
||||
FBSDK_EXTERN OSStatus fbsdkdfl_SecItemCopyMatching(CFDictionaryRef query, CFTypeRef *result);
|
||||
FBSDK_EXTERN OSStatus fbsdkdfl_SecItemDelete(CFDictionaryRef query);
|
||||
|
||||
#pragma mark - sqlite3 APIs
|
||||
|
||||
// These are local wrappers around the corresponding sqlite3 method from /usr/include/sqlite3.h
|
||||
FBSDK_EXTERN SQLITE_API const char *fbsdkdfl_sqlite3_errmsg(sqlite3 *db);
|
||||
FBSDK_EXTERN SQLITE_API int fbsdkdfl_sqlite3_prepare_v2(sqlite3 *db, const char *zSql, int nByte, sqlite3_stmt **ppStmt, const char **pzTail);
|
||||
FBSDK_EXTERN SQLITE_API int fbsdkdfl_sqlite3_reset(sqlite3_stmt *pStmt);
|
||||
FBSDK_EXTERN SQLITE_API int fbsdkdfl_sqlite3_finalize(sqlite3_stmt *pStmt);
|
||||
FBSDK_EXTERN SQLITE_API int fbsdkdfl_sqlite3_open_v2(const char *filename, sqlite3 **ppDb, int flags, const char *zVfs);
|
||||
FBSDK_EXTERN SQLITE_API int fbsdkdfl_sqlite3_exec(sqlite3 *db, const char *sql, int (*callback)(void *, int, char **, char **), void *arg, char **errmsg);
|
||||
FBSDK_EXTERN SQLITE_API int fbsdkdfl_sqlite3_close(sqlite3 *db);
|
||||
FBSDK_EXTERN SQLITE_API int fbsdkdfl_sqlite3_bind_double(sqlite3_stmt *stmt, int index, double value);
|
||||
FBSDK_EXTERN SQLITE_API int fbsdkdfl_sqlite3_bind_int(sqlite3_stmt *stmt, int index, int value);
|
||||
FBSDK_EXTERN SQLITE_API int fbsdkdfl_sqlite3_bind_text(sqlite3_stmt *stmt, int index, const char *value, int n, void(*callback)(void *));
|
||||
FBSDK_EXTERN SQLITE_API int fbsdkdfl_sqlite3_step(sqlite3_stmt *stmt);
|
||||
FBSDK_EXTERN SQLITE_API double fbsdkdfl_sqlite3_column_double(sqlite3_stmt *stmt, int iCol);
|
||||
FBSDK_EXTERN SQLITE_API int fbsdkdfl_sqlite3_column_int(sqlite3_stmt *stmt, int iCol);
|
||||
FBSDK_EXTERN SQLITE_API const unsigned char *fbsdkdfl_sqlite3_column_text(sqlite3_stmt *stmt, int iCol);
|
||||
|
||||
#pragma mark - Social Constants
|
||||
|
||||
FBSDK_EXTERN NSString *fbsdkdfl_SLServiceTypeFacebook(void);
|
||||
|
||||
#pragma mark - Social Classes
|
||||
|
||||
FBSDK_EXTERN Class fbsdkdfl_SLComposeViewControllerClass(void);
|
||||
|
||||
#pragma mark - QuartzCore Classes
|
||||
|
||||
FBSDK_EXTERN Class fbsdkdfl_CATransactionClass(void);
|
||||
|
||||
#pragma mark - QuartzCore APIs
|
||||
|
||||
// These are local wrappers around the corresponding transform methods from QuartzCore.framework/CATransform3D.h
|
||||
FBSDK_EXTERN CATransform3D fbsdkdfl_CATransform3DMakeScale (CGFloat sx, CGFloat sy, CGFloat sz);
|
||||
FBSDK_EXTERN CATransform3D fbsdkdfl_CATransform3DMakeTranslation (CGFloat tx, CGFloat ty, CGFloat tz);
|
||||
FBSDK_EXTERN CATransform3D fbsdkdfl_CATransform3DConcat (CATransform3D a, CATransform3D b);
|
||||
|
||||
FBSDK_EXTERN const CATransform3D fbsdkdfl_CATransform3DIdentity;
|
||||
|
||||
#pragma mark - AudioToolbox APIs
|
||||
|
||||
// These are local wrappers around the corresponding methods in AudioToolbox/AudioToolbox.h
|
||||
FBSDK_EXTERN OSStatus fbsdkdfl_AudioServicesCreateSystemSoundID(CFURLRef inFileURL, SystemSoundID *outSystemSoundID);
|
||||
FBSDK_EXTERN OSStatus fbsdkdfl_AudioServicesDisposeSystemSoundID(SystemSoundID inSystemSoundID);
|
||||
FBSDK_EXTERN void fbsdkdfl_AudioServicesPlaySystemSound(SystemSoundID inSystemSoundID);
|
||||
|
||||
#pragma mark - AdSupport Classes
|
||||
|
||||
FBSDK_EXTERN Class fbsdkdfl_ASIdentifierManagerClass(void);
|
||||
|
||||
#pragma mark - SafariServices Classes
|
||||
|
||||
FBSDK_EXTERN Class fbsdkdfl_SFSafariViewControllerClass(void);
|
||||
|
||||
#pragma mark - Accounts Constants
|
||||
|
||||
FBSDK_EXTERN NSString *fbsdkdfl_ACFacebookAppIdKey(void);
|
||||
FBSDK_EXTERN NSString *fbsdkdfl_ACFacebookAudienceEveryone(void);
|
||||
FBSDK_EXTERN NSString *fbsdkdfl_ACFacebookAudienceFriends(void);
|
||||
FBSDK_EXTERN NSString *fbsdkdfl_ACFacebookAudienceKey(void);
|
||||
FBSDK_EXTERN NSString *fbsdkdfl_ACFacebookAudienceOnlyMe(void);
|
||||
FBSDK_EXTERN NSString *fbsdkdfl_ACFacebookPermissionsKey(void);
|
||||
|
||||
#pragma mark - Accounts Classes
|
||||
|
||||
FBSDK_EXTERN Class fbsdkdfl_ACAccountStoreClass(void);
|
||||
|
||||
#pragma mark - StoreKit classes
|
||||
|
||||
FBSDK_EXTERN Class fbsdkdfl_SKPaymentQueueClass(void);
|
||||
FBSDK_EXTERN Class fbsdkdfl_SKProductsRequestClass(void);
|
||||
|
||||
#pragma mark - AssetsLibrary Classes
|
||||
|
||||
FBSDK_EXTERN Class fbsdkdfl_ALAssetsLibraryClass(void);
|
||||
|
||||
#pragma mark - CoreTelephony Classes
|
||||
|
||||
FBSDK_EXTERN Class fbsdkdfl_CTTelephonyNetworkInfoClass(void);
|
||||
@@ -0,0 +1,56 @@
|
||||
// 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>
|
||||
|
||||
@interface FBSDKError : NSObject
|
||||
|
||||
+ (NSString *)errorDomain;
|
||||
|
||||
+ (BOOL)errorIsNetworkError:(NSError *)error;
|
||||
|
||||
+ (NSError *)errorWithCode:(NSInteger)code message:(NSString *)message;
|
||||
+ (NSError *)errorWithCode:(NSInteger)code message:(NSString *)message underlyingError:(NSError *)underlyingError;
|
||||
+ (NSError *)errorWithCode:(NSInteger)code
|
||||
userInfo:(NSDictionary *)userInfo
|
||||
message:(NSString *)message
|
||||
underlyingError:(NSError *)underlyingError;
|
||||
|
||||
+ (NSError *)invalidArgumentErrorWithName:(NSString *)name value:(id)value message:(NSString *)message;
|
||||
+ (NSError *)invalidArgumentErrorWithName:(NSString *)name
|
||||
value:(id)value
|
||||
message:(NSString *)message
|
||||
underlyingError:(NSError *)underlyingError;
|
||||
+ (NSError *)invalidCollectionErrorWithName:(NSString *)name
|
||||
collection:(id<NSFastEnumeration>)collection
|
||||
item:(id)item
|
||||
message:(NSString *)message;
|
||||
+ (NSError *)invalidCollectionErrorWithName:(NSString *)name
|
||||
collection:(id<NSFastEnumeration>)collection
|
||||
item:(id)item
|
||||
message:(NSString *)message
|
||||
underlyingError:(NSError *)underlyingError;
|
||||
|
||||
+ (NSError *)requiredArgumentErrorWithName:(NSString *)name message:(NSString *)message;
|
||||
+ (NSError *)requiredArgumentErrorWithName:(NSString *)name
|
||||
message:(NSString *)message
|
||||
underlyingError:(NSError *)underlyingError;
|
||||
|
||||
+ (NSError *)unknownErrorWithMessage:(NSString *)message;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,163 @@
|
||||
// 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 "FBSDKError.h"
|
||||
|
||||
#import "FBSDKConstants.h"
|
||||
#import "FBSDKInternalUtility.h"
|
||||
#import "FBSDKTypeUtility.h"
|
||||
|
||||
@implementation FBSDKError
|
||||
|
||||
#pragma mark - Class Methods
|
||||
|
||||
+ (NSString *)errorDomain
|
||||
{
|
||||
return FBSDKErrorDomain;
|
||||
}
|
||||
|
||||
+ (BOOL)errorIsNetworkError:(NSError *)error
|
||||
{
|
||||
if (error == nil) {
|
||||
return NO;
|
||||
}
|
||||
|
||||
NSError *innerError = error.userInfo[NSUnderlyingErrorKey];
|
||||
if ([self errorIsNetworkError:innerError]) {
|
||||
return YES;
|
||||
}
|
||||
|
||||
switch (error.code) {
|
||||
case NSURLErrorTimedOut:
|
||||
case NSURLErrorCannotFindHost:
|
||||
case NSURLErrorCannotConnectToHost:
|
||||
case NSURLErrorNetworkConnectionLost:
|
||||
case NSURLErrorDNSLookupFailed:
|
||||
case NSURLErrorNotConnectedToInternet:
|
||||
case NSURLErrorInternationalRoamingOff:
|
||||
case NSURLErrorCallIsActive:
|
||||
case NSURLErrorDataNotAllowed:
|
||||
return YES;
|
||||
default:
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
|
||||
+ (NSError *)errorWithCode:(NSInteger)code message:(NSString *)message
|
||||
{
|
||||
return [self errorWithCode:code message:message underlyingError:nil];
|
||||
}
|
||||
|
||||
+ (NSError *)errorWithCode:(NSInteger)code message:(NSString *)message underlyingError:(NSError *)underlyingError
|
||||
{
|
||||
return [self errorWithCode:code userInfo:nil message:message underlyingError:underlyingError];
|
||||
}
|
||||
|
||||
+ (NSError *)errorWithCode:(NSInteger)code
|
||||
userInfo:(NSDictionary *)userInfo
|
||||
message:(NSString *)message
|
||||
underlyingError:(NSError *)underlyingError
|
||||
{
|
||||
NSMutableDictionary *fullUserInfo = [[NSMutableDictionary alloc] initWithDictionary:userInfo];
|
||||
[FBSDKInternalUtility dictionary:fullUserInfo setObject:message forKey:FBSDKErrorDeveloperMessageKey];
|
||||
[FBSDKInternalUtility dictionary:fullUserInfo setObject:underlyingError forKey:NSUnderlyingErrorKey];
|
||||
userInfo = ([fullUserInfo count] ? [fullUserInfo copy] : nil);
|
||||
return [[NSError alloc] initWithDomain:[self errorDomain] code:code userInfo:userInfo];
|
||||
}
|
||||
|
||||
+ (NSError *)invalidArgumentErrorWithName:(NSString *)name value:(id)value message:(NSString *)message
|
||||
{
|
||||
return [self invalidArgumentErrorWithName:name value:value message:message underlyingError:nil];
|
||||
}
|
||||
|
||||
+ (NSError *)invalidArgumentErrorWithName:(NSString *)name
|
||||
value:(id)value
|
||||
message:(NSString *)message
|
||||
underlyingError:(NSError *)underlyingError
|
||||
{
|
||||
if (!message) {
|
||||
message = [[NSString alloc] initWithFormat:@"Invalid value for %@: %@", name, value];
|
||||
}
|
||||
NSMutableDictionary *userInfo = [[NSMutableDictionary alloc] init];
|
||||
[FBSDKInternalUtility dictionary:userInfo setObject:name forKey:FBSDKErrorArgumentNameKey];
|
||||
[FBSDKInternalUtility dictionary:userInfo setObject:value forKey:FBSDKErrorArgumentValueKey];
|
||||
return [self errorWithCode:FBSDKInvalidArgumentErrorCode
|
||||
userInfo:userInfo
|
||||
message:message
|
||||
underlyingError:underlyingError];
|
||||
}
|
||||
|
||||
+ (NSError *)invalidCollectionErrorWithName:(NSString *)name
|
||||
collection:(id<NSFastEnumeration>)collection
|
||||
item:(id)item
|
||||
message:(NSString *)message
|
||||
{
|
||||
return [self invalidCollectionErrorWithName:name collection:collection item:item message:message underlyingError:nil];
|
||||
}
|
||||
|
||||
+ (NSError *)invalidCollectionErrorWithName:(NSString *)name
|
||||
collection:(id<NSFastEnumeration>)collection
|
||||
item:(id)item
|
||||
message:(NSString *)message
|
||||
underlyingError:(NSError *)underlyingError
|
||||
{
|
||||
if (!message) {
|
||||
message = [[NSString alloc] initWithFormat:@"Invalid item (%@) found in collection for %@: %@", item, name, collection];
|
||||
}
|
||||
NSMutableDictionary *userInfo = [[NSMutableDictionary alloc] init];
|
||||
[FBSDKInternalUtility dictionary:userInfo setObject:name forKey:FBSDKErrorArgumentNameKey];
|
||||
[FBSDKInternalUtility dictionary:userInfo setObject:item forKey:FBSDKErrorArgumentValueKey];
|
||||
[FBSDKInternalUtility dictionary:userInfo setObject:collection forKey:FBSDKErrorArgumentCollectionKey];
|
||||
return [self errorWithCode:FBSDKInvalidArgumentErrorCode
|
||||
userInfo:userInfo
|
||||
message:message
|
||||
underlyingError:underlyingError];
|
||||
}
|
||||
|
||||
+ (NSError *)requiredArgumentErrorWithName:(NSString *)name message:(NSString *)message
|
||||
{
|
||||
return [self requiredArgumentErrorWithName:name message:message underlyingError:nil];
|
||||
}
|
||||
|
||||
+ (NSError *)requiredArgumentErrorWithName:(NSString *)name
|
||||
message:(NSString *)message
|
||||
underlyingError:(NSError *)underlyingError
|
||||
{
|
||||
if (!message) {
|
||||
message = [[NSString alloc] initWithFormat:@"Value for %@ is required.", name];
|
||||
}
|
||||
return [self invalidArgumentErrorWithName:name value:nil message:message underlyingError:underlyingError];
|
||||
}
|
||||
|
||||
+ (NSError *)unknownErrorWithMessage:(NSString *)message
|
||||
{
|
||||
return [self errorWithCode:FBSDKUnknownErrorCode
|
||||
userInfo:nil
|
||||
message:message
|
||||
underlyingError:nil];
|
||||
}
|
||||
|
||||
#pragma mark - Object Lifecycle
|
||||
|
||||
- (instancetype)init
|
||||
{
|
||||
FBSDK_NO_DESIGNATED_INITIALIZER();
|
||||
return nil;
|
||||
}
|
||||
|
||||
@end
|
||||
+336
@@ -0,0 +1,336 @@
|
||||
// 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 <UIKit/UIKit.h>
|
||||
|
||||
#define FBSDK_CANOPENURL_FACEBOOK @"fbauth2"
|
||||
#define FBSDK_CANOPENURL_MESSENGER @"fb-messenger-api"
|
||||
|
||||
typedef NS_ENUM(int32_t, FBSDKUIKitVersion)
|
||||
{
|
||||
FBSDKUIKitVersion_6_0 = 0x0944,
|
||||
FBSDKUIKitVersion_6_1 = 0x094C,
|
||||
FBSDKUIKitVersion_7_0 = 0x0B57,
|
||||
FBSDKUIKitVersion_7_1 = 0x0B77,
|
||||
FBSDKUIKitVersion_8_0 = 0x0CF6,
|
||||
};
|
||||
|
||||
@interface FBSDKInternalUtility : NSObject
|
||||
|
||||
/*!
|
||||
@abstract Constructs the scheme for apps that come to the current app through the bridge.
|
||||
*/
|
||||
+ (NSString *)appURLScheme;
|
||||
|
||||
/*!
|
||||
@abstract Constructs an URL for the current app.
|
||||
@param host The host for the URL.
|
||||
@param path The path for the URL.
|
||||
@param queryParameters The query parameters for the URL. This will be converted into a query string.
|
||||
@param errorRef If an error occurs, upon return contains an NSError object that describes the problem.
|
||||
@return The app URL.
|
||||
*/
|
||||
+ (NSURL *)appURLWithHost:(NSString *)host
|
||||
path:(NSString *)path
|
||||
queryParameters:(NSDictionary *)queryParameters
|
||||
error:(NSError *__autoreleasing *)errorRef;
|
||||
|
||||
/*!
|
||||
@abstract Parses an FB url's query params (and potentially fragment) into a dictionary.
|
||||
@param url The FB url.
|
||||
@return A dictionary with the key/value pairs.
|
||||
*/
|
||||
+ (NSDictionary *)dictionaryFromFBURL:(NSURL *)url;
|
||||
|
||||
/*!
|
||||
@abstract Adds an object to an array if it is not nil.
|
||||
@param array The array to add the object to.
|
||||
@param object The object to add to the array.
|
||||
*/
|
||||
+ (void)array:(NSMutableArray *)array addObject:(id)object;
|
||||
|
||||
/*!
|
||||
@abstract Returns bundle for returning localized strings
|
||||
@discussion We assume a convention of a bundle named FBSDKStrings.bundle, otherwise we
|
||||
return the main bundle.
|
||||
*/
|
||||
+ (NSBundle *)bundleForStrings;
|
||||
|
||||
/*!
|
||||
@abstract Converts simple value types to the string equivelant for serializing to a request query or body.
|
||||
@param value The value to be converted.
|
||||
@return The value that may have been converted if able (otherwise the input param).
|
||||
*/
|
||||
+ (id)convertRequestValue:(id)value;
|
||||
|
||||
/*!
|
||||
@abstract Gets the milliseconds since the Unix Epoch.
|
||||
@discussion Changes in the system clock will affect this value.
|
||||
@return The number of milliseconds since the Unix Epoch.
|
||||
*/
|
||||
+ (unsigned long)currentTimeInMilliseconds;
|
||||
|
||||
/*!
|
||||
@abstract Sets an object for a key in a dictionary if it is not nil.
|
||||
@param dictionary The dictionary to set the value for.
|
||||
@param object The value to set after serializing to JSON.
|
||||
@param key The key to set the value for.
|
||||
@param errorRef If an error occurs, upon return contains an NSError object that describes the problem.
|
||||
@return NO if an error occurred while serializing the object, otherwise YES.
|
||||
*/
|
||||
+ (BOOL)dictionary:(NSMutableDictionary *)dictionary
|
||||
setJSONStringForObject:(id)object
|
||||
forKey:(id<NSCopying>)key
|
||||
error:(NSError *__autoreleasing *)errorRef;
|
||||
|
||||
/*!
|
||||
@abstract Sets an object for a key in a dictionary if it is not nil.
|
||||
@param dictionary The dictionary to set the value for.
|
||||
@param object The value to set.
|
||||
@param key The key to set the value for.
|
||||
*/
|
||||
+ (void)dictionary:(NSMutableDictionary *)dictionary setObject:(id)object forKey:(id<NSCopying>)key;
|
||||
|
||||
/*!
|
||||
@abstract Constructs a Facebook URL.
|
||||
@param hostPrefix The prefix for the host, such as 'm', 'graph', etc.
|
||||
@param path The path for the URL. This may or may not include a version.
|
||||
@param queryParameters The query parameters for the URL. This will be converted into a query string.
|
||||
@param errorRef If an error occurs, upon return contains an NSError object that describes the problem.
|
||||
@return The Facebook URL.
|
||||
*/
|
||||
+ (NSURL *)facebookURLWithHostPrefix:(NSString *)hostPrefix
|
||||
path:(NSString *)path
|
||||
queryParameters:(NSDictionary *)queryParameters
|
||||
error:(NSError *__autoreleasing *)errorRef;
|
||||
|
||||
/*!
|
||||
@abstract Constructs a Facebook URL.
|
||||
@param hostPrefix The prefix for the host, such as 'm', 'graph', etc.
|
||||
@param path The path for the URL. This may or may not include a version.
|
||||
@param queryParameters The query parameters for the URL. This will be converted into a query string.
|
||||
@param defaultVersion A version to add to the URL if none is found in the path.
|
||||
@param errorRef If an error occurs, upon return contains an NSError object that describes the problem.
|
||||
@return The Facebook URL.
|
||||
*/
|
||||
+ (NSURL *)facebookURLWithHostPrefix:(NSString *)hostPrefix
|
||||
path:(NSString *)path
|
||||
queryParameters:(NSDictionary *)queryParameters
|
||||
defaultVersion:(NSString *)defaultVersion
|
||||
error:(NSError *__autoreleasing *)errorRef;
|
||||
|
||||
/*!
|
||||
@abstract Tests whether the supplied URL is a valid URL for opening in the browser.
|
||||
@param URL The URL to test.
|
||||
@return YES if the URL refers to an http or https resource, otherwise NO.
|
||||
*/
|
||||
+ (BOOL)isBrowserURL:(NSURL *)URL;
|
||||
|
||||
/*!
|
||||
@abstract Tests whether the supplied bundle identifier references a Facebook app.
|
||||
@param bundleIdentifier The bundle identifier to test.
|
||||
@return YES if the bundle identifier refers to a Facebook app, otherwise NO.
|
||||
*/
|
||||
+ (BOOL)isFacebookBundleIdentifier:(NSString *)bundleIdentifier;
|
||||
|
||||
/*!
|
||||
@abstract Tests whether the operating system is at least the specified version.
|
||||
@param version The version to test against.
|
||||
@return YES if the operating system is greater than or equal to the specified version, otherwise NO.
|
||||
*/
|
||||
+ (BOOL)isOSRunTimeVersionAtLeast:(NSOperatingSystemVersion)version;
|
||||
|
||||
/*!
|
||||
@abstract Tests whether the supplied bundle identifier references the Safari app.
|
||||
@param bundleIdentifier The bundle identifier to test.
|
||||
@return YES if the bundle identifier refers to the Safari app, otherwise NO.
|
||||
*/
|
||||
+ (BOOL)isSafariBundleIdentifier:(NSString *)bundleIdentifier;
|
||||
|
||||
/*!
|
||||
@abstract Tests whether the UIKit version that the current app was linked to is at least the specified version.
|
||||
@param version The version to test against.
|
||||
@return YES if the linked UIKit version is greater than or equal to the specified version, otherwise NO.
|
||||
*/
|
||||
+ (BOOL)isUIKitLinkTimeVersionAtLeast:(FBSDKUIKitVersion)version;
|
||||
|
||||
/*!
|
||||
@abstract Tests whether the UIKit version in the runtime is at least the specified version.
|
||||
@param version The version to test against.
|
||||
@return YES if the runtime UIKit version is greater than or equal to the specified version, otherwise NO.
|
||||
*/
|
||||
+ (BOOL)isUIKitRunTimeVersionAtLeast:(FBSDKUIKitVersion)version;
|
||||
|
||||
/*!
|
||||
@abstract Converts an object into a JSON string.
|
||||
@param object The object to convert to JSON.
|
||||
@param errorRef If an error occurs, upon return contains an NSError object that describes the problem.
|
||||
@param invalidObjectHandler Handles objects that are invalid, returning a replacement value or nil to ignore.
|
||||
@return A JSON string or nil if the object cannot be converted to JSON.
|
||||
*/
|
||||
+ (NSString *)JSONStringForObject:(id)object
|
||||
error:(NSError *__autoreleasing *)errorRef
|
||||
invalidObjectHandler:(id(^)(id object, BOOL *stop))invalidObjectHandler;
|
||||
|
||||
/*!
|
||||
@abstract Checks equality between 2 objects.
|
||||
@discussion Checks for pointer equality, nils, isEqual:.
|
||||
@param object The first object to compare.
|
||||
@param other The second object to compare.
|
||||
@result YES if the objects are equal, otherwise NO.
|
||||
*/
|
||||
+ (BOOL)object:(id)object isEqualToObject:(id)other;
|
||||
|
||||
/*!
|
||||
@abstract Converts a JSON string into an object
|
||||
@param string The JSON string to convert.
|
||||
@param errorRef If an error occurs, upon return contains an NSError object that describes the problem.
|
||||
@return An NSDictionary, NSArray, NSString or NSNumber containing the object representation, or nil if the string
|
||||
cannot be converted.
|
||||
*/
|
||||
+ (id)objectForJSONString:(NSString *)string error:(NSError *__autoreleasing *)errorRef;
|
||||
|
||||
/*!
|
||||
@abstract The version of the operating system on which the process is executing.
|
||||
*/
|
||||
+ (NSOperatingSystemVersion)operatingSystemVersion;
|
||||
|
||||
/*!
|
||||
@abstract Constructs a query string from a dictionary.
|
||||
@param dictionary The dictionary with key/value pairs for the query string.
|
||||
@param errorRef If an error occurs, upon return contains an NSError object that describes the problem.
|
||||
@param invalidObjectHandler Handles objects that are invalid, returning a replacement value or nil to ignore.
|
||||
@result Query string representation of the parameters.
|
||||
*/
|
||||
+ (NSString *)queryStringWithDictionary:(NSDictionary *)dictionary
|
||||
error:(NSError *__autoreleasing *)errorRef
|
||||
invalidObjectHandler:(id(^)(id object, BOOL *stop))invalidObjectHandler;
|
||||
|
||||
/*!
|
||||
@abstract Tests whether the orientation should be manually adjusted for views outside of the root view controller.
|
||||
@discussion With the legacy layout the developer must worry about device orientation when working with views outside of
|
||||
the window's root view controller and apply the correct rotation transform and/or swap a view's width and height
|
||||
values. If the application was linked with UIKit on iOS 7 or earlier or the application is running on iOS 7 or earlier
|
||||
then we need to use the legacy layout code. Otherwise if the application was linked with UIKit on iOS 8 or later and
|
||||
the application is running on iOS 8 or later, UIKit handles all of the rotation complexity and the origin is always in
|
||||
the top-left and no rotation transform is necessary.
|
||||
@return YES if if the orientation must be manually adjusted, otherwise NO.
|
||||
*/
|
||||
+ (BOOL)shouldManuallyAdjustOrientation;
|
||||
|
||||
/*!
|
||||
@abstract Constructs an NSURL.
|
||||
@param scheme The scheme for the URL.
|
||||
@param host The host for the URL.
|
||||
@param path The path for the URL.
|
||||
@param queryParameters The query parameters for the URL. This will be converted into a query string.
|
||||
@param errorRef If an error occurs, upon return contains an NSError object that describes the problem.
|
||||
@return The URL.
|
||||
*/
|
||||
+ (NSURL *)URLWithScheme:(NSString *)scheme
|
||||
host:(NSString *)host
|
||||
path:(NSString *)path
|
||||
queryParameters:(NSDictionary *)queryParameters
|
||||
error:(NSError *__autoreleasing *)errorRef;
|
||||
|
||||
/*!
|
||||
* @abstract Deletes all the cookies in the NSHTTPCookieStorage for Facebook web dialogs
|
||||
*/
|
||||
+ (void)deleteFacebookCookies;
|
||||
|
||||
/*!
|
||||
@abstract Extracts permissions from a response fetched from me/permissions
|
||||
@param responseObject the response
|
||||
@param grantedPermissions the set to add granted permissions to
|
||||
@param declinedPermissions the set to add decliend permissions to.
|
||||
*/
|
||||
+ (void)extractPermissionsFromResponse:(NSDictionary *)responseObject
|
||||
grantedPermissions:(NSMutableSet *)grantedPermissions
|
||||
declinedPermissions:(NSMutableSet *)declinedPermissions;
|
||||
|
||||
/*!
|
||||
@abstract Registers a transient object so that it will not be deallocated until unregistered
|
||||
@param object The transient object
|
||||
*/
|
||||
+ (void)registerTransientObject:(id)object;
|
||||
|
||||
/*!
|
||||
@abstract Unregisters a transient object that was previously registered with registerTransientObject:
|
||||
@param object The transient object
|
||||
*/
|
||||
+ (void)unregisterTransientObject:(__weak id)object;
|
||||
|
||||
/*!
|
||||
@abstract validates that the app ID is non-nil, throws an NSException if nil.
|
||||
*/
|
||||
+ (void)validateAppID;
|
||||
|
||||
/*!
|
||||
@abstract validates that the right URL schemes are registered, throws an NSException if not.
|
||||
*/
|
||||
+ (void)validateURLSchemes;
|
||||
|
||||
/*!
|
||||
@abstract Attempts to find the first UIViewController in the view's responder chain. Returns nil if not found.
|
||||
*/
|
||||
+ (UIViewController *)viewControllerforView:(UIView*)view;
|
||||
|
||||
/*!
|
||||
@abstract returns true if the url scheme is registered in the CFBundleURLTypes
|
||||
*/
|
||||
+ (BOOL)isRegisteredURLScheme:(NSString *)urlScheme;
|
||||
|
||||
/*!
|
||||
@abstract returns currently displayed top view controller.
|
||||
*/
|
||||
+ (UIViewController *)topMostViewController;
|
||||
|
||||
/*
|
||||
@abstract Checks if the permission is a publish permission.
|
||||
*/
|
||||
+ (BOOL)isPublishPermission:(NSString *)permission;
|
||||
|
||||
/*
|
||||
@abstract Checks if the set of permissions are all read permissions.
|
||||
*/
|
||||
+ (BOOL)areAllPermissionsReadPermissions:(NSSet *)permissions;
|
||||
|
||||
/*
|
||||
@abstract Checks if the set of permissions are all publish permissions.
|
||||
*/
|
||||
+ (BOOL)areAllPermissionsPublishPermissions:(NSSet *)permissions;
|
||||
|
||||
#pragma mark - FB Apps Installed
|
||||
|
||||
+ (BOOL)isFacebookAppInstalled;
|
||||
+ (BOOL)isMessengerAppInstalled;
|
||||
+ (void)checkRegisteredCanOpenURLScheme:(NSString *)urlScheme;
|
||||
+ (BOOL)isRegisteredCanOpenURLScheme:(NSString *)urlScheme;
|
||||
|
||||
#define FBSDKConditionalLog(condition, loggingBehavior, desc, ...) \
|
||||
{ \
|
||||
if (!(condition)) { \
|
||||
NSString *msg = [NSString stringWithFormat:(desc), ##__VA_ARGS__]; \
|
||||
[FBSDKLogger singleShotLogEntry:loggingBehavior logEntry:msg]; \
|
||||
} \
|
||||
}
|
||||
|
||||
#define FB_BASE_URL @"facebook.com"
|
||||
|
||||
@end
|
||||
+695
@@ -0,0 +1,695 @@
|
||||
// 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 "FBSDKInternalUtility.h"
|
||||
|
||||
#import <sys/time.h>
|
||||
|
||||
#import <mach-o/dyld.h>
|
||||
|
||||
#import "FBSDKCoreKit+Internal.h"
|
||||
#import "FBSDKError.h"
|
||||
#import "FBSDKMacros.h"
|
||||
#import "FBSDKSettings.h"
|
||||
#import "FBSDKUtility.h"
|
||||
|
||||
typedef NS_ENUM(NSUInteger, FBSDKInternalUtilityVersionMask)
|
||||
{
|
||||
FBSDKInternalUtilityMajorVersionMask = 0xFFFF0000,
|
||||
//FBSDKInternalUtilityMinorVersionMask = 0x0000FF00, // unused
|
||||
//FBSDKInternalUtilityPatchVersionMask = 0x000000FF, // unused
|
||||
};
|
||||
|
||||
typedef NS_ENUM(NSUInteger, FBSDKInternalUtilityVersionShift)
|
||||
{
|
||||
FBSDKInternalUtilityMajorVersionShift = 16,
|
||||
//FBSDKInternalUtilityMinorVersionShift = 8, // unused
|
||||
//FBSDKInternalUtilityPatchVersionShift = 0, // unused
|
||||
};
|
||||
|
||||
@implementation FBSDKInternalUtility
|
||||
|
||||
#pragma mark - Class Methods
|
||||
|
||||
+ (NSString *)appURLScheme
|
||||
{
|
||||
NSString *appID = ([FBSDKSettings appID] ?: @"");
|
||||
NSString *suffix = ([FBSDKSettings appURLSchemeSuffix] ?: @"");
|
||||
return [[NSString alloc] initWithFormat: @"fb%@%@", appID, suffix];
|
||||
}
|
||||
|
||||
+ (NSURL *)appURLWithHost:(NSString *)host
|
||||
path:(NSString *)path
|
||||
queryParameters:(NSDictionary *)queryParameters
|
||||
error:(NSError *__autoreleasing *)errorRef
|
||||
{
|
||||
return [self URLWithScheme:[self appURLScheme]
|
||||
host:host
|
||||
path:path
|
||||
queryParameters:queryParameters
|
||||
error:errorRef];
|
||||
}
|
||||
|
||||
+ (NSDictionary *)dictionaryFromFBURL:(NSURL *)url
|
||||
{
|
||||
// version 3.2.3 of the Facebook app encodes the parameters in the query but
|
||||
// version 3.3 and above encode the parameters in the fragment;
|
||||
// merge them together with fragment taking priority.
|
||||
NSMutableDictionary *params = [NSMutableDictionary dictionary];
|
||||
[params addEntriesFromDictionary:[FBSDKUtility dictionaryWithQueryString:url.query]];
|
||||
|
||||
// Only get the params from the fragment if it has authorize as the host
|
||||
if ([url.host isEqualToString:@"authorize"]) {
|
||||
[params addEntriesFromDictionary:[FBSDKUtility dictionaryWithQueryString:url.fragment]];
|
||||
}
|
||||
return params;
|
||||
}
|
||||
|
||||
+ (void)array:(NSMutableArray *)array addObject:(id)object
|
||||
{
|
||||
if (object) {
|
||||
[array addObject:object];
|
||||
}
|
||||
}
|
||||
|
||||
+ (NSBundle *)bundleForStrings
|
||||
{
|
||||
static NSBundle *bundle;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
NSString *stringsBundlePath = [[NSBundle mainBundle] pathForResource:@"FacebookSDKStrings"
|
||||
ofType:@"bundle"];
|
||||
bundle = [NSBundle bundleWithPath:stringsBundlePath] ?: [NSBundle mainBundle];
|
||||
});
|
||||
return bundle;
|
||||
}
|
||||
|
||||
+ (id)convertRequestValue:(id)value
|
||||
{
|
||||
if ([value isKindOfClass:[NSNumber class]]) {
|
||||
value = [(NSNumber *)value stringValue];
|
||||
} else if ([value isKindOfClass:[NSURL class]]) {
|
||||
value = [(NSURL *)value absoluteString];
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
+ (unsigned long)currentTimeInMilliseconds
|
||||
{
|
||||
struct timeval time;
|
||||
gettimeofday(&time, NULL);
|
||||
return (time.tv_sec * 1000) + (time.tv_usec / 1000);
|
||||
}
|
||||
|
||||
+ (BOOL)dictionary:(NSMutableDictionary *)dictionary
|
||||
setJSONStringForObject:(id)object
|
||||
forKey:(id<NSCopying>)key
|
||||
error:(NSError *__autoreleasing *)errorRef
|
||||
{
|
||||
if (!object || !key) {
|
||||
return YES;
|
||||
}
|
||||
NSString *JSONString = [self JSONStringForObject:object error:errorRef invalidObjectHandler:NULL];
|
||||
if (!JSONString) {
|
||||
return NO;
|
||||
}
|
||||
[self dictionary:dictionary setObject:JSONString forKey:key];
|
||||
return YES;
|
||||
}
|
||||
|
||||
+ (void)dictionary:(NSMutableDictionary *)dictionary setObject:(id)object forKey:(id<NSCopying>)key
|
||||
{
|
||||
if (object && key) {
|
||||
[dictionary setObject:object forKey:key];
|
||||
}
|
||||
}
|
||||
|
||||
+ (void)extractPermissionsFromResponse:(NSDictionary *)responseObject
|
||||
grantedPermissions:(NSMutableSet *)grantedPermissions
|
||||
declinedPermissions:(NSMutableSet *)declinedPermissions
|
||||
{
|
||||
NSArray *resultData = responseObject[@"data"];
|
||||
if (resultData.count > 0) {
|
||||
for (NSDictionary *permissionsDictionary in resultData) {
|
||||
NSString *permissionName = permissionsDictionary[@"permission"];
|
||||
NSString *status = permissionsDictionary[@"status"];
|
||||
|
||||
if ([status isEqualToString:@"granted"]) {
|
||||
[grantedPermissions addObject:permissionName];
|
||||
} else if ([status isEqualToString:@"declined"]) {
|
||||
[declinedPermissions addObject:permissionName];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+ (NSURL *)facebookURLWithHostPrefix:(NSString *)hostPrefix
|
||||
path:(NSString *)path
|
||||
queryParameters:(NSDictionary *)queryParameters
|
||||
error:(NSError *__autoreleasing *)errorRef
|
||||
{
|
||||
return [self facebookURLWithHostPrefix:hostPrefix
|
||||
path:path
|
||||
queryParameters:queryParameters
|
||||
defaultVersion:nil
|
||||
error:errorRef];
|
||||
}
|
||||
|
||||
+ (NSURL *)facebookURLWithHostPrefix:(NSString *)hostPrefix
|
||||
path:(NSString *)path
|
||||
queryParameters:(NSDictionary *)queryParameters
|
||||
defaultVersion:(NSString *)defaultVersion
|
||||
error:(NSError *__autoreleasing *)errorRef
|
||||
{
|
||||
if ([hostPrefix length] && ![hostPrefix hasSuffix:@"."]) {
|
||||
hostPrefix = [hostPrefix stringByAppendingString:@"."];
|
||||
}
|
||||
|
||||
NSString *host = @"facebook.com";
|
||||
NSString *domainPart = [FBSDKSettings facebookDomainPart];
|
||||
if ([domainPart length]) {
|
||||
host = [[NSString alloc] initWithFormat:@"%@.%@", domainPart, host];
|
||||
}
|
||||
host = [NSString stringWithFormat:@"%@%@", hostPrefix ?: @"", host ?: @""];
|
||||
|
||||
NSString *version = defaultVersion ?: FBSDK_TARGET_PLATFORM_VERSION;
|
||||
if ([version length]) {
|
||||
version = [@"/" stringByAppendingString:version];
|
||||
}
|
||||
|
||||
if ([path length]) {
|
||||
NSScanner *versionScanner = [[NSScanner alloc] initWithString:path];
|
||||
if ([versionScanner scanString:@"/v" intoString:NULL] &&
|
||||
[versionScanner scanInteger:NULL] &&
|
||||
[versionScanner scanString:@"." intoString:NULL] &&
|
||||
[versionScanner scanInteger:NULL]) {
|
||||
version = nil;
|
||||
}
|
||||
if (![path hasPrefix:@"/"]) {
|
||||
path = [@"/" stringByAppendingString:path];
|
||||
}
|
||||
}
|
||||
path = [[NSString alloc] initWithFormat:@"%@%@", version ?: @"", path ?: @""];
|
||||
|
||||
return [self URLWithScheme:@"https"
|
||||
host:host
|
||||
path:path
|
||||
queryParameters:queryParameters
|
||||
error:errorRef];
|
||||
}
|
||||
|
||||
+ (BOOL)isBrowserURL:(NSURL *)URL
|
||||
{
|
||||
NSString *scheme = [URL.scheme lowercaseString];
|
||||
return ([scheme isEqualToString:@"http"] || [scheme isEqualToString:@"https"]);
|
||||
}
|
||||
|
||||
+ (BOOL)isFacebookBundleIdentifier:(NSString *)bundleIdentifier
|
||||
{
|
||||
return ([bundleIdentifier hasPrefix:@"com.facebook."] ||
|
||||
[bundleIdentifier hasPrefix:@".com.facebook."]);
|
||||
}
|
||||
|
||||
+ (BOOL)isOSRunTimeVersionAtLeast:(NSOperatingSystemVersion)version
|
||||
{
|
||||
return ([self _compareOperatingSystemVersion:[self operatingSystemVersion] toVersion:version] != NSOrderedAscending);
|
||||
}
|
||||
|
||||
+ (BOOL)isSafariBundleIdentifier:(NSString *)bundleIdentifier
|
||||
{
|
||||
return ([bundleIdentifier isEqualToString:@"com.apple.mobilesafari"] ||
|
||||
[bundleIdentifier isEqualToString:@"com.apple.SafariViewService"]);
|
||||
}
|
||||
|
||||
+ (BOOL)isUIKitLinkTimeVersionAtLeast:(FBSDKUIKitVersion)version
|
||||
{
|
||||
static int32_t linkTimeMajorVersion;
|
||||
static dispatch_once_t getVersionOnce;
|
||||
dispatch_once(&getVersionOnce, ^{
|
||||
int32_t linkTimeVersion = NSVersionOfLinkTimeLibrary("UIKit");
|
||||
linkTimeMajorVersion = ((MAX(linkTimeVersion, 0) & FBSDKInternalUtilityMajorVersionMask) >> FBSDKInternalUtilityMajorVersionShift);
|
||||
});
|
||||
return (version <= linkTimeMajorVersion);
|
||||
}
|
||||
|
||||
+ (BOOL)isUIKitRunTimeVersionAtLeast:(FBSDKUIKitVersion)version
|
||||
{
|
||||
static int32_t runTimeMajorVersion;
|
||||
static dispatch_once_t getVersionOnce;
|
||||
dispatch_once(&getVersionOnce, ^{
|
||||
int32_t runTimeVersion = NSVersionOfRunTimeLibrary("UIKit");
|
||||
runTimeMajorVersion = ((MAX(runTimeVersion, 0) & FBSDKInternalUtilityMajorVersionMask) >> FBSDKInternalUtilityMajorVersionShift);
|
||||
});
|
||||
return (version <= runTimeMajorVersion);
|
||||
}
|
||||
|
||||
+ (NSString *)JSONStringForObject:(id)object
|
||||
error:(NSError *__autoreleasing *)errorRef
|
||||
invalidObjectHandler:(id(^)(id object, BOOL *stop))invalidObjectHandler
|
||||
{
|
||||
if (invalidObjectHandler || ![NSJSONSerialization isValidJSONObject:object]) {
|
||||
object = [self _convertObjectToJSONObject:object invalidObjectHandler:invalidObjectHandler stop:NULL];
|
||||
if (![NSJSONSerialization isValidJSONObject:object]) {
|
||||
if (errorRef != NULL) {
|
||||
*errorRef = [FBSDKError invalidArgumentErrorWithName:@"object"
|
||||
value:object
|
||||
message:@"Invalid object for JSON serialization."];
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
NSData *data = [NSJSONSerialization dataWithJSONObject:object options:0 error:errorRef];
|
||||
if (!data) {
|
||||
return nil;
|
||||
}
|
||||
return [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
|
||||
}
|
||||
|
||||
+ (BOOL)object:(id)object isEqualToObject:(id)other;
|
||||
{
|
||||
if (object == other) {
|
||||
return YES;
|
||||
}
|
||||
if (!object || !other) {
|
||||
return NO;
|
||||
}
|
||||
return [object isEqual:other];
|
||||
}
|
||||
|
||||
+ (id)objectForJSONString:(NSString *)string error:(NSError *__autoreleasing *)errorRef
|
||||
{
|
||||
NSData *data = [string dataUsingEncoding:NSUTF8StringEncoding];
|
||||
if (!data) {
|
||||
if (errorRef != NULL) {
|
||||
*errorRef = nil;
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
return [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:errorRef];
|
||||
}
|
||||
|
||||
+ (NSOperatingSystemVersion)operatingSystemVersion
|
||||
{
|
||||
static NSOperatingSystemVersion operatingSystemVersion = {
|
||||
.majorVersion = 0,
|
||||
.minorVersion = 0,
|
||||
.patchVersion = 0,
|
||||
};
|
||||
static dispatch_once_t getVersionOnce;
|
||||
dispatch_once(&getVersionOnce, ^{
|
||||
if ([NSProcessInfo instancesRespondToSelector:@selector(operatingSystemVersion)]) {
|
||||
operatingSystemVersion = [NSProcessInfo processInfo].operatingSystemVersion;
|
||||
} else {
|
||||
NSArray *components = [[UIDevice currentDevice].systemVersion componentsSeparatedByString:@"."];
|
||||
switch (components.count) {
|
||||
default:
|
||||
case 3:
|
||||
operatingSystemVersion.patchVersion = [components[2] integerValue];
|
||||
// fall through
|
||||
case 2:
|
||||
operatingSystemVersion.minorVersion = [components[1] integerValue];
|
||||
// fall through
|
||||
case 1:
|
||||
operatingSystemVersion.majorVersion = [components[0] integerValue];
|
||||
break;
|
||||
case 0:
|
||||
operatingSystemVersion.majorVersion = ([self isUIKitLinkTimeVersionAtLeast:FBSDKUIKitVersion_7_0] ? 7 : 6);
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
return operatingSystemVersion;
|
||||
}
|
||||
|
||||
+ (NSString *)queryStringWithDictionary:(NSDictionary *)dictionary
|
||||
error:(NSError *__autoreleasing *)errorRef
|
||||
invalidObjectHandler:(id(^)(id object, BOOL *stop))invalidObjectHandler
|
||||
{
|
||||
NSMutableString *queryString = [[NSMutableString alloc] init];
|
||||
__block BOOL hasParameters = NO;
|
||||
if (dictionary) {
|
||||
NSMutableArray *keys = [[dictionary allKeys] mutableCopy];
|
||||
// remove non-string keys, as they are not valid
|
||||
[keys filterUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(id evaluatedObject, NSDictionary *bindings) {
|
||||
return [evaluatedObject isKindOfClass:[NSString class]];
|
||||
}]];
|
||||
// sort the keys so that the query string order is deterministic
|
||||
[keys sortUsingSelector:@selector(compare:)];
|
||||
BOOL stop = NO;
|
||||
for (NSString *key in keys) {
|
||||
id value = [self convertRequestValue:dictionary[key]];
|
||||
if ([value isKindOfClass:[NSString class]]) {
|
||||
value = [FBSDKUtility URLEncode:value];
|
||||
}
|
||||
if (invalidObjectHandler && ![value isKindOfClass:[NSString class]]) {
|
||||
value = invalidObjectHandler(value, &stop);
|
||||
if (stop) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (value) {
|
||||
if (hasParameters) {
|
||||
[queryString appendString:@"&"];
|
||||
}
|
||||
[queryString appendFormat:@"%@=%@", key, value];
|
||||
hasParameters = YES;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (errorRef != NULL) {
|
||||
*errorRef = nil;
|
||||
}
|
||||
return ([queryString length] ? [queryString copy] : nil);
|
||||
}
|
||||
|
||||
+ (BOOL)shouldManuallyAdjustOrientation
|
||||
{
|
||||
return (![self isUIKitLinkTimeVersionAtLeast:FBSDKUIKitVersion_8_0] ||
|
||||
![self isUIKitRunTimeVersionAtLeast:FBSDKUIKitVersion_8_0]);
|
||||
}
|
||||
|
||||
+ (NSURL *)URLWithScheme:(NSString *)scheme
|
||||
host:(NSString *)host
|
||||
path:(NSString *)path
|
||||
queryParameters:(NSDictionary *)queryParameters
|
||||
error:(NSError *__autoreleasing *)errorRef
|
||||
{
|
||||
if (![path hasPrefix:@"/"]) {
|
||||
path = [@"/" stringByAppendingString:path ?: @""];
|
||||
}
|
||||
|
||||
NSString *queryString = nil;
|
||||
if ([queryParameters count]) {
|
||||
NSError *queryStringError;
|
||||
queryString = [@"?" stringByAppendingString:[FBSDKUtility queryStringWithDictionary:queryParameters
|
||||
error:&queryStringError]];
|
||||
if (!queryString) {
|
||||
if (errorRef != NULL) {
|
||||
*errorRef = [FBSDKError invalidArgumentErrorWithName:@"queryParameters"
|
||||
value:queryParameters
|
||||
message:nil
|
||||
underlyingError:queryStringError];
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
|
||||
NSURL *URL = [[NSURL alloc] initWithString:[NSString stringWithFormat:
|
||||
@"%@://%@%@%@",
|
||||
scheme ?: @"",
|
||||
host ?: @"",
|
||||
path ?: @"",
|
||||
queryString ?: @""]];
|
||||
if (errorRef != NULL) {
|
||||
if (URL) {
|
||||
*errorRef = nil;
|
||||
} else {
|
||||
*errorRef = [FBSDKError unknownErrorWithMessage:@"Unknown error building URL."];
|
||||
}
|
||||
}
|
||||
return URL;
|
||||
}
|
||||
|
||||
+ (void)deleteFacebookCookies
|
||||
{
|
||||
NSHTTPCookieStorage *cookies = [NSHTTPCookieStorage sharedHTTPCookieStorage];
|
||||
NSArray *facebookCookies = [cookies cookiesForURL:[self facebookURLWithHostPrefix:@"m."
|
||||
path:@"/dialog/"
|
||||
queryParameters:nil
|
||||
error:NULL]];
|
||||
|
||||
for (NSHTTPCookie *cookie in facebookCookies) {
|
||||
[cookies deleteCookie:cookie];
|
||||
}
|
||||
}
|
||||
|
||||
static NSMapTable *_transientObjects;
|
||||
|
||||
+ (void)registerTransientObject:(id)object
|
||||
{
|
||||
NSAssert([NSThread isMainThread], @"Must be called from the main thread!");
|
||||
if (!_transientObjects) {
|
||||
_transientObjects = [[NSMapTable alloc] init];
|
||||
}
|
||||
NSUInteger count = [(NSNumber *)[_transientObjects objectForKey:object] unsignedIntegerValue];
|
||||
[_transientObjects setObject:@(count + 1) forKey:object];
|
||||
}
|
||||
|
||||
+ (void)unregisterTransientObject:(__weak id)object
|
||||
{
|
||||
if (!object) {
|
||||
return;
|
||||
}
|
||||
NSAssert([NSThread isMainThread], @"Must be called from the main thread!");
|
||||
NSUInteger count = [(NSNumber *)[_transientObjects objectForKey:object] unsignedIntegerValue];
|
||||
if (count == 1) {
|
||||
[_transientObjects removeObjectForKey:object];
|
||||
} else if (count != 0) {
|
||||
[_transientObjects setObject:@(count - 1) forKey:object];
|
||||
} else {
|
||||
[FBSDKLogger singleShotLogEntry:FBSDKLoggingBehaviorDeveloperErrors
|
||||
formatString:@"unregisterTransientObject:%@ count is 0. This may indicate a bug in the FBSDK. Please"
|
||||
" file a report to developers.facebook.com/bugs if you encounter any problems. Thanks!", [object class]];
|
||||
}
|
||||
}
|
||||
|
||||
+ (UIViewController *)viewControllerforView:(UIView*)view
|
||||
{
|
||||
UIResponder *responder = view.nextResponder;
|
||||
while (responder) {
|
||||
if ([responder isKindOfClass:[UIViewController class]]) {
|
||||
return (UIViewController *)responder;
|
||||
}
|
||||
responder = responder.nextResponder;
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
#pragma mark - FB Apps Installed
|
||||
|
||||
+ (BOOL)isFacebookAppInstalled
|
||||
{
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
[FBSDKInternalUtility checkRegisteredCanOpenURLScheme:FBSDK_CANOPENURL_FACEBOOK];
|
||||
});
|
||||
NSURLComponents *components = [[NSURLComponents alloc] init];
|
||||
components.scheme = FBSDK_CANOPENURL_FACEBOOK;
|
||||
components.path = @"/";
|
||||
return [[UIApplication sharedApplication]
|
||||
canOpenURL:components.URL];
|
||||
}
|
||||
|
||||
+ (BOOL)isMessengerAppInstalled
|
||||
{
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
[FBSDKInternalUtility checkRegisteredCanOpenURLScheme:FBSDK_CANOPENURL_MESSENGER];
|
||||
});
|
||||
NSURLComponents *components = [[NSURLComponents alloc] init];
|
||||
components.scheme = FBSDK_CANOPENURL_MESSENGER;
|
||||
components.path = @"/";
|
||||
return [[UIApplication sharedApplication]
|
||||
canOpenURL:components.URL];
|
||||
|
||||
}
|
||||
|
||||
#pragma mark - Object Lifecycle
|
||||
|
||||
- (instancetype)init
|
||||
{
|
||||
FBSDK_NO_DESIGNATED_INITIALIZER();
|
||||
return nil;
|
||||
}
|
||||
|
||||
#pragma mark - Helper Methods
|
||||
|
||||
+ (NSComparisonResult)_compareOperatingSystemVersion:(NSOperatingSystemVersion)version1
|
||||
toVersion:(NSOperatingSystemVersion)version2
|
||||
{
|
||||
if (version1.majorVersion < version2.majorVersion) {
|
||||
return NSOrderedAscending;
|
||||
} else if (version1.majorVersion > version2.majorVersion) {
|
||||
return NSOrderedDescending;
|
||||
} else if (version1.minorVersion < version2.minorVersion) {
|
||||
return NSOrderedAscending;
|
||||
} else if (version1.minorVersion > version2.minorVersion) {
|
||||
return NSOrderedDescending;
|
||||
} else if (version1.patchVersion < version2.patchVersion) {
|
||||
return NSOrderedAscending;
|
||||
} else if (version1.patchVersion > version2.patchVersion) {
|
||||
return NSOrderedDescending;
|
||||
} else {
|
||||
return NSOrderedSame;
|
||||
}
|
||||
}
|
||||
|
||||
+ (id)_convertObjectToJSONObject:(id)object
|
||||
invalidObjectHandler:(id(^)(id object, BOOL *stop))invalidObjectHandler
|
||||
stop:(BOOL *)stopRef
|
||||
{
|
||||
__block BOOL stop = NO;
|
||||
if ([object isKindOfClass:[NSString class]] || [object isKindOfClass:[NSNumber class]]) {
|
||||
// good to go, keep the object
|
||||
} else if ([object isKindOfClass:[NSURL class]]) {
|
||||
object = [(NSURL *)object absoluteString];
|
||||
} else if ([object isKindOfClass:[NSDictionary class]]) {
|
||||
NSMutableDictionary *dictionary = [[NSMutableDictionary alloc] init];
|
||||
[(NSDictionary *)object enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *dictionaryStop) {
|
||||
[self dictionary:dictionary
|
||||
setObject:[self _convertObjectToJSONObject:obj invalidObjectHandler:invalidObjectHandler stop:&stop]
|
||||
forKey:[FBSDKTypeUtility stringValue:key]];
|
||||
if (stop) {
|
||||
*dictionaryStop = YES;
|
||||
}
|
||||
}];
|
||||
object = dictionary;
|
||||
} else if ([object isKindOfClass:[NSArray class]]) {
|
||||
NSMutableArray *array = [[NSMutableArray alloc] init];
|
||||
for (id obj in (NSArray *)object) {
|
||||
id convertedObj = [self _convertObjectToJSONObject:obj invalidObjectHandler:invalidObjectHandler stop:&stop];
|
||||
[self array:array addObject:convertedObj];
|
||||
if (stop) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
object = array;
|
||||
} else {
|
||||
object = invalidObjectHandler(object, stopRef);
|
||||
}
|
||||
if (stopRef != NULL) {
|
||||
*stopRef = stop;
|
||||
}
|
||||
return object;
|
||||
}
|
||||
|
||||
+ (void)validateAppID
|
||||
{
|
||||
if (![FBSDKSettings appID]) {
|
||||
NSString *reason = @"App ID not found. Add a string value with your app ID for the key "
|
||||
@"FacebookAppID to the Info.plist or call [FBSDKSettings setAppID:].";
|
||||
@throw [NSException exceptionWithName:@"InvalidOperationException" reason:reason userInfo:nil];
|
||||
}
|
||||
}
|
||||
|
||||
+ (void)validateURLSchemes
|
||||
{
|
||||
[self validateAppID];
|
||||
NSString *defaultUrlScheme = [NSString stringWithFormat:@"fb%@%@", [FBSDKSettings appID], [FBSDKSettings appURLSchemeSuffix] ?: @""];
|
||||
if (![self isRegisteredURLScheme:defaultUrlScheme]) {
|
||||
NSString *reason = [NSString stringWithFormat:@"%@ is not registered as a URL scheme. Please add it in your Info.plist", defaultUrlScheme];
|
||||
@throw [NSException exceptionWithName:@"InvalidOperationException" reason:reason userInfo:nil];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+ (UIViewController *)topMostViewController
|
||||
{
|
||||
UIViewController *topController = [UIApplication sharedApplication].keyWindow.rootViewController;
|
||||
while (topController.presentedViewController) {
|
||||
topController = topController.presentedViewController;
|
||||
}
|
||||
return topController;
|
||||
}
|
||||
|
||||
|
||||
+ (BOOL)isRegisteredURLScheme:(NSString *)urlScheme {
|
||||
static dispatch_once_t fetchBundleOnce;
|
||||
static NSArray *urlTypes = nil;
|
||||
|
||||
dispatch_once(&fetchBundleOnce, ^{
|
||||
urlTypes = [[[NSBundle mainBundle] infoDictionary] valueForKey:@"CFBundleURLTypes"];
|
||||
});
|
||||
for (NSDictionary *urlType in urlTypes) {
|
||||
NSArray *urlSchemes = [urlType valueForKey:@"CFBundleURLSchemes"];
|
||||
if ([urlSchemes containsObject:urlScheme]) {
|
||||
return YES;
|
||||
}
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
+ (void)checkRegisteredCanOpenURLScheme:(NSString *)urlScheme
|
||||
{
|
||||
static dispatch_once_t initCheckedSchemesOnce;
|
||||
static NSMutableSet *checkedSchemes = nil;
|
||||
|
||||
dispatch_once(&initCheckedSchemesOnce, ^{
|
||||
checkedSchemes = [NSMutableSet set];
|
||||
});
|
||||
|
||||
@synchronized(self) {
|
||||
if ([checkedSchemes containsObject:urlScheme]) {
|
||||
return;
|
||||
} else {
|
||||
[checkedSchemes addObject:urlScheme];
|
||||
}
|
||||
}
|
||||
|
||||
if (![self isRegisteredCanOpenURLScheme:urlScheme]){
|
||||
NSString *reason = [NSString stringWithFormat:@"%@ is missing from your Info.plist under LSApplicationQueriesSchemes and is required for iOS 9.0", urlScheme];
|
||||
#ifdef __IPHONE_9_0
|
||||
@throw [NSException exceptionWithName:@"InvalidOperationException" reason:reason userInfo:nil];
|
||||
#else
|
||||
[FBSDKLogger singleShotLogEntry:FBSDKLoggingBehaviorDeveloperErrors logEntry:reason];
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
+ (BOOL)isRegisteredCanOpenURLScheme:(NSString *)urlScheme
|
||||
{
|
||||
static dispatch_once_t fetchBundleOnce;
|
||||
static NSArray *schemes = nil;
|
||||
|
||||
dispatch_once(&fetchBundleOnce, ^{
|
||||
schemes = [[[NSBundle mainBundle] infoDictionary] valueForKey:@"LSApplicationQueriesSchemes"];
|
||||
});
|
||||
|
||||
return [schemes containsObject:urlScheme];
|
||||
}
|
||||
|
||||
+ (BOOL)isPublishPermission:(NSString *)permission
|
||||
{
|
||||
return [permission hasPrefix:@"publish"] ||
|
||||
[permission hasPrefix:@"manage"] ||
|
||||
[permission isEqualToString:@"ads_management"] ||
|
||||
[permission isEqualToString:@"create_event"] ||
|
||||
[permission isEqualToString:@"rsvp_event"];
|
||||
}
|
||||
|
||||
+ (BOOL)areAllPermissionsReadPermissions:(NSSet *)permissions
|
||||
{
|
||||
for (NSString *permission in permissions) {
|
||||
if ([[self class] isPublishPermission:permission]) {
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
|
||||
+ (BOOL)areAllPermissionsPublishPermissions:(NSSet *)permissions
|
||||
{
|
||||
for (NSString *permission in permissions) {
|
||||
if (![[self class] isPublishPermission:permission]) {
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,88 @@
|
||||
// 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>
|
||||
|
||||
/*!
|
||||
@class FBSDKLogger
|
||||
|
||||
@abstract
|
||||
Simple logging utility for conditionally logging strings and then emitting them
|
||||
via NSLog().
|
||||
|
||||
@unsorted
|
||||
*/
|
||||
@interface FBSDKLogger : NSObject
|
||||
|
||||
// Access current accumulated contents of the logger.
|
||||
@property (copy, nonatomic) NSString *contents;
|
||||
|
||||
// Each FBSDKLogger gets a unique serial number to allow the client to log these numbers and, for instance, correlation of Request/Response
|
||||
@property (nonatomic, readonly) NSUInteger loggerSerialNumber;
|
||||
|
||||
// The logging behavior of this logger. See the FB_LOG_BEHAVIOR* constants in FBSession.h
|
||||
@property (copy, nonatomic, readonly) NSString *loggingBehavior;
|
||||
|
||||
// Is the current logger instance active, based on its loggingBehavior?
|
||||
@property (nonatomic, readonly) BOOL isActive;
|
||||
|
||||
//
|
||||
// Instance methods
|
||||
//
|
||||
|
||||
// Create with specified logging behavior
|
||||
- (instancetype)initWithLoggingBehavior:(NSString *)loggingBehavior;
|
||||
|
||||
// Append string, or key/value pair
|
||||
- (void)appendString:(NSString *)string;
|
||||
- (void)appendFormat:(NSString *)formatString, ... NS_FORMAT_FUNCTION(1,2);
|
||||
- (void)appendKey:(NSString *)key value:(NSString *)value;
|
||||
|
||||
// Emit log, clearing out the logger contents.
|
||||
- (void)emitToNSLog;
|
||||
|
||||
//
|
||||
// Class methods
|
||||
//
|
||||
|
||||
//
|
||||
// Return a globally unique serial number to be used for correlating multiple output from the same logger.
|
||||
//
|
||||
+ (NSUInteger)generateSerialNumber;
|
||||
|
||||
// Simple helper to write a single log entry, based upon whether the behavior matches a specified on.
|
||||
+ (void)singleShotLogEntry:(NSString *)loggingBehavior
|
||||
logEntry:(NSString *)logEntry;
|
||||
|
||||
+ (void)singleShotLogEntry:(NSString *)loggingBehavior
|
||||
formatString:(NSString *)formatString, ... NS_FORMAT_FUNCTION(2,3);
|
||||
|
||||
+ (void)singleShotLogEntry:(NSString *)loggingBehavior
|
||||
timestampTag:(NSObject *)timestampTag
|
||||
formatString:(NSString *)formatString, ... NS_FORMAT_FUNCTION(3,4);
|
||||
|
||||
// Register a timestamp label with the "current" time, to then be retrieved by singleShotLogEntry
|
||||
// to include a duration.
|
||||
+ (void)registerCurrentTime:(NSString *)loggingBehavior
|
||||
withTag:(NSObject *)timestampTag;
|
||||
|
||||
// When logging strings, replace all instances of 'replace' with instances of 'replaceWith'.
|
||||
+ (void)registerStringToReplace:(NSString *)replace
|
||||
replaceWith:(NSString *)replaceWith;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,219 @@
|
||||
// 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 "FBSDKLogger.h"
|
||||
|
||||
#import "FBSDKInternalUtility.h"
|
||||
#import "FBSDKSettings+Internal.h"
|
||||
|
||||
static NSUInteger g_serialNumberCounter = 1111;
|
||||
static NSMutableDictionary *g_stringsToReplace = nil;
|
||||
static NSMutableDictionary *g_startTimesWithTags = nil;
|
||||
|
||||
@interface FBSDKLogger ()
|
||||
|
||||
@property (nonatomic, strong, readonly) NSMutableString *internalContents;
|
||||
|
||||
@end
|
||||
|
||||
@implementation FBSDKLogger
|
||||
|
||||
// Lifetime
|
||||
|
||||
- (instancetype)initWithLoggingBehavior:(NSString *)loggingBehavior
|
||||
{
|
||||
if ((self = [super init])) {
|
||||
_isActive = [[FBSDKSettings loggingBehavior] containsObject:loggingBehavior];
|
||||
_loggingBehavior = loggingBehavior;
|
||||
if (_isActive) {
|
||||
_internalContents = [[NSMutableString alloc] init];
|
||||
_loggerSerialNumber = [FBSDKLogger generateSerialNumber];
|
||||
}
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
// Public properties
|
||||
|
||||
- (NSString *)contents
|
||||
{
|
||||
return _internalContents;
|
||||
}
|
||||
|
||||
- (void)setContents:(NSString *)contents
|
||||
{
|
||||
if (_isActive) {
|
||||
_internalContents = [NSMutableString stringWithString:contents];
|
||||
}
|
||||
}
|
||||
|
||||
// Public instance methods
|
||||
|
||||
- (void)appendString:(NSString *)string
|
||||
{
|
||||
if (_isActive) {
|
||||
[_internalContents appendString:string];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)appendFormat:(NSString *)formatString, ...
|
||||
{
|
||||
if (_isActive) {
|
||||
va_list vaArguments;
|
||||
va_start(vaArguments, formatString);
|
||||
NSString *logString = [[NSString alloc] initWithFormat:formatString arguments:vaArguments];
|
||||
va_end(vaArguments);
|
||||
|
||||
[self appendString:logString];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
- (void)appendKey:(NSString *)key value:(NSString *)value
|
||||
{
|
||||
if (_isActive && [value length]) {
|
||||
[_internalContents appendFormat:@" %@:\t%@\n", key, value];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)emitToNSLog
|
||||
{
|
||||
if (_isActive) {
|
||||
|
||||
for (NSString *key in [g_stringsToReplace keyEnumerator]) {
|
||||
[_internalContents replaceOccurrencesOfString:key
|
||||
withString:[g_stringsToReplace objectForKey:key]
|
||||
options:NSLiteralSearch
|
||||
range:NSMakeRange(0, _internalContents.length)];
|
||||
}
|
||||
|
||||
// Xcode 4.4 hangs on extremely long NSLog output (http://openradar.appspot.com/11972490). Truncate if needed.
|
||||
const int MAX_LOG_STRING_LENGTH = 10000;
|
||||
NSString *logString = _internalContents;
|
||||
if (_internalContents.length > MAX_LOG_STRING_LENGTH) {
|
||||
logString = [NSString stringWithFormat:@"TRUNCATED: %@", [_internalContents substringToIndex:MAX_LOG_STRING_LENGTH]];
|
||||
}
|
||||
NSLog(@"FBSDKLog: %@", logString);
|
||||
|
||||
[_internalContents setString:@""];
|
||||
}
|
||||
}
|
||||
|
||||
// Public static methods
|
||||
|
||||
+ (NSUInteger)generateSerialNumber
|
||||
{
|
||||
return g_serialNumberCounter++;
|
||||
}
|
||||
|
||||
+ (void)singleShotLogEntry:(NSString *)loggingBehavior
|
||||
logEntry:(NSString *)logEntry {
|
||||
if ([[FBSDKSettings loggingBehavior] containsObject:loggingBehavior]) {
|
||||
FBSDKLogger *logger = [[FBSDKLogger alloc] initWithLoggingBehavior:loggingBehavior];
|
||||
[logger appendString:logEntry];
|
||||
[logger emitToNSLog];
|
||||
}
|
||||
}
|
||||
|
||||
+ (void)singleShotLogEntry:(NSString *)loggingBehavior
|
||||
formatString:(NSString *)formatString, ... {
|
||||
|
||||
if ([[FBSDKSettings loggingBehavior] containsObject:loggingBehavior]) {
|
||||
va_list vaArguments;
|
||||
va_start(vaArguments, formatString);
|
||||
NSString *logString = [[NSString alloc] initWithFormat:formatString arguments:vaArguments];
|
||||
va_end(vaArguments);
|
||||
|
||||
[self singleShotLogEntry:loggingBehavior logEntry:logString];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+ (void)singleShotLogEntry:(NSString *)loggingBehavior
|
||||
timestampTag:(NSObject *)timestampTag
|
||||
formatString:(NSString *)formatString, ... {
|
||||
|
||||
if ([[FBSDKSettings loggingBehavior] containsObject:loggingBehavior]) {
|
||||
va_list vaArguments;
|
||||
va_start(vaArguments, formatString);
|
||||
NSString *logString = [[NSString alloc] initWithFormat:formatString arguments:vaArguments];
|
||||
va_end(vaArguments);
|
||||
|
||||
// Start time of this "timestampTag" is stashed in the dictionary.
|
||||
// Treat the incoming object tag simply as an address, since it's only used to identify during lifetime. If
|
||||
// we send in as an object, the dictionary will try to copy it.
|
||||
NSNumber *tagAsNumber = [NSNumber numberWithUnsignedLong:(unsigned long)(__bridge void *)timestampTag];
|
||||
NSNumber *startTimeNumber = [g_startTimesWithTags objectForKey:tagAsNumber];
|
||||
|
||||
// Only log if there's been an associated start time.
|
||||
if (startTimeNumber) {
|
||||
unsigned long elapsed = [FBSDKInternalUtility currentTimeInMilliseconds] - startTimeNumber.unsignedLongValue;
|
||||
[g_startTimesWithTags removeObjectForKey:tagAsNumber]; // served its purpose, remove
|
||||
|
||||
// Log string is appended with "%d msec", with nothing intervening. This gives the most control to the caller.
|
||||
logString = [NSString stringWithFormat:@"%@%lu msec", logString, elapsed];
|
||||
|
||||
[self singleShotLogEntry:loggingBehavior logEntry:logString];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+ (void)registerCurrentTime:(NSString *)loggingBehavior
|
||||
withTag:(NSObject *)timestampTag {
|
||||
|
||||
if ([[FBSDKSettings loggingBehavior] containsObject:loggingBehavior]) {
|
||||
|
||||
if (!g_startTimesWithTags) {
|
||||
g_startTimesWithTags = [[NSMutableDictionary alloc] init];
|
||||
}
|
||||
|
||||
if (g_startTimesWithTags.count >= 1000) {
|
||||
[FBSDKLogger singleShotLogEntry:FBSDKLoggingBehaviorDeveloperErrors logEntry:
|
||||
@"Unexpectedly large number of outstanding perf logging start times, something is likely wrong."];
|
||||
}
|
||||
|
||||
unsigned long currTime = [FBSDKInternalUtility currentTimeInMilliseconds];
|
||||
|
||||
// Treat the incoming object tag simply as an address, since it's only used to identify during lifetime. If
|
||||
// we send in as an object, the dictionary will try to copy it.
|
||||
unsigned long tagAsNumber = (unsigned long)(__bridge void *)timestampTag;
|
||||
[g_startTimesWithTags setObject:[NSNumber numberWithUnsignedLong:currTime]
|
||||
forKey:[NSNumber numberWithUnsignedLong:tagAsNumber]];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+ (void)registerStringToReplace:(NSString *)replace
|
||||
replaceWith:(NSString *)replaceWith {
|
||||
|
||||
// Strings sent in here never get cleaned up, but that's OK, don't ever expect too many.
|
||||
|
||||
if ([[FBSDKSettings loggingBehavior] count] > 0) { // otherwise there's no logging.
|
||||
|
||||
if (!g_stringsToReplace) {
|
||||
g_stringsToReplace = [[NSMutableDictionary alloc] init];
|
||||
}
|
||||
|
||||
[g_stringsToReplace setValue:replaceWith forKey:replace];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,38 @@
|
||||
// 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 <CoreGraphics/CoreGraphics.h>
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface FBSDKMath : NSObject
|
||||
|
||||
+ (CGPoint)ceilForPoint:(CGPoint)value;
|
||||
+ (CGSize)ceilForSize:(CGSize)value;
|
||||
+ (CGPoint)floorForPoint:(CGPoint)value;
|
||||
+ (CGSize)floorForSize:(CGSize)value;
|
||||
+ (NSUInteger)hashWithCGFloat:(CGFloat)value;
|
||||
+ (NSUInteger)hashWithCString:(const char *)value;
|
||||
+ (NSUInteger)hashWithDouble:(double)value;
|
||||
+ (NSUInteger)hashWithFloat:(float)value;
|
||||
+ (NSUInteger)hashWithInteger:(NSUInteger)value;
|
||||
+ (NSUInteger)hashWithInteger:(NSUInteger)value1 andInteger:(NSUInteger)value2;
|
||||
+ (NSUInteger)hashWithIntegerArray:(NSUInteger *)values count:(NSUInteger)count;
|
||||
+ (NSUInteger)hashWithLong:(unsigned long long)value;
|
||||
+ (NSUInteger)hashWithPointer:(const void *)value;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,159 @@
|
||||
// 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.
|
||||
|
||||
//
|
||||
// Based on Thomas Wang 32/64 bit mix hash
|
||||
// http://www.concentric.net/~Ttwang/tech/inthash.htm
|
||||
//
|
||||
|
||||
#import "FBSDKMath.h"
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
#import "FBSDKMacros.h"
|
||||
|
||||
@implementation FBSDKMath
|
||||
|
||||
#pragma mark - Class Methods
|
||||
|
||||
+ (CGPoint)ceilForPoint:(CGPoint)value
|
||||
{
|
||||
return CGPointMake(ceilf(value.x), ceilf(value.x));
|
||||
}
|
||||
|
||||
+ (CGSize)ceilForSize:(CGSize)value
|
||||
{
|
||||
return CGSizeMake(ceilf(value.width), ceilf(value.height));
|
||||
}
|
||||
|
||||
+ (CGPoint)floorForPoint:(CGPoint)value
|
||||
{
|
||||
return CGPointMake(floorf(value.x), floorf(value.y));
|
||||
}
|
||||
|
||||
+ (CGSize)floorForSize:(CGSize)value
|
||||
{
|
||||
return CGSizeMake(floorf(value.width), floorf(value.height));
|
||||
}
|
||||
|
||||
+ (NSUInteger)hashWithCGFloat:(CGFloat)value
|
||||
{
|
||||
#if CGFLOAT_IS_DOUBLE
|
||||
return [self hashWithDouble:value];
|
||||
#else
|
||||
return [self hashWithFloat:value];
|
||||
#endif
|
||||
}
|
||||
|
||||
+ (NSUInteger)hashWithCString:(const char *)value
|
||||
{
|
||||
// FNV-1a hash.
|
||||
NSUInteger hash = sizeof(NSUInteger) == 4 ? 2166136261U : 14695981039346656037U;
|
||||
while (*value) {
|
||||
hash ^= *value++;
|
||||
hash *= sizeof(NSUInteger) == 4 ? 16777619 : 1099511628211;
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
+ (NSUInteger)hashWithDouble:(double)value
|
||||
{
|
||||
assert(sizeof(double) == sizeof(uint64_t)); // Size of double must be 8 bytes
|
||||
union {
|
||||
double key;
|
||||
uint64_t bits;
|
||||
} u;
|
||||
u.key = value;
|
||||
return [self hashWithLong:u.bits];
|
||||
}
|
||||
|
||||
+ (NSUInteger)hashWithFloat:(float)value
|
||||
{
|
||||
assert(sizeof(float) == sizeof(uint32_t)); // Size of float must be 4 bytes
|
||||
union {
|
||||
float key;
|
||||
uint32_t bits;
|
||||
} u;
|
||||
u.key = value;
|
||||
return [self hashWithInteger:u.bits];
|
||||
}
|
||||
|
||||
+ (NSUInteger)hashWithInteger:(NSUInteger)value
|
||||
{
|
||||
return [self hashWithPointer:(void *)value];
|
||||
}
|
||||
|
||||
+ (NSUInteger)hashWithInteger:(NSUInteger)value1 andInteger:(NSUInteger)value2
|
||||
{
|
||||
return [self hashWithLong:(((unsigned long long)value1) << 32 | value2)];
|
||||
}
|
||||
|
||||
+ (NSUInteger)hashWithIntegerArray:(NSUInteger *)values count:(NSUInteger)count
|
||||
{
|
||||
if (count == 0) {
|
||||
return 0;
|
||||
}
|
||||
NSUInteger hash = values[0];
|
||||
for (NSUInteger i = 1; i < count; ++i) {
|
||||
hash = [self hashWithInteger:hash andInteger:values[i]];
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
+ (NSUInteger)hashWithLong:(unsigned long long)value
|
||||
{
|
||||
value = (~value) + (value << 18); // key = (key << 18) - key - 1;
|
||||
value ^= (value >> 31);
|
||||
value *= 21; // key = (key + (key << 2)) + (key << 4);
|
||||
value ^= (value >> 11);
|
||||
value += (value << 6);
|
||||
value ^= (value >> 22);
|
||||
return (NSUInteger)value;
|
||||
}
|
||||
|
||||
+ (NSUInteger)hashWithPointer:(const void *)value
|
||||
{
|
||||
NSUInteger hash = (NSUInteger)value;
|
||||
#if !TARGET_RT_64_BIT
|
||||
hash = ~hash + (hash << 15); // key = (key << 15) - key - 1;
|
||||
hash ^= (hash >> 12);
|
||||
hash += (hash << 2);
|
||||
hash ^= (hash >> 4);
|
||||
hash *= 2057; // key = (key + (key << 3)) + (key << 11);
|
||||
hash ^= (hash >> 16);
|
||||
#else
|
||||
hash += ~hash + (hash << 21); // key = (key << 21) - key - 1;
|
||||
hash ^= (hash >> 24);
|
||||
hash = (hash + (hash << 3)) + (hash << 8);
|
||||
hash ^= (hash >> 14);
|
||||
hash = (hash + (hash << 2)) + (hash << 4); // key * 21
|
||||
hash ^= (hash >> 28);
|
||||
hash += (hash << 31);
|
||||
#endif
|
||||
return hash;
|
||||
}
|
||||
|
||||
#pragma mark - Object Lifecycle
|
||||
|
||||
- (instancetype)init
|
||||
{
|
||||
FBSDK_NO_DESIGNATED_INITIALIZER();
|
||||
return nil;
|
||||
}
|
||||
|
||||
@end
|
||||
+67
@@ -0,0 +1,67 @@
|
||||
// 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.
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
typedef double FBSDKMonotonicTimeSeconds;
|
||||
typedef uint64_t FBSDKMonotonicTimeMilliseconds;
|
||||
typedef uint64_t FBSDKMonotonicTimeNanoseconds;
|
||||
typedef uint64_t FBSDKMachAbsoluteTimeUnits;
|
||||
|
||||
/**
|
||||
* return current monotonic time in Milliseconds
|
||||
* Millisecond precision, uint64_t value.
|
||||
* Avoids float/double math operations, thus more efficient than FBSDKMonotonicTimeGetCurrentSeconds.
|
||||
* Should be prefered over FBSDKMonotonicTimeGetCurrentSeconds in case millisecond
|
||||
* precision is requred.
|
||||
* IMPORTANT: this timer doesn't run while the device is sleeping.
|
||||
*/
|
||||
FBSDKMonotonicTimeMilliseconds FBSDKMonotonicTimeGetCurrentMilliseconds(void);
|
||||
|
||||
/**
|
||||
* return current monotonic time in Seconds
|
||||
* Nanosecond precision, double value.
|
||||
* Should be prefered over FBSDKMonotonicTimeGetCurrentMilliseconds in case
|
||||
* nanosecond precision is requred.
|
||||
* IMPORTANT: this timer doesn't run while the device is sleeping.
|
||||
*/
|
||||
FBSDKMonotonicTimeSeconds FBSDKMonotonicTimeGetCurrentSeconds(void);
|
||||
|
||||
/**
|
||||
* return current monotonic time in NanoSeconds
|
||||
* Nanosecond precision, uint64_t value.
|
||||
* Useful when nanosecond precision is required but you want to avoid float/double math operations.
|
||||
* IMPORTANT: this timer doesn't run while the device is sleeping.
|
||||
*/
|
||||
FBSDKMonotonicTimeNanoseconds FBSDKMonotonicTimeGetCurrentNanoseconds(void);
|
||||
|
||||
/**
|
||||
* return number of MachTimeUnits for given number of seconds
|
||||
* this is useful when you want to use the really fast mach_absolute_time() function
|
||||
* to calculate deltas between two points and then check it against a (precomputed) threshold.
|
||||
* Nanosecond precision, uint64_t value.
|
||||
*/
|
||||
FBSDKMachAbsoluteTimeUnits FBSDKMonotonicTimeConvertSecondsToMachUnits(FBSDKMonotonicTimeSeconds seconds);
|
||||
|
||||
/**
|
||||
* return the number of seconds for a given amount of MachTimeUnits
|
||||
* this is useful when you want to use the really fast mach_absolute_time() function, take
|
||||
* deltas between time points, and when you're out of the timing critical section, use
|
||||
* this function to compute how many seconds the delta works out to be.
|
||||
*/
|
||||
FBSDKMonotonicTimeSeconds FBSDKMonotonicTimeConvertMachUnitsToSeconds(FBSDKMachAbsoluteTimeUnits machUnits);
|
||||
+86
@@ -0,0 +1,86 @@
|
||||
// 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.
|
||||
|
||||
#include <mach/mach.h>
|
||||
#include <mach/mach_time.h>
|
||||
#include <assert.h>
|
||||
#include <dispatch/dispatch.h>
|
||||
|
||||
#import "FBSDKMonotonicTime.h"
|
||||
|
||||
/**
|
||||
* PLEASE NOTE: FBSDKSDKMonotonicTimeTests work fine, but are disabled
|
||||
* because they take several seconds. Please re-enable them to test
|
||||
* any changes you're making here!
|
||||
*/
|
||||
static uint64_t _get_time_nanoseconds(void)
|
||||
{
|
||||
static struct mach_timebase_info tb_info = {0};
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
int ret = mach_timebase_info(&tb_info);
|
||||
assert(0 == ret);
|
||||
});
|
||||
|
||||
return (mach_absolute_time() * tb_info.numer) / tb_info.denom;
|
||||
}
|
||||
|
||||
FBSDKMonotonicTimeSeconds FBSDKMonotonicTimeGetCurrentSeconds(void)
|
||||
{
|
||||
const uint64_t nowNanoSeconds = _get_time_nanoseconds();
|
||||
return (FBSDKMonotonicTimeSeconds)nowNanoSeconds / (FBSDKMonotonicTimeSeconds)1000000000.0;
|
||||
}
|
||||
|
||||
FBSDKMonotonicTimeMilliseconds FBSDKMonotonicTimeGetCurrentMilliseconds(void)
|
||||
{
|
||||
const uint64_t nowNanoSeconds = _get_time_nanoseconds();
|
||||
return nowNanoSeconds / 1000000;
|
||||
}
|
||||
|
||||
FBSDKMonotonicTimeNanoseconds FBSDKMonotonicTimeGetCurrentNanoseconds(void)
|
||||
{
|
||||
return _get_time_nanoseconds();
|
||||
}
|
||||
|
||||
FBSDKMachAbsoluteTimeUnits FBSDKMonotonicTimeConvertSecondsToMachUnits(FBSDKMonotonicTimeSeconds seconds)
|
||||
{
|
||||
static double ratio = 0;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
struct mach_timebase_info tb_info = {0};
|
||||
int ret = mach_timebase_info(&tb_info);
|
||||
assert(0 == ret);
|
||||
ratio = ((double) tb_info.denom / (double)tb_info.numer) * 1000000000.0;
|
||||
});
|
||||
|
||||
return seconds * ratio;
|
||||
}
|
||||
|
||||
FBSDKMonotonicTimeSeconds FBSDKMonotonicTimeConvertMachUnitsToSeconds(FBSDKMachAbsoluteTimeUnits machUnits)
|
||||
{
|
||||
static double ratio = 0;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
struct mach_timebase_info tb_info = {0};
|
||||
int ret = mach_timebase_info(&tb_info);
|
||||
assert(0 == ret);
|
||||
ratio = ((double) tb_info.numer / (double)tb_info.denom) / 1000000000.0;
|
||||
});
|
||||
|
||||
return ratio * (double)machUnits;
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
// 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 "FBSDKProfile.h"
|
||||
|
||||
@interface FBSDKProfile(Internal)
|
||||
|
||||
+ (void)cacheProfile:(FBSDKProfile *) profile;
|
||||
+ (FBSDKProfile *)fetchCachedProfile;
|
||||
|
||||
@end
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
// 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 "FBSDKAccessTokenCache.h"
|
||||
#import "FBSDKSettings.h"
|
||||
|
||||
@interface FBSDKSettings(Internal)
|
||||
|
||||
+ (FBSDKAccessTokenCache *)accessTokenCache;
|
||||
|
||||
- (void)setAccessTokenCache;
|
||||
|
||||
+ (NSString *)graphAPIDebugParamValue;
|
||||
|
||||
+ (BOOL)isGraphErrorRecoveryDisabled;
|
||||
|
||||
// used by Unity.
|
||||
+ (NSString *)userAgentSuffix;
|
||||
+ (void)setUserAgentSuffix:(NSString *)suffix;
|
||||
|
||||
@end
|
||||
Generated
+82
@@ -0,0 +1,82 @@
|
||||
// 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 <Accounts/Accounts.h>
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
typedef void (^FBSDKGraphRequestAccessToAccountsHandler)(NSString *oauthToken, NSError *accountStoreError);
|
||||
|
||||
/*
|
||||
@class
|
||||
|
||||
@abstract Adapter around system account store APIs. Note this is only intended for internal
|
||||
consumption. If publicized, consider moving declarations to an internal only header and
|
||||
reconsider dispatching semantics.
|
||||
*/
|
||||
@interface FBSDKSystemAccountStoreAdapter : NSObject
|
||||
|
||||
/*
|
||||
@abstract
|
||||
Requests access to the device's Facebook account for the given parameters.
|
||||
@param permissions the permissions
|
||||
@param defaultAudience the default audience
|
||||
@param isReauthorize a flag describing if this is a reauth request
|
||||
@param appID the app id
|
||||
@param handler the handler that will be invoked on completion (dispatched to the main thread). the oauthToken is nil on failure.
|
||||
*/
|
||||
- (void)requestAccessToFacebookAccountStore:(NSSet *)permissions
|
||||
defaultAudience:(NSString *)defaultAudience
|
||||
isReauthorize:(BOOL)isReauthorize
|
||||
appID:(NSString *)appID
|
||||
handler:(FBSDKGraphRequestAccessToAccountsHandler)handler;
|
||||
|
||||
/*
|
||||
@abstract Sends a message to the device account store to renew the Facebook account credentials
|
||||
|
||||
@param handler the handler that is invoked on completion
|
||||
*/
|
||||
- (void)renewSystemAuthorization:(void(^)(ACAccountCredentialRenewResult result, NSError *error))handler;
|
||||
|
||||
/*
|
||||
@abstracts gets the oauth token stored in the account store credential, if available. If not empty,
|
||||
this implies user has granted access.
|
||||
*/
|
||||
- (NSString *)accessTokenString;
|
||||
|
||||
/*
|
||||
@abstract Gets the singleton instance.
|
||||
*/
|
||||
+ (FBSDKSystemAccountStoreAdapter *)sharedInstance;
|
||||
|
||||
/*
|
||||
@abstract Sets the singleton instance, typically only for unit tests
|
||||
*/
|
||||
+ (void)setSharedInstance:(FBSDKSystemAccountStoreAdapter *)instance;
|
||||
|
||||
/*
|
||||
@abstract Gets or sets the flag indicating if the next requestAccess call should block
|
||||
on a renew call.
|
||||
*/
|
||||
@property (nonatomic, assign) BOOL forceBlockingRenew;
|
||||
|
||||
/*
|
||||
@abstract A convenience getter to the Facebook account type in the account store, if available.
|
||||
*/
|
||||
@property (strong, nonatomic, readonly) ACAccountType *accountType;
|
||||
|
||||
@end
|
||||
Generated
+275
@@ -0,0 +1,275 @@
|
||||
// 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 "FBSDKSystemAccountStoreAdapter.h"
|
||||
|
||||
#import "FBSDKConstants.h"
|
||||
#import "FBSDKDynamicFrameworkLoader.h"
|
||||
#import "FBSDKError.h"
|
||||
#import "FBSDKLogger.h"
|
||||
#import "FBSDKSettings+Internal.h"
|
||||
|
||||
@interface FBSDKSystemAccountStoreAdapter ()
|
||||
|
||||
@property (retain, nonatomic, readonly) ACAccountStore *accountStore;
|
||||
|
||||
@end
|
||||
|
||||
static NSString *const FBForceBlockingRenewKey = @"com.facebook.sdk:ForceBlockingRenewKey";
|
||||
static FBSDKSystemAccountStoreAdapter *_singletonInstance = nil;
|
||||
|
||||
@implementation FBSDKSystemAccountStoreAdapter
|
||||
{
|
||||
ACAccountStore *_accountStore;
|
||||
ACAccountType *_accountType;
|
||||
}
|
||||
|
||||
+ (void)initialize
|
||||
{
|
||||
if (self == [FBSDKSystemAccountStoreAdapter class]) {
|
||||
_singletonInstance = [[self alloc] init];
|
||||
}
|
||||
}
|
||||
|
||||
- (instancetype)init
|
||||
{
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_forceBlockingRenew = [[NSUserDefaults standardUserDefaults] boolForKey:FBForceBlockingRenewKey];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
#pragma mark - Properties
|
||||
|
||||
- (ACAccountStore *)accountStore
|
||||
{
|
||||
if (_accountStore == nil) {
|
||||
_accountStore = [[fbsdkdfl_ACAccountStoreClass() alloc] init];
|
||||
}
|
||||
return _accountStore;
|
||||
}
|
||||
|
||||
- (ACAccountType *)accountType
|
||||
{
|
||||
if (_accountType == nil) {
|
||||
_accountType = [self.accountStore accountTypeWithAccountTypeIdentifier:@"com.apple.facebook"];
|
||||
}
|
||||
return _accountType;
|
||||
}
|
||||
|
||||
- (void)setForceBlockingRenew:(BOOL)forceBlockingRenew
|
||||
{
|
||||
if (_forceBlockingRenew != forceBlockingRenew) {
|
||||
_forceBlockingRenew = forceBlockingRenew;
|
||||
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
|
||||
[userDefaults setBool:forceBlockingRenew forKey:FBForceBlockingRenewKey];
|
||||
[userDefaults synchronize];
|
||||
}
|
||||
}
|
||||
|
||||
+ (FBSDKSystemAccountStoreAdapter *)sharedInstance
|
||||
{
|
||||
return _singletonInstance;
|
||||
}
|
||||
|
||||
+ (void)setSharedInstance:(FBSDKSystemAccountStoreAdapter *)instance
|
||||
{
|
||||
_singletonInstance = instance;
|
||||
}
|
||||
|
||||
- (NSString *)accessTokenString
|
||||
{
|
||||
if (self.accountType && self.accountType.accessGranted) {
|
||||
NSArray *fbAccounts = [self.accountStore accountsWithAccountType:self.accountType];
|
||||
if (fbAccounts.count > 0) {
|
||||
id account = [fbAccounts objectAtIndex:0];
|
||||
id credential = [account credential];
|
||||
|
||||
return [credential oauthToken];
|
||||
}
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
#pragma mark - Public properties and methods
|
||||
|
||||
- (void)requestAccessToFacebookAccountStore:(NSSet *)permissions
|
||||
defaultAudience:(NSString *)defaultAudience
|
||||
isReauthorize:(BOOL)isReauthorize
|
||||
appID:(NSString *)appID
|
||||
handler:(FBSDKGraphRequestAccessToAccountsHandler)handler
|
||||
{
|
||||
if (appID == nil) {
|
||||
@throw [NSException exceptionWithName:NSInvalidArgumentException
|
||||
reason:@"appID cannot be nil"
|
||||
userInfo:nil];
|
||||
}
|
||||
|
||||
// no publish_* permissions are permitted with a nil audience
|
||||
if (!defaultAudience && isReauthorize) {
|
||||
for (NSString *p in permissions) {
|
||||
if ([p hasPrefix:@"publish"]) {
|
||||
[[NSException exceptionWithName:NSInvalidArgumentException
|
||||
reason:@"FBSDKLoginManager: One or more publish permission was requested "
|
||||
@"without specifying an audience; use FBSDKDefaultAudienceOnlyMe, "
|
||||
@"FBSDKDefaultAudienceFriends, or FBSDKDefaultAudienceEveryone"
|
||||
userInfo:nil]
|
||||
raise];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// construct access options
|
||||
NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
|
||||
appID, fbsdkdfl_ACFacebookAppIdKey(),
|
||||
[permissions allObjects], fbsdkdfl_ACFacebookPermissionsKey(),
|
||||
defaultAudience, fbsdkdfl_ACFacebookAudienceKey(), // must end on this key/value due to audience possibly being nil
|
||||
nil];
|
||||
|
||||
if (self.forceBlockingRenew
|
||||
&& [self.accountStore accountsWithAccountType:self.accountType].count > 0) {
|
||||
// If the force renew flag is set and an iOS FB account is still set,
|
||||
// chain the requestAccessBlock to a successful renew result
|
||||
[self renewSystemAuthorization:^(ACAccountCredentialRenewResult result, NSError *error) {
|
||||
if (result == ACAccountCredentialRenewResultRenewed) {
|
||||
self.forceBlockingRenew = NO;
|
||||
[self requestAccessToFacebookAccountStore:options retrying:NO handler:handler];
|
||||
} else if (handler) {
|
||||
// Otherwise, invoke the caller's handler back on the main thread with an
|
||||
// error that will trigger the password change user message.
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
handler(nil, error);
|
||||
});
|
||||
}
|
||||
}];
|
||||
} else {
|
||||
// Otherwise go ahead and invoke normal request.
|
||||
[self requestAccessToFacebookAccountStore:options retrying:NO handler:handler];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)requestAccessToFacebookAccountStore:(NSDictionary *)options
|
||||
retrying:(BOOL)retrying
|
||||
handler:(FBSDKGraphRequestAccessToAccountsHandler)handler
|
||||
{
|
||||
if (!self.accountType) {
|
||||
if (handler) {
|
||||
handler(nil, [FBSDKError errorWithCode:FBSDKUnknownErrorCode message:@"Invalid request to account store"]);
|
||||
}
|
||||
return;
|
||||
}
|
||||
// we will attempt an iOS integrated facebook login
|
||||
[self.accountStore
|
||||
requestAccessToAccountsWithType:self.accountType
|
||||
options:options
|
||||
completion:^(BOOL granted, NSError *error) {
|
||||
if (!granted &&
|
||||
error.code == ACErrorPermissionDenied &&
|
||||
[error.description rangeOfString:@"remote_app_id does not match stored id"].location != NSNotFound) {
|
||||
|
||||
[FBSDKLogger singleShotLogEntry:FBSDKLoggingBehaviorDeveloperErrors formatString:
|
||||
@"System authorization failed:'%@'. This may be caused by a mismatch between"
|
||||
@" the bundle identifier and your app configuration on the server"
|
||||
@" at developers.facebook.com/apps.",
|
||||
error.localizedDescription];
|
||||
}
|
||||
|
||||
// requestAccessToAccountsWithType:options:completion: completes on an
|
||||
// arbitrary thread; let's process this back on our main thread
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
NSError *accountStoreError = error;
|
||||
NSString *oauthToken = nil;
|
||||
id account = nil;
|
||||
if (granted) {
|
||||
NSArray *fbAccounts = [self.accountStore accountsWithAccountType:self.accountType];
|
||||
if (fbAccounts.count > 0) {
|
||||
account = [fbAccounts objectAtIndex:0];
|
||||
|
||||
id credential = [account credential];
|
||||
|
||||
oauthToken = [credential oauthToken];
|
||||
}
|
||||
self.forceBlockingRenew = NO;
|
||||
}
|
||||
|
||||
if (!accountStoreError && !oauthToken) {
|
||||
if (!retrying) {
|
||||
// This can happen as a result of, e.g., restoring from iCloud to a different device. Try once to renew.
|
||||
[self renewSystemAuthorization:^(ACAccountCredentialRenewResult renewResult, NSError *renewError) {
|
||||
// Call block again, regardless of result -- either we'll get credentials or we'll fail with the
|
||||
// exception below. We want to treat failure here the same regardless of whether it was before or after the refresh attempt.
|
||||
[self requestAccessToFacebookAccountStore:options retrying:YES handler:handler];
|
||||
}];
|
||||
return;
|
||||
}
|
||||
// else call handler with nils.
|
||||
}
|
||||
handler(oauthToken, accountStoreError);
|
||||
});
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)renewSystemAuthorization:(void(^)(ACAccountCredentialRenewResult, NSError *))handler
|
||||
{
|
||||
// if the slider has been set to off, renew calls to iOS simply hang, so we must
|
||||
// preemptively check for that condition.
|
||||
if (self.accountStore && self.accountType && self.accountType.accessGranted) {
|
||||
NSArray *fbAccounts = [self.accountStore accountsWithAccountType:self.accountType];
|
||||
id account;
|
||||
if (fbAccounts && [fbAccounts count] > 0 &&
|
||||
(account = [fbAccounts objectAtIndex:0])) {
|
||||
|
||||
FBSDKAccessToken *currentToken = [FBSDKAccessToken currentAccessToken];
|
||||
if (![currentToken.tokenString isEqualToString:[self accessTokenString]]) {
|
||||
currentToken = nil;
|
||||
}
|
||||
[self.accountStore renewCredentialsForAccount:account completion:^(ACAccountCredentialRenewResult renewResult, NSError *error) {
|
||||
if (error) {
|
||||
[FBSDKLogger singleShotLogEntry:FBSDKLoggingBehaviorAccessTokens
|
||||
logEntry:[NSString stringWithFormat:@"renewCredentialsForAccount result:%ld, error: %@",
|
||||
(long)renewResult,
|
||||
error]];
|
||||
}
|
||||
if (renewResult == ACAccountCredentialRenewResultRenewed &&
|
||||
currentToken &&
|
||||
[currentToken isEqual:[FBSDKAccessToken currentAccessToken]]) {
|
||||
// account store renewals can change the stored oauth token so we need to update the currentAccessToken
|
||||
// so future comparisons to -[ accessTokenString] work correctly (e.g., error recovery).
|
||||
FBSDKAccessToken *updatedToken = [[FBSDKAccessToken alloc] initWithTokenString:[self accessTokenString]
|
||||
permissions:[currentToken.permissions allObjects] declinedPermissions:[currentToken.declinedPermissions allObjects]
|
||||
appID:currentToken.appID
|
||||
userID:currentToken.userID
|
||||
expirationDate:[NSDate distantFuture]
|
||||
refreshDate:[NSDate date]];
|
||||
[FBSDKAccessToken setCurrentAccessToken:updatedToken];
|
||||
}
|
||||
if (handler) {
|
||||
handler(renewResult, error);
|
||||
}
|
||||
}];
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (handler) {
|
||||
handler(ACAccountCredentialRenewResultFailed, nil);
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
// 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/FBSDKMacros.h>
|
||||
|
||||
typedef NS_ENUM(NSInteger, FBSDKTriStateBOOL)
|
||||
{
|
||||
FBSDKTriStateBOOLValueUnknown = -1,
|
||||
FBSDKTriStateBOOLValueNO = 0,
|
||||
FBSDKTriStateBOOLValueYES = 1,
|
||||
};
|
||||
|
||||
FBSDK_EXTERN FBSDKTriStateBOOL FBSDKTriStateBOOLFromBOOL(BOOL value);
|
||||
FBSDK_EXTERN FBSDKTriStateBOOL FBSDKTriStateBOOLFromNSNumber(NSNumber *value);
|
||||
FBSDK_EXTERN BOOL BOOLFromFBSDKTriStateBOOL(FBSDKTriStateBOOL value, BOOL defaultValue);
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
// 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 "FBSDKTriStateBOOL.h"
|
||||
|
||||
FBSDKTriStateBOOL FBSDKTriStateBOOLFromBOOL(BOOL value)
|
||||
{
|
||||
return value ? FBSDKTriStateBOOLValueYES : FBSDKTriStateBOOLValueNO;
|
||||
}
|
||||
|
||||
FBSDKTriStateBOOL FBSDKTriStateBOOLFromNSNumber(NSNumber *value)
|
||||
{
|
||||
return ([value isKindOfClass:[NSNumber class]] ?
|
||||
FBSDKTriStateBOOLFromBOOL([value boolValue]) :
|
||||
FBSDKTriStateBOOLValueUnknown);
|
||||
}
|
||||
|
||||
BOOL BOOLFromFBSDKTriStateBOOL(FBSDKTriStateBOOL value, BOOL defaultValue)
|
||||
{
|
||||
switch (value) {
|
||||
case FBSDKTriStateBOOLValueYES:
|
||||
return YES;
|
||||
case FBSDKTriStateBOOLValueNO:
|
||||
return NO;
|
||||
case FBSDKTriStateBOOLValueUnknown:
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
// 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>
|
||||
|
||||
@interface FBSDKTypeUtility : NSObject
|
||||
|
||||
+ (NSArray *)arrayValue:(id)object;
|
||||
+ (BOOL)boolValue:(id)object;
|
||||
+ (NSDictionary *)dictionaryValue:(id)object;
|
||||
+ (NSInteger)integerValue:(id)object;
|
||||
+ (id)objectValue:(id)object;
|
||||
+ (NSString *)stringValue:(id)object;
|
||||
+ (NSUInteger)unsignedIntegerValue:(id)object;
|
||||
+ (NSURL *)URLValue:(id)object;
|
||||
|
||||
@end
|
||||
+120
@@ -0,0 +1,120 @@
|
||||
// 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 "FBSDKTypeUtility.h"
|
||||
|
||||
#import "FBSDKMacros.h"
|
||||
|
||||
@implementation FBSDKTypeUtility
|
||||
|
||||
#pragma mark - Class Methods
|
||||
|
||||
+ (NSArray *)arrayValue:(id)object
|
||||
{
|
||||
return (NSArray *)[self _objectValue:object ofClass:[NSArray class]];
|
||||
}
|
||||
|
||||
+ (BOOL)boolValue:(id)object
|
||||
{
|
||||
if ([object isKindOfClass:[NSNumber class]]) {
|
||||
// @0 or @NO returns NO, otherwise YES
|
||||
return [(NSNumber *)object boolValue];
|
||||
} else if ([object isKindOfClass:[NSString class]]) {
|
||||
// Returns YES on encountering one of "Y", "y", "T", "t", or a digit 1-9, otherwise NO
|
||||
return [(NSString *)object boolValue];
|
||||
} else {
|
||||
return ([self objectValue:object] != nil);
|
||||
}
|
||||
}
|
||||
|
||||
+ (NSDictionary *)dictionaryValue:(id)object
|
||||
{
|
||||
return (NSDictionary *)[self _objectValue:object ofClass:[NSDictionary class]];
|
||||
}
|
||||
|
||||
+ (NSInteger)integerValue:(id)object
|
||||
{
|
||||
if ([object isKindOfClass:[NSNumber class]]) {
|
||||
return [(NSNumber *)object integerValue];
|
||||
} else if ([object isKindOfClass:[NSString class]]) {
|
||||
return [(NSString *)object integerValue];
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
+ (id)objectValue:(id)object
|
||||
{
|
||||
return ([object isKindOfClass:[NSNull class]] ? nil : object);
|
||||
}
|
||||
|
||||
+ (NSString *)stringValue:(id)object
|
||||
{
|
||||
if ([object isKindOfClass:[NSString class]]) {
|
||||
return (NSString *)object;
|
||||
} else if ([object isKindOfClass:[NSNumber class]]) {
|
||||
return [(NSNumber *)object stringValue];
|
||||
} else if ([object isKindOfClass:[NSURL class]]) {
|
||||
return [(NSURL *)object absoluteString];
|
||||
} else {
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
|
||||
+ (NSUInteger)unsignedIntegerValue:(id)object
|
||||
{
|
||||
if ([object isKindOfClass:[NSNumber class]]) {
|
||||
return [(NSNumber *)object unsignedIntegerValue];
|
||||
} else {
|
||||
// there is no direct support for strings containing unsigned values > NSIntegerMax - not worth writing ourselves
|
||||
// right now, so just cap unsigned values at NSIntegerMax until we have a need for larger
|
||||
NSInteger integerValue = [self integerValue:object];
|
||||
if (integerValue < 0) {
|
||||
integerValue = 0;
|
||||
}
|
||||
return (NSUInteger)integerValue;
|
||||
}
|
||||
}
|
||||
|
||||
+ (NSURL *)URLValue:(id)object
|
||||
{
|
||||
if ([object isKindOfClass:[NSURL class]]) {
|
||||
return (NSURL *)object;
|
||||
} else if ([object isKindOfClass:[NSString class]]) {
|
||||
return [[NSURL alloc] initWithString:(NSString *)object];
|
||||
} else {
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Object Lifecycle
|
||||
|
||||
- (instancetype)init
|
||||
{
|
||||
FBSDK_NO_DESIGNATED_INITIALIZER();
|
||||
return nil;
|
||||
}
|
||||
|
||||
#pragma mark - Helper Methods
|
||||
|
||||
+ (id)_objectValue:(id)object ofClass:(Class)expectedClass
|
||||
{
|
||||
return ([object isKindOfClass:expectedClass] ? object : nil);
|
||||
}
|
||||
|
||||
@end
|
||||
Loaded 100 of 370 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user