- Upgrade Pods

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

View File

@ -29,11 +29,11 @@ PODS:
- Expecta (~> 1.0)
- FBSnapshotTestCase/Core (~> 2.0)
- Specta (~> 1.0)
- FBSDKCoreKit (4.10.1):
- Bolts (~> 1.5)
- FBSDKLoginKit (4.10.1):
- FBSDKCoreKit (4.11.0):
- Bolts (~> 1.7)
- FBSDKLoginKit (4.11.0):
- FBSDKCoreKit
- FBSDKShareKit (4.10.1):
- FBSDKShareKit (4.11.0):
- FBSDKCoreKit
- FBSnapshotTestCase (2.1.0):
- FBSnapshotTestCase/SwiftSupport (= 2.1.0)
@ -48,7 +48,7 @@ PODS:
- CocoaSecurity (~> 1.2.2)
- nv-ios-http-status (0.0.1)
- PEAR-FileManager-iOS (1.3.1)
- PNObject (0.5.7):
- PNObject (0.7.0):
- AFNetworking
- CodFis-Helper
- DJLocalization
@ -101,9 +101,9 @@ SPEC CHECKSUMS:
DJLocalization: 55ab1d1ee4ac2eb3ec4e3a8a93145fd9d10ae6eb
Expecta: e1c022fcd33910b6be89c291d2775b3fe27a89fe
Expecta+Snapshots: c343f410c7a6392f3e22e78f94c44b6c0749a516
FBSDKCoreKit: d2aaed5e9ab7d8d6301c533376a1fbff1cf3deb5
FBSDKLoginKit: 699ff169080e3072de4b9b0faca90bf23dc36deb
FBSDKShareKit: 2fd887cce0056bdda91f99b2021d724a4fed8e88
FBSDKCoreKit: 686ac982723a14ec9ddb85e2f81235d7706c891b
FBSDKLoginKit: bade9fc78277764149ccc5bfaadbf13c83175c6a
FBSDKShareKit: 2d1746144cfc8a9dbbd24997c34ee0471be51b6a
FBSnapshotTestCase: 366ecd378511d7716c79991cd8067d1eed23578d
JRSwizzle: dd5ead5d913a0f29e7f558200165849f006bb1e3
NACrypto: ce3900f1775f1b0cc27ce7c4953b94c598a74149
@ -112,7 +112,7 @@ SPEC CHECKSUMS:
NSUserDefaults-AESEncryptor: da02cfef056f1e18ebe2748767915f08b274c9c5
nv-ios-http-status: b6c2b5fc8656cc19e0d3000dadce2080b99d0e2f
PEAR-FileManager-iOS: 3bc403f68a53483f5629aa822f4649e40275c4d3
PNObject: 9567f1c80c154eb17798e2b9f572a707c407d7b5
PNObject: be02023e5a4c9a1110a569e54886dc13bfa9cb82
PureLayout: f35f5384c9c4e4479df041dbe33ad7577b71ddfb
RZDataBinding: 00d468ebe667f02c2bd5416f87b4b5d826188c4d
Specta: ac94d110b865115fe60ff2c6d7281053c6f8e8a2

View File

@ -363,6 +363,28 @@ FBSDK_EXTERN NSString *const FBSDKAppEventParameterValueNo;
parameters:(NSDictionary *)parameters
accessToken:(FBSDKAccessToken *)accessToken;
/*
* Push Notifications Logging
*/
/*!
@abstract
Log an app event that tracks that the application was open via Push Notification.
@param payload Notification payload received via `UIApplicationDelegate`.
*/
+ (void)logPushNotificationOpen:(NSDictionary *)payload;
/*!
@abstract
Log an app event that tracks that a custom action was taken from a push notification.
@param payload Notification payload received via `UIApplicationDelegate`.
@param action Name of the action that was taken.
*/
+ (void)logPushNotificationOpen:(NSDictionary *)payload action:(NSString *)action;
/*!
@abstract
@ -381,6 +403,21 @@ FBSDK_EXTERN NSString *const FBSDKAppEventParameterValueNo;
*/
+ (void)activateApp;
/*
* Push Notifications Registration
*/
/*!
@abstract
Sets a device token to register the current application installation for push notifications.
@discussion
Sets a device token from `NSData` representation that you get from `UIApplicationDelegate.-application:didRegisterForRemoteNotificationsWithDeviceToken:`.
@param deviceToken Device token data.
*/
+ (void)setPushNotificationsDeviceToken:(NSData *)deviceToken;
/*
* Control over event batching/flushing
*/

View File

@ -147,6 +147,9 @@ NSString *const FBSDKAppEventParameterDialogOutcome = @"fb_dialog_
NSString *const FBSDKAppEventParameterDialogErrorMessage = @"fb_dialog_outcome_error_message";
NSString *const FBSDKAppEventParameterDialogMode = @"fb_dialog_mode";
NSString *const FBSDKAppEventParameterDialogShareContentType = @"fb_dialog_share_content_type";
NSString *const FBSDKAppEventParameterLogTime = @"_logTime";
NSString *const FBSDKAppEventParameterEventName = @"_eventName";
NSString *const FBSDKAppEventParameterImplicitlyLogged = @"_implicitlyLogged";
// Event parameter values internal to this file
NSString *const FBSDKAppEventsDialogOutcomeValue_Completed = @"Completed";
@ -172,6 +175,19 @@ NSString *const FBSDKAppEventsLoggingResultNotification = @"com.facebook.sdk:FBS
NSString *const FBSDKAppEventsOverrideAppIDBundleKey = @"FacebookLoggingOverrideAppID";
//
// Push Notifications
// Activities Endpoint Parameter
static NSString *const FBSDKActivitesParameterPushDeviceToken = @"device_token";
// Event Name
static NSString *const FBSDKAppEventNamePushOpened = @"fb_mobile_push_opened";
// Event Parameter
static NSString *const FBSDKAppEventParameterPushCampaign = @"fb_push_campaign";
static NSString *const FBSDKAppEventParameterPushAction = @"fb_push_action";
// Payload Keys
static NSString *const FBSDKAppEventsPushPayloadKey = @"fb_push_payload";
static NSString *const FBSDKAppEventsPushPayloadCampaignKey = @"campaign";
#define NUM_LOG_EVENTS_TO_TRY_TO_FLUSH_AFTER 100
#define FLUSH_PERIOD_IN_SECONDS 15
#define APP_SUPPORTS_ATTRIBUTION_ID_RECHECK_PERIOD 60 * 60 * 24
@ -183,6 +199,9 @@ static NSString *g_overrideAppID = nil;
@property (nonatomic, readwrite) FBSDKAppEventsFlushBehavior flushBehavior;
//for testing only.
@property (nonatomic, assign) BOOL disableTimer;
@property (nonatomic, copy) NSString *pushNotificationsDeviceTokenString;
@end
@implementation FBSDKAppEvents
@ -344,6 +363,35 @@ static NSString *g_overrideAppID = nil;
}
}
/*
* Push Notifications Logging
*/
+ (void)logPushNotificationOpen:(NSDictionary *)payload
{
[self logPushNotificationOpen:payload action:nil];
}
+ (void)logPushNotificationOpen:(NSDictionary *)payload action:(NSString *)action
{
NSDictionary *facebookPayload = payload[FBSDKAppEventsPushPayloadKey];
if (!facebookPayload) {
return;
}
NSString *campaign = facebookPayload[FBSDKAppEventsPushPayloadCampaignKey];
if (campaign.length == 0) {
[FBSDKLogger singleShotLogEntry:FBSDKLoggingBehaviorDeveloperErrors
logEntry:@"Malformed payload specified for logging a push notification open."];
return;
}
NSMutableDictionary *parameters = [NSMutableDictionary dictionaryWithObject:campaign forKey:FBSDKAppEventParameterPushCampaign];
if (action) {
parameters[FBSDKAppEventParameterPushAction] = action;
}
[self logEvent:FBSDKAppEventNamePushOpened parameters:parameters];
}
+ (void)activateApp
{
[FBSDKAppEventsUtility ensureOnMainThread:NSStringFromSelector(_cmd) className:NSStringFromClass(self)];
@ -360,6 +408,11 @@ static NSString *g_overrideAppID = nil;
[FBSDKTimeSpentData restore:YES];
}
+ (void)setPushNotificationsDeviceToken:(NSData *)deviceToken
{
[FBSDKAppEvents singleton].pushNotificationsDeviceTokenString = [FBSDKInternalUtility hexadecimalStringFromData:deviceToken];
}
+ (FBSDKAppEventsFlushBehavior)flushBehavior
{
return [FBSDKAppEvents singleton].flushBehavior;
@ -532,11 +585,13 @@ static NSString *g_overrideAppID = nil;
}
NSMutableDictionary *eventDictionary = [NSMutableDictionary dictionaryWithDictionary:parameters];
eventDictionary[@"_eventName"] = eventName;
eventDictionary[@"_logTime"] = @([FBSDKAppEventsUtility unixTimeNow]);
eventDictionary[FBSDKAppEventParameterEventName] = eventName;
if (!eventDictionary[FBSDKAppEventParameterLogTime]) {
eventDictionary[FBSDKAppEventParameterLogTime] = @([FBSDKAppEventsUtility unixTimeNow]);
}
[FBSDKInternalUtility dictionary:eventDictionary setObject:valueToSum forKey:@"_valueToSum"];
if (isImplicitlyLogged) {
eventDictionary[@"_implicitlyLogged"] = @"1";
eventDictionary[FBSDKAppEventParameterImplicitlyLogged] = @"1";
}
NSString *currentViewControllerName;
@ -650,6 +705,9 @@ static NSString *g_overrideAppID = nil;
if (appEventsState.numSkipped > 0) {
postParameters[@"num_skipped_events"] = [NSString stringWithFormat:@"%lu", (unsigned long)appEventsState.numSkipped];
}
if (self.pushNotificationsDeviceTokenString) {
postParameters[FBSDKActivitesParameterPushDeviceToken] = self.pushNotificationsDeviceTokenString;
}
NSString *loggingEntry = nil;
if ([[FBSDKSettings loggingBehavior] containsObject:FBSDKLoggingBehaviorAppEvents]) {

View File

@ -27,6 +27,7 @@
#import "FBSDKGraphRequest+Internal.h"
#import "FBSDKGraphRequestConnection.h"
#import "FBSDKInternalUtility.h"
#import "FBSDKLogger.h"
#import "FBSDKSettings+Internal.h"
#import "FBSDKUtility.h"
@ -41,17 +42,6 @@ static NSString *const kIPadKey = @"ipad";
static NSString *const kShouldFallbackKey = @"should_fallback";
static NSString *const kAppLinksKey = @"app_links";
static void FBSDKAppLinkResolverBoltsClassFromString(Class *clazz, NSString *className)
{
*clazz = NSClassFromString(className);
if (*clazz == nil) {
NSString *message = [NSString stringWithFormat:@"Unable to load class %@. Did you link Bolts.framework?", className];
@throw [NSException exceptionWithName:NSInternalInconsistencyException
reason:message
userInfo:nil];
}
}
@interface FBSDKAppLinkResolver ()
@property (nonatomic, strong) NSMutableDictionary *cachedLinks;
@ -68,10 +58,11 @@ static Class g_BFTaskClass;
+ (void)initialize
{
if (self == [FBSDKAppLinkResolver class]) {
FBSDKAppLinkResolverBoltsClassFromString(&g_BFTaskCompletionSourceClass, @"BFTaskCompletionSource");
FBSDKAppLinkResolverBoltsClassFromString(&g_BFAppLinkTargetClass, @"BFAppLinkTarget");
FBSDKAppLinkResolverBoltsClassFromString(&g_BFAppLinkClass, @"BFAppLink");
FBSDKAppLinkResolverBoltsClassFromString(&g_BFTaskClass, @"BFTask");
g_BFTaskCompletionSourceClass = [FBSDKInternalUtility
resolveBoltsClassWithName:@"BFTaskCompletionSource"];
g_BFAppLinkTargetClass = [FBSDKInternalUtility resolveBoltsClassWithName:@"BFAppLinkTarget"];
g_BFTaskClass = [FBSDKInternalUtility resolveBoltsClassWithName:@"BFTask"];
g_BFAppLinkClass = [FBSDKInternalUtility resolveBoltsClassWithName:@"BFAppLink"];
}
}

View File

@ -28,6 +28,14 @@
*/
typedef void (^FBSDKDeferredAppLinkHandler)(NSURL *url, NSError *error);
/*!
@abstract Describes the callback for fetchOrganicDeferredAppLink.
@param url the url representing the deferred App Link
*/
typedef void (^FBSDKDeferredAppInviteHandler)(NSURL *url);
/*!
@abstract Class containing App Links related utility methods.
*/
@ -52,4 +60,41 @@ typedef void (^FBSDKDeferredAppLinkHandler)(NSURL *url, NSError *error);
*/
+ (void)fetchDeferredAppLink:(FBSDKDeferredAppLinkHandler)handler;
/*!
@abstract Call this method from the main thread to fetch deferred deeplink for App Invites
Handler is called with deeplink url, if found, nil otherwise.
@param handler Handler to be called when we fetch deeplink url.
@return YES if async fetch process was started, NO if it failed to start. Note it returns NO
for versions < iOS 9.
@discussion Call this method from the main thread to fetch deferred deeplink if you use App Invites.
This may require a network round trip. If successful, this will call the handler provided, with
deferred deeplink that was clicked by the user. If there is a error/timeout, handler will be called
with nil.
This method only works on iOS 9+ and returns NO otherwise.
This method should only be called from a location that occurs after any launching URL has
been processed (e.g., you should call this method from your application delegate's
didFinishLaunchingWithOptions:).
*/
+ (BOOL)fetchDeferredAppInvite:(FBSDKDeferredAppInviteHandler)handler;
/*
@abstract Call this method to fetch promotion code from the url, if it's present. This function
requires Bolts framework.
Note: This throws an exception if Bolts.framework is not linked. Add '[BFURL class]' in intialize method
of your AppDelegate.
@param url App Link url that was passed to the app.
@return Promotion code string.
@discussion Call this method to fetch App Invite Promotion Code from applink if present.
This can be used to fetch the promotion code that was associated with the invite when it
was created. This method should be called with the url from the openURL method.
*/
+ (NSString*)appInvitePromotionCodeFromURL:(NSURL*)url;
@end

View File

@ -18,8 +18,12 @@
#import "FBSDKAppLinkUtility.h"
#import <Bolts/BFURL.h>
#import "FBSDKAppEventsUtility.h"
#import "FBSDKGraphRequest.h"
#import "FBSDKInternalUtility.h"
#import "FBSDKOrganicDeeplinkHelper.h"
#import "FBSDKSettings.h"
#import "FBSDKUtility.h"
@ -77,4 +81,34 @@ static NSString *const FBSDKDeferredAppLinkEvent = @"DEFERRED_APP_LINK";
}];
}
+ (BOOL)fetchDeferredAppInvite:(FBSDKDeferredAppInviteHandler)handler
{
NSAssert([NSThread isMainThread], @"FBSDKAppLink fetchOrganicDeferredAppLink: must be invoked from main thread.");
NSAssert(handler, @"FBSDKAppLink fetchOrganicDeferredAppLink: must be invoked with valid handler.");
FBSDKOrganicDeeplinkHelper *deeplinkHelper = [[FBSDKOrganicDeeplinkHelper alloc] init];
return [deeplinkHelper fetchOrganicDeeplink:handler];
}
+ (NSString*)appInvitePromotionCodeFromURL:(NSURL*)url;
{
BFURL *parsedUrl = [[FBSDKInternalUtility resolveBoltsClassWithName:@"BFURL"] URLWithURL:url];
NSDictionary *extras = [parsedUrl appLinkExtras];
if (extras) {
NSString *deeplinkContextString = extras[@"deeplink_context"];
// Parse deeplinkContext and extract promo code
if ([deeplinkContextString length] > 0) {
NSError *error = nil;
NSDictionary *deeplinkContextData = [FBSDKInternalUtility objectForJSONString:deeplinkContextString error:&error];
if (!error && [deeplinkContextData isKindOfClass:[NSDictionary class]]) {
return deeplinkContextData[@"promo_code"];
}
}
}
return nil;
}
@end

View File

@ -39,6 +39,7 @@
#import "FBSDKBridgeAPIResponse.h"
#import "FBSDKContainerViewController.h"
#import "FBSDKProfile+Internal.h"
#import "FBSDKOrganicDeeplinkHelper.h"
#endif
NSString *const FBSDKApplicationDidBecomeActiveNotification = @"com.facebook.sdk.FBSDKApplicationDidBecomeActiveNotification";
@ -51,6 +52,7 @@ static NSString *const FBSDKAppLinkInboundEvent = @"fb_al_inbound";
FBSDKBridgeAPIRequest *_pendingRequest;
FBSDKBridgeAPICallbackBlock _pendingRequestCompletionBlock;
id<FBSDKURLOpening> _pendingURLOpen;
FBSDKDeferredAppInviteHandler _organicDeeplinkHandler;
#endif
BOOL _expectingBackground;
UIViewController *_safariViewController;
@ -82,6 +84,8 @@ static NSString *const FBSDKAppLinkInboundEvent = @"fb_al_inbound";
// Register on UIApplicationDidEnterBackgroundNotification events to reset source application data when app backgrounds.
[FBSDKTimeSpentData registerAutoResetSourceApplication];
[FBSDKInternalUtility validateFacebookReservedURLSchemes];
// Remove the observer
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
@ -131,7 +135,34 @@ static NSString *const FBSDKAppLinkInboundEvent = @"fb_al_inbound";
userInfo:nil];
}
[FBSDKTimeSpentData setSourceApplication:sourceApplication openURL:url];
#if !TARGET_OS_TV
if (_organicDeeplinkHandler) {
NSDictionary *params = [FBSDKUtility dictionaryWithQueryString:url.query];
if([params[@"fbsdk_deeplink"] isEqualToString: @"1"]) {
NSURL *sanitizedUrl = nil;
if(![params[@"fbsdk_deeplink_exception"] isEqualToString:@"1"]) {
NSMutableDictionary *sanitizedParams = [NSMutableDictionary dictionaryWithDictionary:params];
[sanitizedParams removeObjectForKey:@"fbsdk_deeplink"];
sanitizedUrl = [FBSDKInternalUtility URLWithScheme:url.scheme
host:url.host
path:url.path
queryParameters:sanitizedParams
error:nil];
}
dispatch_async(dispatch_get_main_queue(), ^{
// Callback handler for organic deeplinking.
_organicDeeplinkHandler(sanitizedUrl);
_organicDeeplinkHandler = nil;
});
return YES;
}
}
// if they completed a SFVC flow, dimiss it.
[_safariViewController.presentingViewController dismissViewControllerAnimated:YES completion: nil];
_safariViewController = nil;

View File

@ -39,7 +39,10 @@
#import <FBSDKCoreKit/FBSDKMutableCopying.h>
#import <FBSDKCoreKit/FBSDKProfile.h>
#import <FBSDKCoreKit/FBSDKProfilePictureView.h>
#else
#import <FBSDKCoreKit/FBSDKDeviceButton.h>
#import <FBSDKCoreKit/FBSDKDeviceViewControllerBase.h>
#endif
#define FBSDK_VERSION_STRING @"4.10.1"
#define FBSDK_TARGET_PLATFORM_VERSION @"v2.5"
#define FBSDK_VERSION_STRING @"4.11.0"
#define FBSDK_TARGET_PLATFORM_VERSION @"v2.6"

View File

@ -123,6 +123,14 @@ FBSDK_EXTERN NSString *const FBSDKProfileChangeNewKey;
*/
+ (void)enableUpdatesOnAccessTokenChange:(BOOL)enable;
/*!
@abstract Loads the current profile and passes it to the completion block.
@param completion The block to be executed once the profile is loaded
@discussion If the profile is already loaded, this method will call the completion block synchronously, otherwise it
will begin a graph request to update `currentProfile` and then call the completion block when finished.
*/
+ (void)loadCurrentProfileWithCompletion:(void(^)(FBSDKProfile *profile, NSError *error))completion;
/*!
@abstract A convenience method for returning a complete `NSURL` for retrieving the user's profile image.
@param mode The picture mode

View File

@ -122,6 +122,11 @@ static FBSDKProfile *g_currentProfile;
}
}
+ (void)loadCurrentProfileWithCompletion:(void (^)(FBSDKProfile *, NSError *))completion
{
[self loadProfileWithToken:[FBSDKAccessToken currentAccessToken] completion:completion];
}
#pragma mark - NSCopying
- (instancetype)copyWithZone:(NSZone *)zone
@ -205,9 +210,8 @@ static FBSDKProfile *g_currentProfile;
#pragma mark - Private
+ (void)observeChangeAccessTokenChange:(NSNotification *)notification
+ (void)loadProfileWithToken:(FBSDKAccessToken *)token completion:(void (^)(FBSDKProfile *, NSError *))completion
{
FBSDKAccessToken *token = notification.userInfo[FBSDKAccessTokenChangeNewKey];
static FBSDKGraphRequestConnection *executingRequestConnection = nil;
BOOL isStale = [[NSDate date] timeIntervalSinceDate:g_currentProfile.refreshDate] > FBSDKPROFILE_STALE_IN_SECONDS;
@ -223,6 +227,9 @@ static FBSDKProfile *g_currentProfile;
executingRequestConnection = [request startWithCompletionHandler:^(FBSDKGraphRequestConnection *connection, id result, NSError *error) {
if (expectedCurrentProfile != g_currentProfile) {
// current profile has already changed since request was started. Let's not overwrite.
if (completion != NULL) {
completion(nil, nil);
}
return;
}
FBSDKProfile *profile = nil;
@ -236,10 +243,21 @@ static FBSDKProfile *g_currentProfile;
refreshDate:[NSDate date]];
}
[[self class] setCurrentProfile:profile];
if (completion != NULL) {
completion(profile, error);
}
}];
} else if (completion != NULL) {
completion(g_currentProfile, nil);
}
}
+ (void)observeChangeAccessTokenChange:(NSNotification *)notification
{
FBSDKAccessToken *token = notification.userInfo[FBSDKAccessTokenChangeNewKey];
[self loadProfileWithToken:token completion:NULL];
}
@end
@implementation FBSDKProfile(Internal)

View File

@ -144,6 +144,7 @@ FBSDK_EXTERN NSString *const FBSDKAppEventNameFBSDKLikeControlImpression;
FBSDK_EXTERN NSString *const FBSDKAppEventNameFBSDKLikeControlNetworkUnavailable;
FBSDK_EXTERN NSString *const FBSDKAppEventParameterDialogErrorMessage;
FBSDK_EXTERN NSString *const FBSDKAppEventParameterLogTime;
@interface FBSDKAppEvents (Internal)

View File

@ -207,30 +207,55 @@
[[NSNotificationCenter defaultCenter] postNotificationName:FBSDKAppEventsLoggingResultNotification object:error];
}
+ (BOOL)matchString:(NSString *)string
firstCharacterSet:(NSCharacterSet *)firstCharacterSet
restOfStringCharacterSet:(NSCharacterSet *)restOfStringCharacterSet
{
if (string.length == 0) {
return NO;
}
for (NSUInteger i = 0; i < string.length; i++) {
const unichar c = [string characterAtIndex:i];
if (i == 0) {
if (![firstCharacterSet characterIsMember:c]) {
return NO;
}
} else {
if (![restOfStringCharacterSet characterIsMember:c]) {
return NO;
}
}
}
return YES;
}
+ (BOOL)regexValidateIdentifier:(NSString *)identifier
{
static NSRegularExpression *regex;
static NSCharacterSet *firstCharacterSet;
static NSCharacterSet *restOfStringCharacterSet;
static dispatch_once_t onceToken;
static NSMutableSet *cachedIdentifiers;
dispatch_once(&onceToken, ^{
NSString *regexString = @"^[0-9a-zA-Z_]+[0-9a-zA-Z _-]*$";
regex = [NSRegularExpression regularExpressionWithPattern:regexString
options:0
error:NULL];
NSMutableCharacterSet *mutableSet = [NSMutableCharacterSet alphanumericCharacterSet];
[mutableSet addCharactersInString:@"_"];
firstCharacterSet = [mutableSet copy];
[mutableSet addCharactersInString:@"- "];
restOfStringCharacterSet = [mutableSet copy];
cachedIdentifiers = [[NSMutableSet alloc] init];
});
@synchronized(self) {
if (![cachedIdentifiers containsObject:identifier]) {
NSUInteger numMatches = [regex numberOfMatchesInString:identifier options:0 range:NSMakeRange(0, identifier.length)];
if (numMatches > 0) {
if ([self matchString:identifier
firstCharacterSet:firstCharacterSet
restOfStringCharacterSet:restOfStringCharacterSet]) {
[cachedIdentifiers addObject:identifier];
} else {
return NO;
}
}
}
return YES;
}

View File

@ -22,6 +22,8 @@
#import "FBSDKAppEventsUtility.h"
#import "FBSDKInternalUtility.h"
#import "FBSDKLogger.h"
#import "FBSDKServerConfiguration.h"
#import "FBSDKServerConfigurationManager.h"
#import "FBSDKSettings.h"
@ -30,13 +32,15 @@ NSString *const FBSDKTimeSpentFilename
static NSString *const FBSDKTimeSpentPersistKeySessionSecondsSpent = @"secondsSpentInCurrentSession";
static NSString *const FBSDKTimeSpentPersistKeySessionNumInterruptions = @"numInterruptions";
static NSString *const FBSDKTimeSpentPersistKeyLastSuspendTime = @"lastSuspendTime";
static NSString *const FBSDKTimeSpentPersistKeySessionID = @"sessionID";
static NSString *const FBSDKAppEventNameActivatedApp = @"fb_mobile_activate_app";
static NSString *const FBSDKAppEventNameDeactivatedApp = @"fb_mobile_deactivate_app";
static NSString *const FBSDKAppEventParameterNameSessionInterruptions = @"fb_mobile_app_interruptions";
static NSString *const FBSDKAppEventParameterNameTimeBetweenSessions = @"fb_mobile_time_between_sessions";
static NSString *const FBSDKAppEventParameterNameSessionID = @"_session_id";
static const int NUM_SECONDS_IDLE_TO_BE_NEW_SESSION = 60;
static const int SECS_PER_MIN = 60;
static const int SECS_PER_HOUR = 60 * SECS_PER_MIN;
static const int SECS_PER_DAY = 24 * SECS_PER_HOUR;
@ -79,12 +83,6 @@ static const long INACTIVE_SECONDS_QUANTA[] =
* with the duration of the previous session as the 'value' of this event, along with the number of
* interruptions from that previous session as an event parameter.
*/
@interface FBSDKTimeSpentData()
@property (nonatomic) NSInteger numSecondsIdleToBeNewSession;
@end
@implementation FBSDKTimeSpentData
{
BOOL _isCurrentlyLoaded;
@ -94,6 +92,8 @@ static const long INACTIVE_SECONDS_QUANTA[] =
long _timeSinceLastSuspend;
int _numInterruptionsInCurrentSession;
long _lastRestoreTime;
long _lastSuspendTime;
NSString *_sessionID;
}
//
@ -113,15 +113,6 @@ static const long INACTIVE_SECONDS_QUANTA[] =
//
// Internal methods
//
- (instancetype)init
{
if ((self = [super init])) {
_numSecondsIdleToBeNewSession = NUM_SECONDS_IDLE_TO_BE_NEW_SESSION;
}
return self;
}
+ (FBSDKTimeSpentData *)singleton
{
static dispatch_once_t pred;
@ -159,7 +150,8 @@ static const long INACTIVE_SECONDS_QUANTA[] =
@{
FBSDKTimeSpentPersistKeySessionSecondsSpent : @(_secondsSpentInCurrentSession),
FBSDKTimeSpentPersistKeySessionNumInterruptions : @(_numInterruptionsInCurrentSession),
FBSDKTimeSpentPersistKeyLastSuspendTime : @(now)
FBSDKTimeSpentPersistKeyLastSuspendTime : @(now),
FBSDKTimeSpentPersistKeySessionID : _sessionID,
};
NSString *content = [FBSDKInternalUtility JSONStringForObject:timeSpentData error:NULL invalidObjectHandler:NULL];
@ -200,8 +192,10 @@ static const long INACTIVE_SECONDS_QUANTA[] =
if (!content) {
// Nothing persisted, so this is the first launch.
_sessionID = [[NSUUID UUID] UUIDString];
_secondsSpentInCurrentSession = 0;
_numInterruptionsInCurrentSession = 0;
_lastSuspendTime = 0;
// We want to log the app activation event on the first launch, but not the deactivate event
_shouldLogActivateEvent = YES;
@ -211,12 +205,13 @@ static const long INACTIVE_SECONDS_QUANTA[] =
NSDictionary *results = [FBSDKInternalUtility objectForJSONString:content error:NULL];
long lastActiveTime = [[results objectForKey:FBSDKTimeSpentPersistKeyLastSuspendTime] longValue];
_lastSuspendTime = [[results objectForKey:FBSDKTimeSpentPersistKeyLastSuspendTime] longValue];
_timeSinceLastSuspend = now - lastActiveTime;
_timeSinceLastSuspend = now - _lastSuspendTime;
_secondsSpentInCurrentSession = [[results objectForKey:FBSDKTimeSpentPersistKeySessionSecondsSpent] intValue];
_sessionID = results[FBSDKTimeSpentPersistKeySessionID];
_numInterruptionsInCurrentSession = [[results objectForKey:FBSDKTimeSpentPersistKeySessionNumInterruptions] intValue];
_shouldLogActivateEvent = (_timeSinceLastSuspend > _numSecondsIdleToBeNewSession);
_shouldLogActivateEvent = (_timeSinceLastSuspend > [FBSDKServerConfigurationManager cachedServerConfiguration].sessionTimoutInterval);
// Other than the first launch, we always log the last session's deactivate with this session's activate.
_shouldLogDeactivateEvent = _shouldLogActivateEvent;
@ -233,38 +228,52 @@ static const long INACTIVE_SECONDS_QUANTA[] =
_isCurrentlyLoaded = YES;
if (calledFromActivateApp) {
if (_shouldLogActivateEvent) {
[FBSDKAppEvents logEvent:FBSDKAppEventNameActivatedApp
parameters:@{
FBSDKAppEventParameterLaunchSource: [[self class] getSourceApplication]
}];
}
// It's important to log deactivate first to reset sessionID
if (_shouldLogDeactivateEvent) {
int quantaIndex = 0;
while (_timeSinceLastSuspend > INACTIVE_SECONDS_QUANTA[quantaIndex]) {
quantaIndex++;
}
[FBSDKAppEvents logEvent:FBSDKAppEventNameDeactivatedApp
valueToSum:_secondsSpentInCurrentSession
parameters:
@{ FBSDKAppEventParameterNameSessionInterruptions : @(_numInterruptionsInCurrentSession),
FBSDKAppEventParameterNameTimeBetweenSessions : [NSString stringWithFormat:@"session_quanta_%d", quantaIndex],
FBSDKAppEventParameterLaunchSource: [[self class] getSourceApplication],
}
];
parameters:[self appEventsParametersForDeactivate]];
// We've logged the session stats, now reset.
_secondsSpentInCurrentSession = 0;
_numInterruptionsInCurrentSession = 0;
_sessionID = [[NSUUID UUID] UUIDString];
}
if (_shouldLogActivateEvent) {
[FBSDKAppEvents logEvent:FBSDKAppEventNameActivatedApp
parameters:[self appEventsParametersForActivate]];
}
}
}
}
- (NSDictionary *)appEventsParametersForActivate
{
return @{
FBSDKAppEventParameterLaunchSource: [[self class] getSourceApplication],
FBSDKAppEventParameterNameSessionID: _sessionID,
};
}
- (NSDictionary *)appEventsParametersForDeactivate
{
int quantaIndex = 0;
while (_timeSinceLastSuspend > INACTIVE_SECONDS_QUANTA[quantaIndex]) {
quantaIndex++;
}
NSMutableDictionary *params = [@{ FBSDKAppEventParameterNameSessionInterruptions : @(_numInterruptionsInCurrentSession),
FBSDKAppEventParameterNameTimeBetweenSessions : [NSString stringWithFormat:@"session_quanta_%d", quantaIndex],
FBSDKAppEventParameterLaunchSource: [[self class] getSourceApplication],
FBSDKAppEventParameterNameSessionID : _sessionID ?: @"",
} mutableCopy];
if (_lastSuspendTime) {
params[FBSDKAppEventParameterLogTime] = @(_lastSuspendTime);
}
return [params copy];
}
+ (void)setSourceApplication:(NSString *)sourceApplication openURL:(NSURL *)url
{
[self setSourceApplication:sourceApplication

View File

@ -0,0 +1,25 @@
// Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
//
// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,
// copy, modify, and distribute this software in source code or binary form for use
// in connection with the web services and APIs provided by Facebook.
//
// As with any software that integrates with the Facebook platform, your use of
// this software is subject to the Facebook Developer Principles and Policies
// [http://developers.facebook.com/policy/]. This copyright notice shall be
// included in all copies or substantial portions of the software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#import <Foundation/Foundation.h>
#import <FBSDKCoreKit/FBSDKAppLinkUtility.h>
@interface FBSDKOrganicDeeplinkHelper: NSObject
- (bool)fetchOrganicDeeplink:(FBSDKDeferredAppInviteHandler)handler;
@end

View File

@ -0,0 +1,151 @@
// Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
//
// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,
// copy, modify, and distribute this software in source code or binary form for use
// in connection with the web services and APIs provided by Facebook.
//
// As with any software that integrates with the Facebook platform, your use of
// this software is subject to the Facebook Developer Principles and Policies
// [http://developers.facebook.com/policy/]. This copyright notice shall be
// included in all copies or substantial portions of the software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#import "FBSDKOrganicDeeplinkHelper.h"
#import <Foundation/Foundation.h>
#import <SafariServices/SafariServices.h>
#import <UIKit/UIKit.h>
#import "FBSDKApplicationDelegate+Internal.h"
#import "FBSDKDynamicFrameworkLoader.h"
#import "FBSDKInternalUtility.h"
#import "FBSDKSettings.h"
@interface FBSDKOrganicDeeplinkHelper () <
SFSafariViewControllerDelegate
>
@end
@implementation FBSDKOrganicDeeplinkHelper {
UIWindow *_safariWindow;
UIViewController *_safariViewController;
FBSDKDeferredAppInviteHandler _handler;
}
- (bool)fetchOrganicDeeplink:(FBSDKDeferredAppInviteHandler) handler
{
_handler = handler;
// trying to dynamically load SFSafariViewController class
// so for the cases when it is available we can send users through Safari View Controller flow
// in cases it is not available regular flow will be selected
Class SFSafariViewControllerClass = fbsdkdfl_SFSafariViewControllerClass();
if(!SFSafariViewControllerClass) {
return NO;
}
_safariWindow = [[UIWindow alloc] initWithFrame:[[[[UIApplication sharedApplication] delegate] window] bounds]];
_safariWindow.windowLevel = UIWindowLevelNormal - 1;
_safariWindow.rootViewController = [[UIViewController alloc] init];;
[_safariWindow setHidden:NO];
_safariViewController = [[SFSafariViewControllerClass alloc] initWithURL: [self constructDeeplinkRetrievalUrl]];
dispatch_async(dispatch_get_main_queue(), ^{
[FBSDKApplicationDelegate sharedInstance].organicDeeplinkHandler = handler;
[self presentSafariViewController];
// Dispatch a fallback handler call, if we get no response within 10 seconds.
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(10.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
if([FBSDKApplicationDelegate sharedInstance].organicDeeplinkHandler)
{
[self cleanUpSafariViewController];
[FBSDKApplicationDelegate sharedInstance].organicDeeplinkHandler = nil;
_handler(nil);
}
});
});
return YES;
}
- (void)presentSafariViewController
{
_safariViewController.view.userInteractionEnabled = NO;
_safariViewController.view.alpha = 0;
[_safariWindow.rootViewController addChildViewController:_safariViewController];
[_safariWindow.rootViewController.view addSubview:_safariViewController.view];
[_safariViewController performSelector:@selector(setDelegate:) withObject:self];
[_safariViewController didMoveToParentViewController:_safariWindow.rootViewController];
_safariViewController.view.frame = CGRectZero;
return;
}
- (void)cleanUpSafariViewController
{
if(_safariViewController)
{
[_safariViewController performSelector:@selector(setDelegate:) withObject:nil];
[_safariViewController willMoveToParentViewController:nil];
[_safariViewController.view removeFromSuperview];
[_safariViewController removeFromParentViewController];
_safariViewController = nil;
_safariWindow.rootViewController = nil;
_safariWindow = nil;
}
return;
}
- (NSURL*)constructDeeplinkRetrievalUrl
{
NSString *appID = [FBSDKSettings appID];
UIDevice* device = [UIDevice currentDevice];
NSString* deviceName = @"default";
switch (device.userInterfaceIdiom) {
case UIUserInterfaceIdiomPad:
deviceName = @"ipad";
break;
case UIUserInterfaceIdiomPhone:
deviceName = @"iphone";
break;
case UIUserInterfaceIdiomTV:
deviceName = @"tvos";
break;
#if __IPHONE_9_3
case UIUserInterfaceIdiomCarPlay:
#endif
case UIUserInterfaceIdiomUnspecified:
deviceName = @"unspecified";
break;
}
NSMutableDictionary *parameters = [[NSMutableDictionary alloc] init];
parameters[@"application_id"] = appID;
parameters[@"device"] = deviceName;
return [FBSDKInternalUtility facebookURLWithHostPrefix:@"m"
path:@"/deferreddeeplink/retrieve/"
queryParameters:parameters
defaultVersion: @""
error:nil];
}
#pragma mark - SFSafariViewControllerDelegate
- (void)safariViewController:(SFSafariViewController *)controller didCompleteInitialLoad:(BOOL)didLoadSuccessfully
{
// Mark request as complete, Safari would redirect to url with correct deeplink or default uri.
[self cleanUpSafariViewController];
}
@end

View File

@ -46,6 +46,8 @@ typedef void(^FBSDKBridgeAPICallbackBlock)(FBSDKBridgeAPIResponse *response);
handler:(void(^)(BOOL))handler;
- (void)openURL:(NSURL *)url sender:(id<FBSDKURLOpening>)sender handler:(void(^)(BOOL))handler;
@property (nonatomic, copy) FBSDKDeferredAppInviteHandler organicDeeplinkHandler;
#endif
@property (nonatomic, readonly, getter=isActive) BOOL active;

View File

@ -38,6 +38,11 @@
#import "UI/FBSDKUIUtility.h"
#import "UI/FBSDKViewImpressionTracker.h"
#import "WebDialog/FBSDKWebDialog.h"
#else
#import "Device/FBSDKDeviceButton+Internal.h"
#import "Device/FBSDKDeviceDialogView.h"
#import "Device/FBSDKDeviceViewControllerBase+Internal.h"
#import "Device/FBSDKModalFormPresentationController.h"
#endif
#import "AppEvents/FBSDKAppEvents+Internal.h"

View File

@ -20,7 +20,9 @@
#import <UIKit/UIKit.h>
#define FBSDK_CANOPENURL_FACEBOOK @"fbauth2"
#define FBSDK_CANOPENURL_FBAPI @"fbapi"
#define FBSDK_CANOPENURL_MESSENGER @"fb-messenger-api"
#define FBSDK_CANOPENURL_SHARE_EXTENSION @"fbshareextension"
typedef NS_ENUM(int32_t, FBSDKUIKitVersion)
{
@ -281,11 +283,22 @@ setJSONStringForObject:(id)object
*/
+ (void)validateAppID;
/**
Validates that the client access token is non-nil, otherwise - throws an NSException otherwise.
Returns the composed client access token.
*/
+ (NSString *)validateRequiredClientAccessToken;
/*!
@abstract validates that the right URL schemes are registered, throws an NSException if not.
*/
+ (void)validateURLSchemes;
/*!
@abstract validates that Facebook reserved URL schemes are not registered, throws an NSException if they are.
*/
+ (void)validateFacebookReservedURLSchemes;
/*!
@abstract Attempts to find the first UIViewController in the view's responder chain. Returns nil if not found.
*/
@ -301,6 +314,11 @@ setJSONStringForObject:(id)object
*/
+ (UIViewController *)topMostViewController;
/*!
@abstract Converts NSData to a hexadecimal UTF8 String.
*/
+ (NSString *)hexadecimalStringFromData:(NSData *)data;
/*
@abstract Checks if the permission is a publish permission.
*/
@ -333,4 +351,5 @@ setJSONStringForObject:(id)object
#define FB_BASE_URL @"facebook.com"
+ (Class)resolveBoltsClassWithName:(NSString *)className;
@end

View File

@ -587,6 +587,16 @@ static NSMapTable *_transientObjects;
}
}
+ (NSString *)validateRequiredClientAccessToken {
if (![FBSDKSettings clientToken]) {
NSString *reason = @"ClientToken is required to be set for this operation. "
@"Set the FacebookClientToken in the Info.plist or call [FBSDKSettings setClientToken:]. "
@"You can find your client token in your App Settings -> Advanced.";
@throw [NSException exceptionWithName:@"InvalidOperationException" reason:reason userInfo:nil];
}
return [NSString stringWithFormat:@"%@|%@", [FBSDKSettings appID], [FBSDKSettings clientToken]];
}
+ (void)validateURLSchemes
{
[self validateAppID];
@ -597,6 +607,16 @@ static NSMapTable *_transientObjects;
}
}
+ (void)validateFacebookReservedURLSchemes
{
for (NSString * fbUrlScheme in @[FBSDK_CANOPENURL_FACEBOOK, FBSDK_CANOPENURL_MESSENGER, FBSDK_CANOPENURL_FBAPI, FBSDK_CANOPENURL_SHARE_EXTENSION]) {
if ([self isRegisteredURLScheme:fbUrlScheme]) {
NSString *reason = [NSString stringWithFormat:@"%@ is registered as a URL scheme. Please move the entry from CFBundleURLSchemes in your Info.plist to LSApplicationQueriesSchemes. If you are trying to resolve \"canOpenURL: failed\" warnings, those only indicate that the Facebook app is not installed on your device or simulator and can be ignored.", fbUrlScheme];
@throw [NSException exceptionWithName:@"InvalidOperationException" reason:reason userInfo:nil];
}
}
}
+ (UIViewController *)topMostViewController
{
@ -607,6 +627,20 @@ static NSMapTable *_transientObjects;
return topController;
}
+ (NSString *)hexadecimalStringFromData:(NSData *)data
{
NSUInteger dataLength = data.length;
if (dataLength == 0) {
return nil;
}
const unsigned char *dataBuffer = data.bytes;
NSMutableString *hexString = [NSMutableString stringWithCapacity:(dataLength * 2)];
for (int i = 0; i < dataLength; ++i) {
[hexString appendFormat:@"%02x", dataBuffer[i]];
}
return [hexString copy];
}
+ (BOOL)isRegisteredURLScheme:(NSString *)urlScheme {
static dispatch_once_t fetchBundleOnce;
@ -692,4 +726,17 @@ static NSMapTable *_transientObjects;
return YES;
}
+ (Class)resolveBoltsClassWithName:(NSString *)className;
{
Class clazz = NSClassFromString(className);
if (clazz == nil) {
NSString *message = [NSString stringWithFormat:@"Unable to load class %@. Did you link Bolts.framework?", className];
@throw [NSException exceptionWithName:NSInternalInconsistencyException
reason:message
userInfo:nil];
}
return clazz;
}
@end

View File

@ -26,6 +26,7 @@
+ (NSInteger)integerValue:(id)object;
+ (id)objectValue:(id)object;
+ (NSString *)stringValue:(id)object;
+ (NSTimeInterval)timeIntervalValue:(id)object;
+ (NSUInteger)unsignedIntegerValue:(id)object;
+ (NSURL *)URLValue:(id)object;

View File

@ -76,6 +76,17 @@
}
}
+ (NSTimeInterval)timeIntervalValue:(id)object
{
if ([object isKindOfClass:[NSNumber class]]) {
return [(NSNumber *)object doubleValue];
} else if ([object isKindOfClass:[NSString class]]) {
return [(NSString *)object doubleValue];
} else {
return 0;
}
}
+ (NSUInteger)unsignedIntegerValue:(id)object
{
if ([object isKindOfClass:[NSNumber class]]) {

View File

@ -18,8 +18,7 @@
#import "FBSDKErrorConfiguration.h"
#import <FBSDKCoreKit/FBSDKCoreKit+Internal.h>
#import "FBSDKCoreKit+Internal.h"
#import "FBSDKErrorRecoveryConfiguration.h"
static NSString *const kErrorCategoryOther = @"other";

View File

@ -50,6 +50,7 @@ implicitPurchaseLoggingEnabled:(BOOL)implicitPurchaseLoggingEnabled
dialogFlows:(NSDictionary *)dialogFlows
timestamp:(NSDate *)timestamp
errorConfiguration:(FBSDKErrorConfiguration *)errorConfiguration
sessionTimeoutInterval:(NSTimeInterval) sessionTimeoutInterval
defaults:(BOOL)defaults
NS_DESIGNATED_INITIALIZER;
@ -66,6 +67,7 @@ NS_DESIGNATED_INITIALIZER;
@property (nonatomic, assign, readonly, getter=isSystemAuthenticationEnabled) BOOL systemAuthenticationEnabled;
@property (nonatomic, copy, readonly) NSString *loginTooltipText;
@property (nonatomic, copy, readonly) NSDate *timestamp;
@property (nonatomic, assign) NSTimeInterval sessionTimoutInterval;
- (FBSDKDialogConfiguration *)dialogConfigurationForDialogName:(NSString *)dialogName;
- (BOOL)useNativeDialogForDialogName:(NSString *)dialogName;

View File

@ -36,6 +36,7 @@
#define FBSDK_SERVER_CONFIGURATION_SYSTEM_AUTHENTICATION_ENABLED_KEY @"systemAuthenticationEnabled"
#define FBSDK_SERVER_CONFIGURATION_NATIVE_AUTH_FLOW_ENABLED_KEY @"nativeAuthFlowEnabled"
#define FBSDK_SERVER_CONFIGURATION_TIMESTAMP_KEY @"timestamp"
#define FBSDK_SERVER_CONFIGURATION_SESSION_TIMEOUT_INTERVAL @"sessionTimeoutInterval"
#pragma mark - Dialog Names
@ -82,6 +83,7 @@ implicitPurchaseLoggingEnabled:(BOOL)implicitPurchaseLoggingEnabled
dialogFlows:(NSDictionary *)dialogFlows
timestamp:(NSDate *)timestamp
errorConfiguration:(FBSDKErrorConfiguration *)errorConfiguration
sessionTimeoutInterval:(NSTimeInterval) sessionTimeoutInterval
defaults:(BOOL)defaults
{
if ((self = [super init])) {
@ -99,6 +101,7 @@ implicitPurchaseLoggingEnabled:(BOOL)implicitPurchaseLoggingEnabled
_dialogFlows = [dialogFlows copy];
_timestamp = [timestamp copy];
_errorConfiguration = [errorConfiguration copy];
_sessionTimoutInterval = sessionTimeoutInterval;
_defaults = defaults;
}
return self;
@ -173,6 +176,7 @@ implicitPurchaseLoggingEnabled:(BOOL)implicitPurchaseLoggingEnabled
NSDictionary *dialogFlows = [decoder decodeObjectOfClasses:dialogFlowsClasses
forKey:FBSDK_SERVER_CONFIGURATION_DIALOG_FLOWS_KEY];
FBSDKErrorConfiguration *errorConfiguration = [decoder decodeObjectOfClass:[FBSDKErrorConfiguration class] forKey:FBSDK_SERVER_CONFIGURATION_ERROR_CONFIGS_KEY];
NSTimeInterval sessionTimeoutInterval = [decoder decodeDoubleForKey:FBSDK_SERVER_CONFIGURATION_SESSION_TIMEOUT_INTERVAL];
return [self initWithAppID:appID
appName:appName
loginTooltipEnabled:loginTooltipEnabled
@ -187,6 +191,7 @@ implicitPurchaseLoggingEnabled:implicitPurchaseLoggingEnabbled
dialogFlows:dialogFlows
timestamp:timestamp
errorConfiguration:errorConfiguration
sessionTimeoutInterval:sessionTimeoutInterval
defaults:NO];
}
@ -207,6 +212,7 @@ implicitPurchaseLoggingEnabled:implicitPurchaseLoggingEnabbled
[encoder encodeBool:_nativeAuthFlowEnabled forKey:FBSDK_SERVER_CONFIGURATION_NATIVE_AUTH_FLOW_ENABLED_KEY];
[encoder encodeBool:_systemAuthenticationEnabled forKey:FBSDK_SERVER_CONFIGURATION_SYSTEM_AUTHENTICATION_ENABLED_KEY];
[encoder encodeObject:_timestamp forKey:FBSDK_SERVER_CONFIGURATION_TIMESTAMP_KEY];
[encoder encodeDouble:_sessionTimoutInterval forKey:FBSDK_SERVER_CONFIGURATION_SESSION_TIMEOUT_INTERVAL];
}
#pragma mark - NSCopying

View File

@ -28,4 +28,6 @@
+ (FBSDKGraphRequest *)requestToLoadServerConfiguration:(NSString *)appID;
+ (void)clearCache;
@end

View File

@ -28,6 +28,7 @@
#import "FBSDKTypeUtility.h"
// one hour
#define DEFAULT_SESSION_TIMEOUT_INTERVAL 60
#define FBSDK_SERVER_CONFIGURATION_MANAGER_CACHE_TIMEOUT (60 * 60)
#define FBSDK_SERVER_CONFIGURATION_USER_DEFAULTS_KEY @"com.facebook.sdk:serverConfiguration%@"
@ -43,6 +44,7 @@
#define FBSDK_SERVER_CONFIGURATION_LOGIN_TOOLTIP_TEXT_FIELD @"gdpv4_nux_content"
#define FBSDK_SERVER_CONFIGURATION_NATIVE_PROXY_AUTH_FLOW_ENABLED_FIELD @"ios_supports_native_proxy_auth_flow"
#define FBSDK_SERVER_CONFIGURATION_SYSTEM_AUTHENTICATION_ENABLED_FIELD @"ios_supports_system_auth"
#define FBSDK_SERVER_CONFIGURATION_SESSION_TIMEOUT_FIELD @"app_events_session_timeout"
@implementation FBSDKServerConfigurationManager
@ -69,6 +71,17 @@ typedef NS_OPTIONS(NSUInteger, FBSDKServerConfigurationManagerAppEventsFeatures)
}
}
+ (void)clearCache
{
_serverConfiguration = nil;
_serverConfigurationError = nil;
_serverConfigurationErrorTimestamp = nil;
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSString *defaultsKey = [NSString stringWithFormat:FBSDK_SERVER_CONFIGURATION_USER_DEFAULTS_KEY, [FBSDKSettings appID]];
[defaults removeObjectForKey:defaultsKey];
[defaults synchronize];
}
+ (FBSDKServerConfiguration *)cachedServerConfiguration
{
NSString *appID = [FBSDKSettings appID];
@ -167,6 +180,7 @@ typedef NS_OPTIONS(NSUInteger, FBSDKServerConfigurationManagerAppEventsFeatures)
NSDictionary *dialogFlows = [FBSDKTypeUtility dictionaryValue:resultDictionary[FBSDK_SERVER_CONFIGURATION_DIALOG_FLOWS_FIELD]];
FBSDKErrorConfiguration *errorConfiguration = [[FBSDKErrorConfiguration alloc] initWithDictionary:nil];
[errorConfiguration parseArray:resultDictionary[FBSDK_SERVER_CONFIGURATION_ERROR_CONFIGURATION_FIELD]];
NSTimeInterval sessionTimeoutInterval = [FBSDKTypeUtility timeIntervalValue:resultDictionary[FBSDK_SERVER_CONFIGURATION_SESSION_TIMEOUT_FIELD]] ?: DEFAULT_SESSION_TIMEOUT_INTERVAL;
FBSDKServerConfiguration *serverConfiguration = [[FBSDKServerConfiguration alloc] initWithAppID:appID
appName:appName
loginTooltipEnabled:loginTooltipEnabled
@ -181,6 +195,7 @@ typedef NS_OPTIONS(NSUInteger, FBSDKServerConfigurationManagerAppEventsFeatures)
dialogFlows:dialogFlows
timestamp:[NSDate date]
errorConfiguration:errorConfiguration
sessionTimeoutInterval:sessionTimeoutInterval
defaults:NO];
[self _didProcessConfigurationFromNetwork:serverConfiguration appID:appID error:nil];
}
@ -204,6 +219,7 @@ typedef NS_OPTIONS(NSUInteger, FBSDKServerConfigurationManagerAppEventsFeatures)
FBSDK_SERVER_CONFIGURATION_LOGIN_TOOLTIP_TEXT_FIELD,
FBSDK_SERVER_CONFIGURATION_NATIVE_PROXY_AUTH_FLOW_ENABLED_FIELD,
FBSDK_SERVER_CONFIGURATION_SYSTEM_AUTHENTICATION_ENABLED_FIELD,
FBSDK_SERVER_CONFIGURATION_SESSION_TIMEOUT_FIELD,
];
NSDictionary *parameters = @{ @"fields": [fields componentsJoinedByString:@","] };
FBSDKGraphRequest *request = [[FBSDKGraphRequest alloc] initWithGraphPath:appID
@ -251,6 +267,7 @@ typedef NS_OPTIONS(NSUInteger, FBSDKServerConfigurationManagerAppEventsFeatures)
dialogFlows:dialogFlows
timestamp:nil
errorConfiguration:nil
sessionTimeoutInterval:DEFAULT_SESSION_TIMEOUT_INTERVAL
defaults:YES];
}
return _defaultServerConfiguration;

View File

@ -44,6 +44,22 @@
*/
@property (nonatomic, copy) NSURL *previewImageURL __attribute__ ((deprecated("use appInvitePreviewImageURL instead")));
/*!
@abstract Promotional code to be displayed while sending and receiving the invite.
@discussion This is optional. This can be between 0 and 10 characters long and can contain
alphanumeric characters only. To set a promo code, you need to set promo text.
*/
@property (nonatomic, copy) NSString *promotionCode;
/*!
@abstract Promotional text to be displayed while sending and receiving the invite.
@discussion This is optional. This can be between 0 and 80 characters long and can contain
alphanumeric and spaces only.
*/
@property (nonatomic, copy) NSString *promotionText;
/*!
@abstract Compares the receiver to another app invite content.
@param content The other content

View File

@ -22,6 +22,9 @@
#define FBSDK_APP_INVITE_CONTENT_APP_LINK_URL_KEY @"appLinkURL"
#define FBSDK_APP_INVITE_CONTENT_PREVIEW_IMAGE_KEY @"previewImage"
#define FBSDK_APP_INVITE_CONTENT_PROMO_CODE_KEY @"promoCode"
#define FBSDK_APP_INVITE_CONTENT_PROMO_TEXT_KEY @"promoText"
@implementation FBSDKAppInviteContent
@ -42,6 +45,8 @@
NSUInteger subhashes[] = {
[_appLinkURL hash],
[_appInvitePreviewImageURL hash],
[_promotionCode hash],
[_promotionText hash],
};
return [FBSDKMath hashWithIntegerArray:subhashes count:sizeof(subhashes) / sizeof(subhashes[0])];
}
@ -61,7 +66,10 @@
{
return (content &&
[FBSDKInternalUtility object:_appLinkURL isEqualToObject:content.appLinkURL] &&
[FBSDKInternalUtility object:_appInvitePreviewImageURL isEqualToObject:content.appInvitePreviewImageURL]);
[FBSDKInternalUtility object:_appInvitePreviewImageURL isEqualToObject:content.appInvitePreviewImageURL] &&
[FBSDKInternalUtility object:_promotionText isEqualToObject:content.promotionText] &&
[FBSDKInternalUtility object:_promotionCode isEqualToObject:content.promotionText]
);
}
#pragma mark - NSCoding
@ -76,6 +84,11 @@
if ((self = [self init])) {
_appLinkURL = [decoder decodeObjectOfClass:[NSURL class] forKey:FBSDK_APP_INVITE_CONTENT_APP_LINK_URL_KEY];
_appInvitePreviewImageURL = [decoder decodeObjectOfClass:[NSURL class] forKey:FBSDK_APP_INVITE_CONTENT_PREVIEW_IMAGE_KEY];
_promotionCode = [decoder decodeObjectOfClass:[NSString class] forKey:
FBSDK_APP_INVITE_CONTENT_PROMO_CODE_KEY];
_promotionText = [decoder decodeObjectOfClass:[NSString class] forKey:
FBSDK_APP_INVITE_CONTENT_PROMO_TEXT_KEY];
}
return self;
}
@ -84,6 +97,9 @@
{
[encoder encodeObject:_appLinkURL forKey:FBSDK_APP_INVITE_CONTENT_APP_LINK_URL_KEY];
[encoder encodeObject:_appInvitePreviewImageURL forKey:FBSDK_APP_INVITE_CONTENT_PREVIEW_IMAGE_KEY];
[encoder encodeObject:_promotionCode forKey:FBSDK_APP_INVITE_CONTENT_PROMO_CODE_KEY];
[encoder encodeObject:_promotionText forKey:FBSDK_APP_INVITE_CONTENT_PROMO_TEXT_KEY];
}
#pragma mark - NSCopying
@ -93,6 +109,8 @@
FBSDKAppInviteContent *copy = [[FBSDKAppInviteContent alloc] init];
copy->_appLinkURL = [_appLinkURL copy];
copy->_appInvitePreviewImageURL = [_appInvitePreviewImageURL copy];
copy->_promotionText = [_promotionText copy];
copy->_promotionCode = [_promotionCode copy];
return copy;
}

View File

@ -82,6 +82,23 @@
NSMutableDictionary *parameters = [[NSMutableDictionary alloc] init];
[FBSDKInternalUtility dictionary:parameters setObject:self.content.appLinkURL forKey:@"app_link_url"];
[FBSDKInternalUtility dictionary:parameters setObject:self.content.appInvitePreviewImageURL forKey:@"preview_image_url"];
if (self.content.promotionText) {
NSString *promotionCode = self.content.promotionCode ?: @"";
NSDictionary *deeplinkContext = @{@"promo_code" : promotionCode, @"promo_text" : self.content.promotionText};
NSError *jsonError = nil;
NSString *deeplinkContextString = [FBSDKInternalUtility JSONStringForObject:deeplinkContext error:&jsonError invalidObjectHandler:NULL];
if (!jsonError) {
[FBSDKInternalUtility dictionary:parameters setObject:promotionCode forKey:@"promo_code"];
[FBSDKInternalUtility dictionary:parameters setObject:self.content.promotionText forKey:@"promo_text"];
[FBSDKInternalUtility dictionary:parameters setObject:deeplinkContextString forKey:@"deeplink_context"];
} else {
[FBSDKLogger singleShotLogEntry:FBSDKLoggingBehaviorDeveloperErrors
formatString:@"Cannot convert deeplink_contex to json:"];
}
}
FBSDKBridgeAPIRequest *webBridgeRequest = [FBSDKBridgeAPIRequest bridgeAPIRequestWithProtocolType:FBSDKBridgeAPIProtocolTypeWeb
scheme:FBSDK_SHARE_JS_DIALOG_SCHEME
methodName:FBSDK_APP_INVITE_METHOD_NAME

View File

@ -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 <Foundation/Foundation.h>
#import <FBSDKCoreKit/FBSDKCopying.h>
/*!
@abstract Represents a single hashtag that can be used with the share dialog.
*/
@interface FBSDKHashtag : NSObject <FBSDKCopying, NSSecureCoding>
/*!
@abstract Convenience method to build a new hashtag with a string identifier. Equivalent to setting the
`stringRepresentation` property.
@param hashtagString The hashtag string.
*/
+ (instancetype)hashtagWithString:(NSString *)hashtagString;
/*!
@abstract The hashtag string.
@discussion You are responsible for making sure that `stringRepresentation` is a valid hashtag (a single '#' followed
by one or more word characters). Invalid hashtags are ignored when sharing content. You can check validity with the
`valid` property.
@return The hashtag string.
*/
@property (nonatomic, readwrite, copy) NSString *stringRepresentation;
/*!
@abstract Tests if a hashtag is valid.
@discussion A valid hashtag matches the regular expression "#\w+": A single '#' followed by one or more
word characters.
@return YES if the hashtag is valid, NO otherwise.
*/
@property (nonatomic, readonly, assign, getter=isValid) BOOL valid;
/*!
@abstract Compares the receiver to another hashtag.
@param hashtag The other hashtag
@return YES if the receiver is equal to the other hashtag; otherwise NO
*/
- (BOOL)isEqualToHashtag:(FBSDKHashtag *)hashtag;
@end

View File

@ -0,0 +1,123 @@
// 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 "FBSDKHashtag.h"
#import "FBSDKCoreKit+Internal.h"
#define FBSDK_HASHTAG_STRING_KEY @"hashtag"
static NSRegularExpression *HashtagRegularExpression()
{
static NSRegularExpression *hashtagRegularExpression = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
hashtagRegularExpression = [[NSRegularExpression alloc] initWithPattern:@"^#\\w+$" options:0 error:NULL];
});
return hashtagRegularExpression;
}
@implementation FBSDKHashtag
#pragma mark - Class Methods
+ (instancetype)hashtagWithString:(NSString *)hashtagString
{
FBSDKHashtag *hashtag = [[self alloc] init];
hashtag.stringRepresentation = hashtagString;
return hashtag;
}
#pragma mark - Properties
- (NSString *)description
{
if (self.valid) {
return _stringRepresentation;
} else {
return [NSString stringWithFormat:@"Invalid hashtag '%@'", _stringRepresentation];
}
}
- (BOOL)isValid
{
if (_stringRepresentation == nil) {
return NO;
}
NSRange fullString = NSMakeRange(0, _stringRepresentation.length);
NSRegularExpression *hashtagRegularExpression = HashtagRegularExpression();
NSUInteger numberOfMatches = [hashtagRegularExpression numberOfMatchesInString:_stringRepresentation
options:0
range:fullString];
return numberOfMatches > 0;
}
#pragma mark - Equality
- (NSUInteger)hash
{
return [_stringRepresentation hash];
}
- (BOOL)isEqual:(id)object
{
if (self == object) {
return YES;
}
if (![object isKindOfClass:[FBSDKHashtag class]]) {
return NO;
}
return [self isEqualToHashtag:(FBSDKHashtag *)object];
}
- (BOOL)isEqualToHashtag:(FBSDKHashtag *)hashtag
{
return (hashtag &&
[FBSDKInternalUtility object:_stringRepresentation isEqualToObject:hashtag.stringRepresentation]);
}
#pragma mark - NSCoding
+ (BOOL)supportsSecureCoding
{
return YES;
}
- (id)initWithCoder:(NSCoder *)aDecoder
{
if ((self = [self init])) {
_stringRepresentation = [aDecoder decodeObjectOfClass:[NSString class] forKey:FBSDK_HASHTAG_STRING_KEY];
}
return self;
}
- (void)encodeWithCoder:(NSCoder *)aCoder
{
[aCoder encodeObject:_stringRepresentation forKey:FBSDK_HASHTAG_STRING_KEY];
}
#pragma mark - NSCopying
- (id)copyWithZone:(NSZone *)zone
{
FBSDKHashtag *copy = [[FBSDKHashtag alloc] init];
copy.stringRepresentation = [_stringRepresentation copy];
return copy;
}
@end

View File

@ -25,6 +25,7 @@
#import "FBSDKShareDefines.h"
#import "FBSDKShareError.h"
#import "FBSDKShareLinkContent.h"
#import "FBSDKShareMediaContent.h"
#import "FBSDKShareOpenGraphAction.h"
#import "FBSDKShareOpenGraphContent.h"
#import "FBSDKShareOpenGraphObject.h"
@ -34,8 +35,6 @@
#import "FBSDKShareVideo.h"
#import "FBSDKShareVideoContent.h"
#define FBSDK_SHARE_DIALOG_APP_SCHEME @"fbapi"
#define FBSDK_SHARE_EXTENSION_APP_SCHEME @"fbshareextension"
#define FBSDK_SHARE_FEED_METHOD_NAME @"feed"
#define FBSDK_SHARE_METHOD_MIN_VERSION @"20130410"
#define FBSDK_SHARE_METHOD_OG_MIN_VERSION @"20130214"
@ -43,6 +42,25 @@
#define FBSDK_SHARE_METHOD_PHOTOS_MIN_VERSION @"20140116"
#define FBSDK_SHARE_METHOD_VIDEO_MIN_VERSION @"20150313"
#define FBSDK_SHARE_METHOD_ATTRIBUTED_SHARE_SHEET_MIN_VERSION @"20150629"
#define FBSDK_SHARE_METHOD_QUOTE_MIN_VERSION @"20160328"
#define FBSDK_SHARE_METHOD_MMP_MIN_VERSION @"20160328"
FBSDK_STATIC_INLINE void FBSDKShareDialogValidateAPISchemeRegisteredForCanOpenUrl()
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
[FBSDKInternalUtility checkRegisteredCanOpenURLScheme:FBSDK_CANOPENURL_FBAPI];
});
}
FBSDK_STATIC_INLINE void FBSDKShareDialogValidateShareExtensionSchemeRegisteredForCanOpenUrl()
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
[FBSDKInternalUtility checkRegisteredCanOpenURLScheme:FBSDK_CANOPENURL_SHARE_EXTENSION];
});
}
@interface FBSDKShareDialog () <FBSDKWebDialogDelegate>
@end
@ -113,7 +131,7 @@
BOOL didShow = NO;
NSError *error = nil;
if ([self validateWithError:&error]) {
if ([self _validateWithError:&error]) {
switch (self.mode) {
case FBSDKShareDialogModeAutomatic:{
didShow = [self _showAutomatic:&error];
@ -156,47 +174,7 @@
- (BOOL)validateWithError:(NSError *__autoreleasing *)errorRef
{
if (errorRef != NULL) {
*errorRef = nil;
}
id<FBSDKSharingContent> shareContent = self.shareContent;
if (!shareContent) {
if (errorRef != NULL) {
*errorRef = [FBSDKShareError requiredArgumentErrorWithName:@"shareContent" message:nil];
}
return NO;
}
if (![FBSDKShareUtility validateShareContent:shareContent error:errorRef]) {
return NO;
}
if ([shareContent isKindOfClass:[FBSDKShareVideoContent class]]) {
if (![FBSDKShareUtility validateAssetLibraryURLWithShareVideoContent:(FBSDKShareVideoContent *)shareContent name:@"videoURL" error:errorRef]) {
return NO;
}
}
switch (self.mode) {
case FBSDKShareDialogModeAutomatic:{
return (
([self _canShowNative] && [self _validateShareContentForNative:errorRef]) ||
([self _canShowShareSheet] && [self _validateShareContentForShareSheet:errorRef]) ||
[self _validateShareContentForFeed:errorRef] ||
[self _validateShareContentForBrowser:errorRef]);
}
case FBSDKShareDialogModeNative:{
return [self _validateShareContentForNative:errorRef];
}
case FBSDKShareDialogModeShareSheet:{
return [self _validateShareContentForShareSheet:errorRef];
}
case FBSDKShareDialogModeBrowser:
case FBSDKShareDialogModeWeb:{
return [self _validateShareContentForBrowser:errorRef];
}
case FBSDKShareDialogModeFeedBrowser:
case FBSDKShareDialogModeFeedWeb:{
return [self _validateShareContentForFeed:errorRef];
}
}
return [self _validateWithError:errorRef] && [self _validateFullyCompatibleWithError:errorRef];
}
#pragma mark - FBSDKWebDialogDelegate
@ -245,6 +223,17 @@
return [configuration.defaultShareMode isEqualToString:@"share_sheet"];
}
- (BOOL)_isOpenGraphURLShare:(FBSDKShareOpenGraphContent *)shareContent
{
__block BOOL hasOGURL = NO;
[shareContent.action enumerateKeysAndObjectsUsingBlock:^(NSString *key, id object, BOOL *stop) {
if ([object isKindOfClass:[NSURL class]]) {
hasOGURL = YES;
}
}];
return hasOGURL;
}
-(BOOL)_showAutomatic:(NSError *__autoreleasing *)errorRef
{
BOOL isDefaultToShareSheet = [self _isDefaultToShareSheet];
@ -280,7 +269,7 @@
if ([shareContent isKindOfClass:[FBSDKShareOpenGraphContent class]]) {
methodName = FBSDK_SHARE_OPEN_GRAPH_METHOD_NAME;
BOOL containsMedia = NO;
[FBSDKShareUtility testShareContent:shareContent containsMedia:&containsMedia containsPhotos:NULL];
[FBSDKShareUtility testShareContent:shareContent containsMedia:&containsMedia containsPhotos:NULL containsVideos:NULL];
if (containsMedia) {
methodVersion = FBSDK_SHARE_METHOD_OG_IMAGE_MIN_VERSION;
} else {
@ -328,7 +317,8 @@
if (![FBSDKInternalUtility isOSRunTimeVersionAtLeast:iOS8Version]) {
return NO;
}
NSString *scheme = FBSDK_SHARE_DIALOG_APP_SCHEME;
FBSDKShareDialogValidateAPISchemeRegisteredForCanOpenUrl();
NSString *scheme = FBSDK_CANOPENURL_FBAPI;
NSString *minimumVersion = FBSDK_SHARE_METHOD_ATTRIBUTED_SHARE_SHEET_MIN_VERSION;
NSURLComponents *components = [[NSURLComponents alloc] init];
components.scheme = [scheme stringByAppendingString:minimumVersion];
@ -343,8 +333,33 @@
if (![FBSDKInternalUtility isOSRunTimeVersionAtLeast:iOS8Version]) {
return NO;
}
FBSDKShareDialogValidateShareExtensionSchemeRegisteredForCanOpenUrl();
NSURLComponents *components = [[NSURLComponents alloc] init];
components.scheme = FBSDK_SHARE_EXTENSION_APP_SCHEME;
components.scheme = FBSDK_CANOPENURL_SHARE_EXTENSION;
components.path = @"/";
return [[UIApplication sharedApplication] canOpenURL:components.URL];
}
- (BOOL)_canUseQuoteInShareSheet
{
return [self _canUseFBShareSheet] && [self _supportsShareSheetMinimumVersion:FBSDK_SHARE_METHOD_QUOTE_MIN_VERSION];
}
- (BOOL)_canUseMMPInShareSheet
{
return [self _canUseFBShareSheet] && [self _supportsShareSheetMinimumVersion:FBSDK_SHARE_METHOD_MMP_MIN_VERSION];
}
- (BOOL)_supportsShareSheetMinimumVersion:(NSString *)minimumVersion
{
NSOperatingSystemVersion iOS8Version = { .majorVersion = 8, .minorVersion = 0, .patchVersion = 0 };
if (![FBSDKInternalUtility isOSRunTimeVersionAtLeast:iOS8Version]) {
return NO;
}
FBSDKShareDialogValidateAPISchemeRegisteredForCanOpenUrl();
NSString *scheme = FBSDK_CANOPENURL_FBAPI;
NSURLComponents *components = [[NSURLComponents alloc] init];
components.scheme = [scheme stringByAppendingString:minimumVersion];
components.path = @"/";
return [[UIApplication sharedApplication] canOpenURL:components.URL];
}
@ -357,10 +372,43 @@
- (NSArray *)_contentImages
{
NSMutableArray *ret = [NSMutableArray new];
id<FBSDKSharingContent> shareContent = self.shareContent;
return ([shareContent isKindOfClass:[FBSDKSharePhotoContent class]] ?
[((FBSDKSharePhotoContent *)shareContent).photos valueForKeyPath:@"@distinctUnionOfObjects.image"] :
nil);
if ([shareContent isKindOfClass:[FBSDKSharePhotoContent class]]) {
[ret addObjectsFromArray:[((FBSDKSharePhotoContent *)shareContent).photos valueForKeyPath:@"@distinctUnionOfObjects.image"]];
} else if ([shareContent isKindOfClass:[FBSDKShareMediaContent class]]) {
for (id media in ((FBSDKShareMediaContent *)shareContent).media) {
if ([media isKindOfClass:[FBSDKSharePhoto class]]) {
UIImage *image = ((FBSDKSharePhoto *)media).image;
if (image != nil) {
[ret addObject:image];
}
}
}
}
return [ret copy];
}
- (NSArray *)_contentVideoURLs
{
NSMutableArray *ret = [NSMutableArray new];
id<FBSDKSharingContent> shareContent = self.shareContent;
if ([shareContent isKindOfClass:[FBSDKShareVideoContent class]]) {
NSURL *videoURL = ((FBSDKShareVideoContent *)shareContent).video.videoURL;
if (videoURL != nil) {
[ret addObject:videoURL];
}
} else if ([shareContent isKindOfClass:[FBSDKShareMediaContent class]]) {
for (id media in ((FBSDKShareMediaContent *)shareContent).media) {
if ([media isKindOfClass:[FBSDKShareVideo class]]) {
NSURL *videoURL = ((FBSDKShareVideo *)media).videoURL;
if (videoURL != nil) {
[ret addObject:videoURL];
}
}
}
}
return [ret copy];
}
- (NSArray *)_contentURLs
@ -545,9 +593,7 @@
}
NSArray *images = [self _contentImages];
NSArray *URLs = [self _contentURLs];
NSURL *videoURL = ([self.shareContent isKindOfClass:[FBSDKShareVideoContent class]] ?
((FBSDKShareVideoContent *)self.shareContent).video.videoURL :
nil);
NSArray *videoURLs = [self _contentVideoURLs];
Class composeViewControllerClass = [fbsdkdfl_SLComposeViewControllerClass() class];
NSString *facebookServiceType = fbsdkdfl_SLServiceTypeFacebook();
@ -561,17 +607,19 @@
}
return NO;
}
if ([self _canAttributeThroughShareSheet]) {
NSString *attributionToken = [NSString stringWithFormat:@"fb-app-id:%@", [FBSDKSettings appID]];
[composeViewController setInitialText:attributionToken];
NSString *initialText = [self _calculateInitialText];
if (initialText.length > 0) {
[composeViewController setInitialText:initialText];
}
for (UIImage *image in images) {
[composeViewController addImage:image];
}
for (NSURL *URL in URLs) {
[composeViewController addURL:URL];
}
if (videoURL) {
for (NSURL *videoURL in videoURLs) {
[composeViewController addURL:videoURL];
}
composeViewController.completionHandler = ^(SLComposeViewControllerResult result) {
@ -625,12 +673,105 @@
return [configuration useSafariViewControllerForDialogName:FBSDKDialogConfigurationNameShare];
}
- (BOOL)_validateWithError:(NSError *__autoreleasing *)errorRef
{
if (errorRef != NULL) {
*errorRef = nil;
}
id<FBSDKSharingContent> shareContent = self.shareContent;
if (!shareContent) {
if (errorRef != NULL) {
*errorRef = [FBSDKShareError requiredArgumentErrorWithName:@"shareContent" message:nil];
}
return NO;
}
if (![FBSDKShareUtility validateShareContent:shareContent error:errorRef]) {
return NO;
}
if ([shareContent isKindOfClass:[FBSDKShareVideoContent class]]) {
if (![FBSDKShareUtility validateAssetLibraryURLWithShareVideoContent:(FBSDKShareVideoContent *)shareContent name:@"videoURL" error:errorRef]) {
return NO;
}
}
if ([shareContent isKindOfClass:[FBSDKShareMediaContent class]]) {
if (![FBSDKShareUtility validateAssetLibraryURLsWithShareMediaContent:(FBSDKShareMediaContent *)shareContent name:@"mediaVideoURL" error:errorRef]) {
return NO;
}
}
switch (self.mode) {
case FBSDKShareDialogModeAutomatic:{
return (
([self _canShowNative] && [self _validateShareContentForNative:errorRef]) ||
([self _canShowShareSheet] && [self _validateShareContentForShareSheet:errorRef]) ||
[self _validateShareContentForFeed:errorRef] ||
[self _validateShareContentForBrowser:errorRef]);
}
case FBSDKShareDialogModeNative:{
return [self _validateShareContentForNative:errorRef];
}
case FBSDKShareDialogModeShareSheet:{
return [self _validateShareContentForShareSheet:errorRef];
}
case FBSDKShareDialogModeBrowser:
case FBSDKShareDialogModeWeb:{
return [self _validateShareContentForBrowser:errorRef];
}
case FBSDKShareDialogModeFeedBrowser:
case FBSDKShareDialogModeFeedWeb:{
return [self _validateShareContentForFeed:errorRef];
}
}
}
/**
`validateWithError:` can be used by clients of this API to discover if certain features are
available for a specific `mode`. However, these features could be optional for said `mode`, in which
case `validateWithError:` should return NO but when calling `show`, the dialog must still show.
ie: Quotes are only available if FB for iOS v52 or higher is installed. If the client adds a quote to
the `ShareLinkContent` object and FB for iOS v52 or higher is not installed, `validateWithError:` will
return NO if the `mode` is set to ShareSheet. However, calling `show` will actually show the shareSheet
without the Quote.
This method exists to enable the behavior described above and should only be called from `validateWithError:`.
*/
- (BOOL)_validateFullyCompatibleWithError:(NSError *__autoreleasing *)errorRef
{
id<FBSDKSharingContent> shareContent = self.shareContent;
if ([shareContent isKindOfClass:[FBSDKShareLinkContent class]]) {
FBSDKShareLinkContent *shareLinkContent = (FBSDKShareLinkContent *)shareContent;
if (shareLinkContent.quote.length > 0 &&
self.mode == FBSDKShareDialogModeShareSheet &&
![self _canUseQuoteInShareSheet]) {
if ((errorRef != NULL) && !*errorRef) {
*errorRef = [FBSDKShareError invalidArgumentErrorWithName:@"shareContent"
value:shareLinkContent
message:@"Quotes are only supported if Facebook for iOS version 52 and above is installed"];
}
return NO;
}
} else if ([shareContent isKindOfClass:[FBSDKShareMediaContent class]]) {
FBSDKShareMediaContent *mediaContent = (FBSDKShareMediaContent *)shareContent;
if ([FBSDKShareUtility shareMediaContentContainsPhotosAndVideos:mediaContent] &&
self.mode == FBSDKShareDialogModeShareSheet &&
![self _canUseMMPInShareSheet]) {
if ((errorRef != NULL) && !*errorRef) {
*errorRef = [FBSDKShareError invalidArgumentErrorWithName:@"shareContent"
value:shareContent
message:@"Multimedia content (photos + videos) is only supported if Facebook for iOS version 52 and above is installed"];
}
return NO;
}
}
return YES;
}
- (BOOL)_validateShareContentForBrowser:(NSError **)errorRef
{
id<FBSDKSharingContent> shareContent = self.shareContent;
BOOL containsMedia;
BOOL containsPhotos;
[FBSDKShareUtility testShareContent:shareContent containsMedia:&containsMedia containsPhotos:&containsPhotos];
[FBSDKShareUtility testShareContent:shareContent containsMedia:&containsMedia containsPhotos:&containsPhotos containsVideos:NULL];
if (containsPhotos) {
if ((errorRef != NULL) && !*errorRef) {
*errorRef = [FBSDKShareError invalidArgumentErrorWithName:@"shareContent"
@ -667,6 +808,16 @@
- (BOOL)_validateShareContentForNative:(NSError **)errorRef
{
id<FBSDKSharingContent> shareContent = self.shareContent;
if ([shareContent isKindOfClass:[FBSDKShareMediaContent class]]) {
if ([FBSDKShareUtility shareMediaContentContainsPhotosAndVideos:(FBSDKShareMediaContent *)shareContent]) {
if ((errorRef != NULL) && !*errorRef) {
*errorRef = [FBSDKShareError invalidArgumentErrorWithName:@"shareContent"
value:shareContent
message:@"Multimedia Content is only available for mode `ShareSheet`"];
}
return NO;
}
}
if (![shareContent isKindOfClass:[FBSDKShareVideoContent class]]) {
return YES;
}
@ -689,9 +840,26 @@
} else if ([shareContent isKindOfClass:[FBSDKShareVideoContent class]]) {
return ([self _canUseFBShareSheet] &&
[self _validateVideoURL:((FBSDKShareVideoContent *)shareContent).video.videoURL error:errorRef]);
} else if ([shareContent isKindOfClass:[FBSDKShareMediaContent class]]) {
return ([self _canUseFBShareSheet] &&
[FBSDKShareUtility validateShareMediaContent:(FBSDKShareMediaContent *)shareContent error:errorRef]);
} else if ([shareContent isKindOfClass:[FBSDKShareOpenGraphContent class]]) {
FBSDKShareOpenGraphContent *ogContent = (FBSDKShareOpenGraphContent *)shareContent;
BOOL isOGURLShare = [self _isOpenGraphURLShare:ogContent];
BOOL isValidOGShare = (isOGURLShare &&
[ogContent.action.actionType length] != 0 &&
[ogContent.previewPropertyName length] != 0);
if (!isValidOGShare) {
if ((errorRef != NULL) && !*errorRef) {
NSString *message = @"Share content must include an URL in the action, an action type, and a preview property name in order to share with the share sheet.";
*errorRef = [FBSDKShareError invalidArgumentErrorWithName:@"shareContent" value:shareContent message:message];
}
}
return isValidOGShare;
} else if (![shareContent isKindOfClass:[FBSDKShareLinkContent class]]) {
if ((errorRef != NULL) && !*errorRef) {
NSString *message = @"Share content must be FBSDKShareLinkContent or FBSDKSharePhotoContent in order to share "
NSString *message = @"Share content must be FBSDKShareLinkContent or FBSDKShareMediaContent in order to share "
@"with the share sheet.";
*errorRef = [FBSDKShareError invalidArgumentErrorWithName:@"shareContent" value:shareContent message:message];
}
@ -785,4 +953,58 @@
accessToken:[FBSDKAccessToken currentAccessToken]];
}
- (NSString *)_calculateInitialText
{
NSString *initialText;
if ([self _canAttributeThroughShareSheet]) {
NSMutableDictionary *initialTextDictionary = [NSMutableDictionary new];
initialTextDictionary[@"app_id"] = [FBSDKSettings appID];
NSString *hashtag = [FBSDKShareUtility hashtagStringFromHashtag:self.shareContent.hashtag];
if (hashtag != nil) {
initialTextDictionary[@"hashtags"] = @[hashtag];
}
if ([self.shareContent isKindOfClass:[FBSDKShareLinkContent class]]) {
NSString *quote = [(FBSDKShareLinkContent *)self.shareContent quote];
if (quote != nil) {
initialTextDictionary[@"quotes"] = @[quote];
}
}
if ([self.shareContent isKindOfClass:[FBSDKShareOpenGraphContent class]]) {
NSDictionary *ogData = [FBSDKShareUtility parametersForShareContent:self.shareContent
shouldFailOnDataError:self.shouldFailOnDataError];
initialTextDictionary[@"og_data"] = ogData;
}
NSError *error = nil;
NSString *jsonString = [FBSDKInternalUtility JSONStringForObject:initialTextDictionary error:&error invalidObjectHandler:NULL];
if (error != nil) {
return nil;
}
NSString *JSONStartDelimiter = @"|";
initialText = [NSString stringWithFormat:@"%@%@%@",
[self _calculatePreJSONInitialTextWithHashtag:hashtag],
JSONStartDelimiter,
jsonString];
} else {
NSString *hashtag = [FBSDKShareUtility hashtagStringFromHashtag:self.shareContent.hashtag];
if (hashtag != nil) {
initialText = hashtag;
}
}
return initialText;
}
// Not all versions of the Share Extension support JSON. Adding this text before allows backward compatibility
- (NSString *)_calculatePreJSONInitialTextWithHashtag:(NSString *)hashtag
{
NSMutableString *text = [NSMutableString new];
[text appendString:[NSString stringWithFormat:@"fb-app-id:%@", [FBSDKSettings appID]]];
if (hashtag != nil) {
[text appendString:@" "];
[text appendString:hashtag];
}
return [text copy];
}
@end

View File

@ -18,6 +18,7 @@
#import <UIKit/UIKit.h>
#import <FBSDKShareKit/FBSDKHashtag.h>
#import <FBSDKShareKit/FBSDKShareAPI.h>
#import <FBSDKShareKit/FBSDKShareConstants.h>
#import <FBSDKShareKit/FBSDKShareLinkContent.h>
@ -46,5 +47,9 @@
#import <FBSDKShareKit/FBSDKShareButton.h>
#import <FBSDKShareKit/FBSDKShareDialog.h>
#import <FBSDKShareKit/FBSDKShareDialogMode.h>
#import <FBSDKShareKit/FBSDKShareMediaContent.h>
#import <FBSDKShareKit/FBSDKSendButton.h>
#else
#import <FBSDKShareKit/FBSDKDeviceShareViewController.h>
#import <FBSDKShareKit/FBSDKDeviceShareButton.h>
#endif

View File

@ -46,6 +46,13 @@
*/
@property (nonatomic, copy) NSURL *imageURL;
/*!
@abstract Some quote text of the link.
@discussion If specified, the quote text will render with custom styling on top of the link.
@return The quote text of a link
*/
@property (nonatomic, copy) NSString *quote;
/*!
@abstract Compares the receiver to another link content.
@param content The other content

View File

@ -19,15 +19,18 @@
#import "FBSDKShareLinkContent+Internal.h"
#import "FBSDKCoreKit+Internal.h"
#import "FBSDKHashtag.h"
#import "FBSDKShareUtility.h"
#define FBSDK_SHARE_STATUS_CONTENT_CONTENT_DESCRIPTION_KEY @"contentDescription"
#define FBSDK_SHARE_STATUS_CONTENT_CONTENT_TITLE_KEY @"contentTitle"
#define FBSDK_SHARE_STATUS_CONTENT_CONTENT_URL_KEY @"contentURL"
#define FBSDK_SHARE_STATUS_CONTENT_HASHTAG_KEY @"hashtag"
#define FBSDK_SHARE_STATUS_CONTENT_IMAGE_URL_KEY @"imageURL"
#define FBSDK_SHARE_STATUS_CONTENT_PEOPLE_IDS_KEY @"peopleIDs"
#define FBSDK_SHARE_STATUS_CONTENT_PLACE_ID_KEY @"placeID"
#define FBSDK_SHARE_STATUS_CONTENT_REF_KEY @"ref"
#define FBSDK_SHARE_STATUS_CONTENT_QUOTE_TEXT_KEY @"quote"
#define FBSDK_SHARE_STATUS_CONTENT_FEED_PARAMETERS_KEY @"feedParameters"
@implementation FBSDKShareLinkContent
@ -35,10 +38,12 @@
#pragma mark - Properties
@synthesize contentURL = _contentURL;
@synthesize hashtag = _hashtag;
@synthesize peopleIDs = _peopleIDs;
@synthesize placeID = _placeID;
@synthesize ref = _ref;
@synthesize feedParameters = _feedParameters;
@synthesize quote = _quote;
- (void)setPeopleIDs:(NSArray *)peopleIDs
{
@ -62,12 +67,14 @@
NSUInteger subhashes[] = {
[_contentDescription hash],
[_contentURL hash],
[_hashtag hash],
[_imageURL hash],
[_peopleIDs hash],
[_placeID hash],
[_ref hash],
[_contentTitle hash],
[_feedParameters hash],
[_quote hash],
};
return [FBSDKMath hashWithIntegerArray:subhashes count:sizeof(subhashes) / sizeof(subhashes[0])];
}
@ -89,11 +96,13 @@
[FBSDKInternalUtility object:_contentDescription isEqualToObject:content.contentDescription] &&
[FBSDKInternalUtility object:_contentTitle isEqualToObject:content.contentTitle] &&
[FBSDKInternalUtility object:_contentURL isEqualToObject:content.contentURL] &&
[FBSDKInternalUtility object:_hashtag isEqualToObject:content.hashtag] &&
[FBSDKInternalUtility object:_feedParameters isEqualToObject:content.feedParameters] &&
[FBSDKInternalUtility object:_imageURL isEqualToObject:content.imageURL] &&
[FBSDKInternalUtility object:_peopleIDs isEqualToObject:content.peopleIDs] &&
[FBSDKInternalUtility object:_placeID isEqualToObject:content.placeID] &&
[FBSDKInternalUtility object:_ref isEqualToObject:content.ref]);
[FBSDKInternalUtility object:_ref isEqualToObject:content.ref]) &&
[FBSDKInternalUtility object:_quote isEqualToObject:content.quote];
}
#pragma mark - NSCoding
@ -111,10 +120,12 @@
_contentTitle = [decoder decodeObjectOfClass:[NSString class] forKey:FBSDK_SHARE_STATUS_CONTENT_CONTENT_TITLE_KEY];
_contentURL = [decoder decodeObjectOfClass:[NSURL class] forKey:FBSDK_SHARE_STATUS_CONTENT_CONTENT_URL_KEY];
_feedParameters = [decoder decodeObjectOfClass:[NSDictionary class] forKey:FBSDK_SHARE_STATUS_CONTENT_FEED_PARAMETERS_KEY];
_hashtag = [decoder decodeObjectOfClass:[FBSDKHashtag class] forKey:FBSDK_SHARE_STATUS_CONTENT_HASHTAG_KEY];
_imageURL = [decoder decodeObjectOfClass:[NSURL class] forKey:FBSDK_SHARE_STATUS_CONTENT_IMAGE_URL_KEY];
_peopleIDs = [decoder decodeObjectOfClass:[NSArray class] forKey:FBSDK_SHARE_STATUS_CONTENT_PEOPLE_IDS_KEY];
_placeID = [decoder decodeObjectOfClass:[NSString class] forKey:FBSDK_SHARE_STATUS_CONTENT_PLACE_ID_KEY];
_ref = [decoder decodeObjectOfClass:[NSString class] forKey:FBSDK_SHARE_STATUS_CONTENT_REF_KEY];
_quote = [decoder decodeObjectOfClass:[NSString class] forKey:FBSDK_SHARE_STATUS_CONTENT_QUOTE_TEXT_KEY];
}
return self;
}
@ -125,10 +136,12 @@
[encoder encodeObject:_contentTitle forKey:FBSDK_SHARE_STATUS_CONTENT_CONTENT_TITLE_KEY];
[encoder encodeObject:_contentURL forKey:FBSDK_SHARE_STATUS_CONTENT_CONTENT_URL_KEY];
[encoder encodeObject:_feedParameters forKey:FBSDK_SHARE_STATUS_CONTENT_FEED_PARAMETERS_KEY];
[encoder encodeObject:_hashtag forKey:FBSDK_SHARE_STATUS_CONTENT_HASHTAG_KEY];
[encoder encodeObject:_imageURL forKey:FBSDK_SHARE_STATUS_CONTENT_IMAGE_URL_KEY];
[encoder encodeObject:_peopleIDs forKey:FBSDK_SHARE_STATUS_CONTENT_PEOPLE_IDS_KEY];
[encoder encodeObject:_placeID forKey:FBSDK_SHARE_STATUS_CONTENT_PLACE_ID_KEY];
[encoder encodeObject:_ref forKey:FBSDK_SHARE_STATUS_CONTENT_REF_KEY];
[encoder encodeObject:_quote forKey:FBSDK_SHARE_STATUS_CONTENT_QUOTE_TEXT_KEY];
}
#pragma mark - NSCopying
@ -140,10 +153,12 @@
copy->_contentTitle = [_contentTitle copy];
copy->_contentURL = [_contentURL copy];
copy->_feedParameters = [_feedParameters copy];
copy->_hashtag = [_hashtag copy];
copy->_imageURL = [_imageURL copy];
copy->_peopleIDs = [_peopleIDs copy];
copy->_placeID = [_placeID copy];
copy->_ref = [_ref copy];
copy->_quote = [_quote copy];
return copy;
}

View File

@ -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 <Foundation/Foundation.h>
#import <FBSDKShareKit/FBSDKSharingContent.h>
/*!
@abstract A model for media content (photo or video) to be shared.
*/
@interface FBSDKShareMediaContent : NSObject <FBSDKSharingContent>
/*!
@abstract Media to be shared.
@return Array of the media (FBSDKSharePhoto or FBSDKShareVideo)
*/
@property (nonatomic, copy) NSArray *media;
/*!
@abstract Compares the receiver to another media content.
@param content The other content
@return YES if the receiver's values are equal to the other content's values; otherwise NO
*/
- (BOOL)isEqualToShareMediaContent:(FBSDKShareMediaContent *)content;
@end

View File

@ -0,0 +1,142 @@
// 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 "FBSDKShareMediaContent.h"
#import "FBSDKCoreKit+Internal.h"
#import "FBSDKHashtag.h"
#import "FBSDKSharePhoto.h"
#import "FBSDKShareUtility.h"
#import "FBSDKShareVideo.h"
#define FBSDK_SHARE_MEDIA_CONTENT_CONTENT_URL_KEY @"contentURL"
#define FBSDK_SHARE_MEDIA_CONTENT_HASHTAG_KEY @"hashtag"
#define FBSDK_SHARE_MEDIA_CONTENT_PEOPLE_IDS_KEY @"peopleIDs"
#define FBSDK_SHARE_MEDIA_CONTENT_MEDIA_KEY @"media"
#define FBSDK_SHARE_MEDIA_CONTENT_PLACE_ID_KEY @"placeID"
#define FBSDK_SHARE_MEDIA_CONTENT_REF_KEY @"ref"
@implementation FBSDKShareMediaContent
#pragma mark - Properties
@synthesize contentURL = _contentURL;
@synthesize hashtag = _hashtag;
@synthesize peopleIDs = _peopleIDs;
@synthesize placeID = _placeID;
@synthesize ref = _ref;
- (void)setPeopleIDs:(NSArray *)peopleIDs
{
[FBSDKShareUtility assertCollection:peopleIDs ofClass:[NSString class] name:@"peopleIDs"];
if (![FBSDKInternalUtility object:_peopleIDs isEqualToObject:peopleIDs]) {
_peopleIDs = [peopleIDs copy];
}
}
- (void)setMedia:(NSArray *)media
{
[FBSDKShareUtility assertCollection:media ofClassStrings:@[NSStringFromClass([FBSDKSharePhoto class]), NSStringFromClass([FBSDKShareVideo class])] name:@"media"];
if (![FBSDKInternalUtility object:_media isEqualToObject:media]) {
_media = [media copy];
}
}
#pragma mark - Equality
- (NSUInteger)hash
{
NSUInteger subhashes[] = {
[_contentURL hash],
[_hashtag hash],
[_peopleIDs hash],
[_media hash],
[_placeID hash],
[_ref hash],
};
return [FBSDKMath hashWithIntegerArray:subhashes count:sizeof(subhashes) / sizeof(subhashes[0])];
}
- (BOOL)isEqual:(id)object
{
if (self == object) {
return YES;
}
if (![object isKindOfClass:[FBSDKShareMediaContent class]]) {
return NO;
}
return [self isEqualToShareMediaContent:(FBSDKShareMediaContent *)object];
}
- (BOOL)isEqualToShareMediaContent:(FBSDKShareMediaContent *)content
{
return (content &&
[FBSDKInternalUtility object:_contentURL isEqualToObject:content.contentURL] &&
[FBSDKInternalUtility object:_hashtag isEqualToObject:content.hashtag] &&
[FBSDKInternalUtility object:_peopleIDs isEqualToObject:content.peopleIDs] &&
[FBSDKInternalUtility object:_media isEqualToObject:content.media] &&
[FBSDKInternalUtility object:_placeID isEqualToObject:content.placeID] &&
[FBSDKInternalUtility object:_ref isEqualToObject:content.ref]);
}
#pragma mark - NSCoding
+ (BOOL)supportsSecureCoding
{
return YES;
}
- (id)initWithCoder:(NSCoder *)decoder
{
if ((self = [self init])) {
_contentURL = [decoder decodeObjectOfClass:[NSURL class] forKey:FBSDK_SHARE_MEDIA_CONTENT_CONTENT_URL_KEY];
_hashtag = [decoder decodeObjectOfClass:[FBSDKHashtag class] forKey:FBSDK_SHARE_MEDIA_CONTENT_HASHTAG_KEY];
_peopleIDs = [decoder decodeObjectOfClass:[NSArray class] forKey:FBSDK_SHARE_MEDIA_CONTENT_PEOPLE_IDS_KEY];
NSSet *classes = [NSSet setWithObjects:[NSArray class], [FBSDKSharePhoto class], nil];
_media = [decoder decodeObjectOfClasses:classes forKey:FBSDK_SHARE_MEDIA_CONTENT_MEDIA_KEY];
_placeID = [decoder decodeObjectOfClass:[NSString class] forKey:FBSDK_SHARE_MEDIA_CONTENT_PLACE_ID_KEY];
_ref = [decoder decodeObjectOfClass:[NSString class] forKey:FBSDK_SHARE_MEDIA_CONTENT_REF_KEY];
}
return self;
}
- (void)encodeWithCoder:(NSCoder *)encoder
{
[encoder encodeObject:_contentURL forKey:FBSDK_SHARE_MEDIA_CONTENT_CONTENT_URL_KEY];
[encoder encodeObject:_hashtag forKey:FBSDK_SHARE_MEDIA_CONTENT_HASHTAG_KEY];
[encoder encodeObject:_peopleIDs forKey:FBSDK_SHARE_MEDIA_CONTENT_PEOPLE_IDS_KEY];
[encoder encodeObject:_media forKey:FBSDK_SHARE_MEDIA_CONTENT_MEDIA_KEY];
[encoder encodeObject:_placeID forKey:FBSDK_SHARE_MEDIA_CONTENT_PLACE_ID_KEY];
[encoder encodeObject:_ref forKey:FBSDK_SHARE_MEDIA_CONTENT_REF_KEY];
}
#pragma mark - NSCopying
- (id)copyWithZone:(NSZone *)zone
{
FBSDKShareMediaContent *copy = [[FBSDKShareMediaContent alloc] init];
copy->_contentURL = [_contentURL copy];
copy->_hashtag = [_hashtag copy];
copy->_peopleIDs = [_peopleIDs copy];
copy->_media = [_media copy];
copy->_placeID = [_placeID copy];
copy->_ref = [_ref copy];
return copy;
}
@end

View File

@ -19,11 +19,13 @@
#import "FBSDKShareOpenGraphContent.h"
#import "FBSDKCoreKit+Internal.h"
#import "FBSDKHashtag.h"
#import "FBSDKSharePhoto.h"
#import "FBSDKShareUtility.h"
#define FBSDK_SHARE_OPEN_GRAPH_CONTENT_ACTION_KEY @"action"
#define FBSDK_SHARE_OPEN_GRAPH_CONTENT_CONTENT_URL_KEY @"contentURL"
#define FBSDK_SHARE_OPEN_GRAPH_CONTENT_HASHTAG_KEY @"hashtag"
#define FBSDK_SHARE_OPEN_GRAPH_CONTENT_PEOPLE_IDS_KEY @"peopleIDs"
#define FBSDK_SHARE_OPEN_GRAPH_CONTENT_PLACE_ID_KEY @"placeID"
#define FBSDK_SHARE_OPEN_GRAPH_CONTENT_PREVIEW_PROPERTY_NAME_KEY @"previewPropertyName"
@ -34,6 +36,7 @@
#pragma mark - Properties
@synthesize contentURL = _contentURL;
@synthesize hashtag = _hashtag;
@synthesize peopleIDs = _peopleIDs;
@synthesize placeID = _placeID;
@synthesize ref = _ref;
@ -53,6 +56,7 @@
NSUInteger subhashes[] = {
[_action hash],
[_contentURL hash],
[_hashtag hash],
[_peopleIDs hash],
[_placeID hash],
[_previewPropertyName hash],
@ -77,6 +81,7 @@
return (content &&
[FBSDKInternalUtility object:_action isEqualToObject:content.action] &&
[FBSDKInternalUtility object:_contentURL isEqualToObject:content.contentURL] &&
[FBSDKInternalUtility object:_hashtag isEqualToObject:content.hashtag] &&
[FBSDKInternalUtility object:_peopleIDs isEqualToObject:content.peopleIDs] &&
[FBSDKInternalUtility object:_placeID isEqualToObject:content.placeID] &&
[FBSDKInternalUtility object:_previewPropertyName isEqualToObject:content.previewPropertyName] &&
@ -96,6 +101,7 @@
_action = [decoder decodeObjectOfClass:[FBSDKShareOpenGraphAction class]
forKey:FBSDK_SHARE_OPEN_GRAPH_CONTENT_ACTION_KEY];
_contentURL = [decoder decodeObjectOfClass:[NSURL class] forKey:FBSDK_SHARE_OPEN_GRAPH_CONTENT_CONTENT_URL_KEY];
_hashtag = [decoder decodeObjectOfClass:[FBSDKHashtag class] forKey:FBSDK_SHARE_OPEN_GRAPH_CONTENT_HASHTAG_KEY];
_peopleIDs = [decoder decodeObjectOfClass:[NSArray class] forKey:FBSDK_SHARE_OPEN_GRAPH_CONTENT_PEOPLE_IDS_KEY];
_placeID = [decoder decodeObjectOfClass:[NSString class] forKey:FBSDK_SHARE_OPEN_GRAPH_CONTENT_PLACE_ID_KEY];
_previewPropertyName = [decoder decodeObjectOfClass:[NSString class]
@ -109,6 +115,7 @@
{
[encoder encodeObject:_action forKey:FBSDK_SHARE_OPEN_GRAPH_CONTENT_ACTION_KEY];
[encoder encodeObject:_contentURL forKey:FBSDK_SHARE_OPEN_GRAPH_CONTENT_CONTENT_URL_KEY];
[encoder encodeObject:_hashtag forKey:FBSDK_SHARE_OPEN_GRAPH_CONTENT_HASHTAG_KEY];
[encoder encodeObject:_peopleIDs forKey:FBSDK_SHARE_OPEN_GRAPH_CONTENT_PEOPLE_IDS_KEY];
[encoder encodeObject:_placeID forKey:FBSDK_SHARE_OPEN_GRAPH_CONTENT_PLACE_ID_KEY];
[encoder encodeObject:_previewPropertyName forKey:FBSDK_SHARE_OPEN_GRAPH_CONTENT_PREVIEW_PROPERTY_NAME_KEY];
@ -122,6 +129,7 @@
FBSDKShareOpenGraphContent *copy = [[FBSDKShareOpenGraphContent alloc] init];
copy->_action = [_action copy];
copy->_contentURL = [_contentURL copy];
copy->_hashtag = [_hashtag copy];
copy->_peopleIDs = [_peopleIDs copy];
copy->_placeID = [_placeID copy];
copy->_previewPropertyName = [_previewPropertyName copy];

View File

@ -19,10 +19,12 @@
#import "FBSDKSharePhotoContent.h"
#import "FBSDKCoreKit+Internal.h"
#import "FBSDKHashtag.h"
#import "FBSDKSharePhoto.h"
#import "FBSDKShareUtility.h"
#define FBSDK_SHARE_PHOTO_CONTENT_CONTENT_URL_KEY @"contentURL"
#define FBSDK_SHARE_PHOTO_CONTENT_HASHTAG_KEY @"hashtag"
#define FBSDK_SHARE_PHOTO_CONTENT_PEOPLE_IDS_KEY @"peopleIDs"
#define FBSDK_SHARE_PHOTO_CONTENT_PHOTOS_KEY @"photos"
#define FBSDK_SHARE_PHOTO_CONTENT_PLACE_ID_KEY @"placeID"
@ -33,6 +35,7 @@
#pragma mark - Properties
@synthesize contentURL = _contentURL;
@synthesize hashtag = _hashtag;
@synthesize peopleIDs = _peopleIDs;
@synthesize placeID = _placeID;
@synthesize ref = _ref;
@ -59,6 +62,7 @@
{
NSUInteger subhashes[] = {
[_contentURL hash],
[_hashtag hash],
[_peopleIDs hash],
[_photos hash],
[_placeID hash],
@ -82,6 +86,7 @@
{
return (content &&
[FBSDKInternalUtility object:_contentURL isEqualToObject:content.contentURL] &&
[FBSDKInternalUtility object:_hashtag isEqualToObject:content.hashtag] &&
[FBSDKInternalUtility object:_peopleIDs isEqualToObject:content.peopleIDs] &&
[FBSDKInternalUtility object:_photos isEqualToObject:content.photos] &&
[FBSDKInternalUtility object:_placeID isEqualToObject:content.placeID] &&
@ -99,6 +104,7 @@
{
if ((self = [self init])) {
_contentURL = [decoder decodeObjectOfClass:[NSURL class] forKey:FBSDK_SHARE_PHOTO_CONTENT_CONTENT_URL_KEY];
_hashtag = [decoder decodeObjectOfClass:[FBSDKHashtag class] forKey:FBSDK_SHARE_PHOTO_CONTENT_HASHTAG_KEY];
_peopleIDs = [decoder decodeObjectOfClass:[NSArray class] forKey:FBSDK_SHARE_PHOTO_CONTENT_PEOPLE_IDS_KEY];
NSSet *classes = [NSSet setWithObjects:[NSArray class], [FBSDKSharePhoto class], nil];
_photos = [decoder decodeObjectOfClasses:classes forKey:FBSDK_SHARE_PHOTO_CONTENT_PHOTOS_KEY];
@ -111,6 +117,7 @@
- (void)encodeWithCoder:(NSCoder *)encoder
{
[encoder encodeObject:_contentURL forKey:FBSDK_SHARE_PHOTO_CONTENT_CONTENT_URL_KEY];
[encoder encodeObject:_hashtag forKey:FBSDK_SHARE_PHOTO_CONTENT_HASHTAG_KEY];
[encoder encodeObject:_peopleIDs forKey:FBSDK_SHARE_PHOTO_CONTENT_PEOPLE_IDS_KEY];
[encoder encodeObject:_photos forKey:FBSDK_SHARE_PHOTO_CONTENT_PHOTOS_KEY];
[encoder encodeObject:_placeID forKey:FBSDK_SHARE_PHOTO_CONTENT_PLACE_ID_KEY];
@ -123,6 +130,7 @@
{
FBSDKSharePhotoContent *copy = [[FBSDKSharePhotoContent alloc] init];
copy->_contentURL = [_contentURL copy];
copy->_hashtag = [_hashtag copy];
copy->_peopleIDs = [_peopleIDs copy];
copy->_photos = [_photos copy];
copy->_placeID = [_placeID copy];

View File

@ -20,6 +20,8 @@
#import <FBSDKCoreKit/FBSDKCopying.h>
@class FBSDKSharePhoto;
/*!
@abstract A video for sharing.
*/
@ -28,16 +30,28 @@
/*!
@abstract Convenience method to build a new video object with a videoURL.
@param videoURL The URL to the video
application
*/
+ (instancetype)videoWithVideoURL:(NSURL *)videoURL;
/*!
@abstract Convenience method to build a new video object with a videoURL and a previewPhoto
@param videoURL The URL to the video
@param previewPhoto The photo that represents the video
*/
+ (instancetype)videoWithVideoURL:(NSURL *)videoURL previewPhoto:(FBSDKSharePhoto *)previewPhoto;
/*!
@abstract The file URL to the video.
@return URL that points to the location of the video on disk
*/
@property (nonatomic, copy) NSURL *videoURL;
/*!
@abstract The photo that represents the video.
@return The photo
*/
@property (nonatomic, copy) FBSDKSharePhoto *previewPhoto;
/*!
@abstract Compares the receiver to another video.
@param video The other video

View File

@ -19,8 +19,10 @@
#import "FBSDKShareVideo.h"
#import "FBSDKCoreKit+Internal.h"
#import "FBSDKSharePhoto.h"
#define FBSDK_SHARE_VIDEO_URL_KEY @"videoURL"
#define FBSDK_SHARE_VIDEO_PREVIEW_PHOTO_KEY @"previewPhoto"
@implementation FBSDKShareVideo
@ -33,11 +35,23 @@
return video;
}
+ (instancetype)videoWithVideoURL:(NSURL *)videoURL previewPhoto:(FBSDKSharePhoto *)previewPhoto
{
FBSDKShareVideo *video = [[FBSDKShareVideo alloc] init];
video.videoURL = videoURL;
video.previewPhoto = previewPhoto;
return video;
}
#pragma mark - Equality
- (NSUInteger)hash
{
return [_videoURL hash];
NSUInteger subhashes[] = {
[_videoURL hash],
[_previewPhoto hash],
};
return [FBSDKMath hashWithIntegerArray:subhashes count:sizeof(subhashes) / sizeof(subhashes[0])];
}
- (BOOL)isEqual:(id)object
@ -54,7 +68,8 @@
- (BOOL)isEqualToShareVideo:(FBSDKShareVideo *)video
{
return (video &&
[FBSDKInternalUtility object:_videoURL isEqualToObject:video.videoURL]);
[FBSDKInternalUtility object:_videoURL isEqualToObject:video.videoURL] &&
[FBSDKInternalUtility object:_previewPhoto isEqualToObject:video.previewPhoto]);
}
#pragma mark - NSCoding
@ -68,6 +83,7 @@
{
if ((self = [self init])) {
_videoURL = [decoder decodeObjectOfClass:[NSURL class] forKey:FBSDK_SHARE_VIDEO_URL_KEY];
_previewPhoto = [decoder decodeObjectOfClass:[FBSDKSharePhoto class] forKey:FBSDK_SHARE_VIDEO_PREVIEW_PHOTO_KEY];
}
return self;
}
@ -75,6 +91,7 @@
- (void)encodeWithCoder:(NSCoder *)encoder
{
[encoder encodeObject:_videoURL forKey:FBSDK_SHARE_VIDEO_URL_KEY];
[encoder encodeObject:_previewPhoto forKey:FBSDK_SHARE_VIDEO_PREVIEW_PHOTO_KEY];
}
#pragma mark - NSCopying
@ -83,6 +100,7 @@
{
FBSDKShareVideo *copy = [[FBSDKShareVideo alloc] init];
copy->_videoURL = [_videoURL copy];
copy->_previewPhoto = [_previewPhoto copy];
return copy;
}

View File

@ -19,9 +19,11 @@
#import "FBSDKShareVideoContent.h"
#import "FBSDKCoreKit+Internal.h"
#import "FBSDKHashtag.h"
#import "FBSDKShareUtility.h"
#define FBSDK_SHARE_VIDEO_CONTENT_CONTENT_URL_KEY @"contentURL"
#define FBSDK_SHARE_VIDEO_CONTENT_HASHTAG_KEY @"hashtag"
#define FBSDK_SHARE_VIDEO_CONTENT_PEOPLE_IDS_KEY @"peopleIDs"
#define FBSDK_SHARE_VIDEO_CONTENT_PLACE_ID_KEY @"placeID"
#define FBSDK_SHARE_VIDEO_CONTENT_PREVIEW_PHOTO_KEY @"previewPhoto"
@ -33,6 +35,7 @@
#pragma mark - Properties
@synthesize contentURL = _contentURL;
@synthesize hashtag = _hashtag;
@synthesize peopleIDs = _peopleIDs;
@synthesize placeID = _placeID;
@synthesize ref = _ref;
@ -51,6 +54,7 @@
{
NSUInteger subhashes[] = {
[_contentURL hash],
[_hashtag hash],
[_peopleIDs hash],
[_placeID hash],
[_previewPhoto hash],
@ -75,6 +79,7 @@
{
return (content &&
[FBSDKInternalUtility object:_contentURL isEqualToObject:content.contentURL] &&
[FBSDKInternalUtility object:_hashtag isEqualToObject:content.hashtag] &&
[FBSDKInternalUtility object:_peopleIDs isEqualToObject:content.peopleIDs] &&
[FBSDKInternalUtility object:_placeID isEqualToObject:content.placeID] &&
[FBSDKInternalUtility object:_previewPhoto isEqualToObject:content.previewPhoto] &&
@ -93,6 +98,7 @@
{
if ((self = [self init])) {
_contentURL = [decoder decodeObjectOfClass:[NSURL class] forKey:FBSDK_SHARE_VIDEO_CONTENT_CONTENT_URL_KEY];
_hashtag = [decoder decodeObjectOfClass:[FBSDKHashtag class] forKey:FBSDK_SHARE_VIDEO_CONTENT_HASHTAG_KEY];
_peopleIDs = [decoder decodeObjectOfClass:[NSArray class] forKey:FBSDK_SHARE_VIDEO_CONTENT_PEOPLE_IDS_KEY];
_placeID = [decoder decodeObjectOfClass:[NSString class] forKey:FBSDK_SHARE_VIDEO_CONTENT_PLACE_ID_KEY];
_previewPhoto = [decoder decodeObjectOfClass:[FBSDKSharePhoto class]
@ -106,6 +112,7 @@
- (void)encodeWithCoder:(NSCoder *)encoder
{
[encoder encodeObject:_contentURL forKey:FBSDK_SHARE_VIDEO_CONTENT_CONTENT_URL_KEY];
[encoder encodeObject:_hashtag forKey:FBSDK_SHARE_VIDEO_CONTENT_HASHTAG_KEY];
[encoder encodeObject:_peopleIDs forKey:FBSDK_SHARE_VIDEO_CONTENT_PEOPLE_IDS_KEY];
[encoder encodeObject:_placeID forKey:FBSDK_SHARE_VIDEO_CONTENT_PLACE_ID_KEY];
[encoder encodeObject:_previewPhoto forKey:FBSDK_SHARE_VIDEO_CONTENT_PREVIEW_PHOTO_KEY];
@ -119,6 +126,7 @@
{
FBSDKShareVideoContent *copy = [[FBSDKShareVideoContent alloc] init];
copy->_contentURL = [_contentURL copy];
copy->_hashtag = [_hashtag copy];
copy->_peopleIDs = [_peopleIDs copy];
copy->_placeID = [_placeID copy];
copy->_previewPhoto = [_previewPhoto copy];

View File

@ -20,6 +20,8 @@
#import <FBSDKCoreKit/FBSDKCopying.h>
@class FBSDKHashtag;
/*!
@abstract A base interface for content to be shared.
*/
@ -33,6 +35,12 @@
*/
@property (nonatomic, copy) NSURL *contentURL;
/*!
@abstract Hashtag for the content being shared.
@return The hashtag for the content being shared.
*/
@property (nonatomic, copy) FBSDKHashtag *hashtag;
/*!
@abstract List of IDs for taggable people to tag with this content.
@description See documentation for Taggable Friends

View File

@ -19,6 +19,7 @@
#import <Foundation/Foundation.h>
#import <FBSDKShareKit/FBSDKShareLinkContent.h>
#import <FBSDKShareKit/FBSDKShareMediaContent.h>
#import <FBSDKShareKit/FBSDKShareOpenGraphContent.h>
#import <FBSDKShareKit/FBSDKSharePhotoContent.h>
#import <FBSDKShareKit/FBSDKShareVideoContent.h>
@ -32,6 +33,7 @@
@interface FBSDKShareUtility : NSObject
+ (void)assertCollection:(id<NSFastEnumeration>)collection ofClass:itemClass name:(NSString *)name;
+ (void)assertCollection:(id<NSFastEnumeration>)collection ofClassStrings:(NSArray *)classStrings name:(NSString *)name;
+ (void)assertOpenGraphKey:(id)key requireNamespace:(BOOL)requireNamespace;
+ (void)assertOpenGraphValue:(id)value;
+ (void)assertOpenGraphValues:(NSDictionary *)dictionary requireKeyNamespace:(BOOL)requireKeyNamespace;
@ -42,14 +44,19 @@
error:(NSError *__autoreleasing *)errorRef;
+ (NSDictionary *)convertOpenGraphValues:(NSDictionary *)dictionary;
+ (NSDictionary *)feedShareDictionaryForContent:(id<FBSDKSharingContent>)content;
+ (NSString *)hashtagStringFromHashtag:(FBSDKHashtag *)hashtag;
+ (NSDictionary *)parametersForShareContent:(id<FBSDKSharingContent>)shareContent
shouldFailOnDataError:(BOOL)shouldFailOnDataError;
+ (void)testShareContent:(id<FBSDKSharingContent>)shareContent
containsMedia:(BOOL *)containsMediaRef
containsPhotos:(BOOL *)containsPhotosRef;
containsPhotos:(BOOL *)containsPhotosRef
containsVideos:(BOOL *)containsVideosRef;
+ (BOOL)shareMediaContentContainsPhotosAndVideos:(FBSDKShareMediaContent *)shareMediaContent;
+ (BOOL)validateAssetLibraryURLWithShareVideoContent:(FBSDKShareVideoContent *)videoContent name:(NSString *)name error:(NSError *__autoreleasing *)errorRef;
+ (BOOL)validateAssetLibraryURLsWithShareMediaContent:(FBSDKShareMediaContent *)mediaContent name:(NSString *)name error:(NSError *__autoreleasing *)errorRef;
+ (BOOL)validateShareContent:(id<FBSDKSharingContent>)shareContent error:(NSError *__autoreleasing *)errorRef;
+ (BOOL)validateShareLinkContent:(FBSDKShareLinkContent *)linkContent error:(NSError *__autoreleasing *)errorRef;
+ (BOOL)validateShareMediaContent:(FBSDKShareMediaContent *)mediaContent error:(NSError *__autoreleasing *)errorRef;
+ (BOOL)validateShareOpenGraphContent:(FBSDKShareOpenGraphContent *)openGraphContent
error:(NSError *__autoreleasing *)errorRef;
+ (BOOL)validateSharePhotoContent:(FBSDKSharePhotoContent *)photoContent error:(NSError *__autoreleasing *)errorRef;

View File

@ -18,10 +18,13 @@
#import "FBSDKShareUtility.h"
#import <FBSDKShareKit/FBSDKHashtag.h>
#import "FBSDKCoreKit+Internal.h"
#import "FBSDKShareConstants.h"
#import "FBSDKShareError.h"
#import "FBSDKShareLinkContent+Internal.h"
#import "FBSDKShareMediaContent.h"
#import "FBSDKShareOpenGraphContent.h"
#import "FBSDKShareOpenGraphObject.h"
#import "FBSDKSharePhoto.h"
@ -34,6 +37,27 @@
#pragma mark - Class Methods
+ (void)assertCollection:(id<NSFastEnumeration>)collection ofClassStrings:(NSArray *)classStrings name:(NSString *)name
{
for (id item in collection) {
BOOL validClass = NO;
for (NSString *classString in classStrings) {
if ([item isKindOfClass:NSClassFromString(classString)]) {
validClass = YES;
break;
}
}
if (!validClass) {
NSString *reason = [[NSString alloc] initWithFormat:
@"Invalid value found in %@: %@ - %@",
name,
item,
collection];
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:reason userInfo:nil];
}
}
}
+ (void)assertCollection:(id<NSFastEnumeration>)collection ofClass:itemClass name:(NSString *)name
{
for (id item in collection) {
@ -123,6 +147,12 @@
parameters = @{ @"href": linkContent.contentURL.absoluteString };
}
}
NSString *hashtagString = [self hashtagStringFromHashtag:content.hashtag];
if (hashtagString != nil) {
NSMutableDictionary *mutableParameters = [parameters mutableCopy];
[FBSDKInternalUtility dictionary:mutableParameters setObject:hashtagString forKey:@"hashtag"];
parameters = [mutableParameters copy];
}
if (methodNameRef != NULL) {
*methodNameRef = methodName;
}
@ -182,6 +212,7 @@
parameters = [[NSMutableDictionary alloc] initWithDictionary:linkContent.feedParameters];
[FBSDKInternalUtility dictionary:parameters setObject:linkContent.contentDescription forKey:@"description"];
[FBSDKInternalUtility dictionary:parameters setObject:linkContent.contentURL forKey:@"link"];
[FBSDKInternalUtility dictionary:parameters setObject:linkContent.quote forKey:@"quote"];
[FBSDKInternalUtility dictionary:parameters setObject:linkContent.contentTitle forKey:@"name"];
[FBSDKInternalUtility dictionary:parameters setObject:linkContent.imageURL forKey:@"picture"];
[FBSDKInternalUtility dictionary:parameters setObject:linkContent.ref forKey:@"ref"];
@ -189,6 +220,20 @@
return [parameters copy];
}
+ (NSString *)hashtagStringFromHashtag:(FBSDKHashtag *)hashtag
{
if (!hashtag) {
return nil;
}
if (hashtag.isValid) {
return hashtag.stringRepresentation;
} else {
[FBSDKLogger singleShotLogEntry:FBSDKLoggingBehaviorDeveloperErrors
formatString:@"Invalid hashtag: '%@'", hashtag.stringRepresentation];
return nil;
}
}
+ (NSDictionary *)parametersForShareContent:(id<FBSDKSharingContent>)shareContent
shouldFailOnDataError:(BOOL)shouldFailOnDataError
{
@ -210,23 +255,34 @@
+ (void)testShareContent:(id<FBSDKSharingContent>)shareContent
containsMedia:(BOOL *)containsMediaRef
containsPhotos:(BOOL *)containsPhotosRef
containsVideos:(BOOL *)containsVideosRef
{
BOOL containsMedia = NO;
BOOL containsPhotos = NO;
BOOL containsVideos = NO;
if ([shareContent isKindOfClass:[FBSDKShareLinkContent class]]) {
containsMedia = NO;
containsPhotos = NO;
containsVideos = NO;
} else if ([shareContent isKindOfClass:[FBSDKShareVideoContent class]]) {
containsMedia = YES;
containsVideos = YES;
containsPhotos = NO;
} else if ([shareContent isKindOfClass:[FBSDKSharePhotoContent class]]) {
[self _testObject:((FBSDKSharePhotoContent *)shareContent).photos
containsMedia:&containsMedia
containsPhotos:&containsPhotos];
containsPhotos:&containsPhotos
containsVideos:&containsVideos];
} else if ([shareContent isKindOfClass:[FBSDKShareMediaContent class]]) {
[self _testObject:((FBSDKShareMediaContent *)shareContent).media
containsMedia:&containsMedia
containsPhotos:&containsPhotos
containsVideos:&containsVideos];
} else if ([shareContent isKindOfClass:[FBSDKShareOpenGraphContent class]]) {
[self _testOpenGraphValueContainer:((FBSDKShareOpenGraphContent *)shareContent).action
containsMedia:&containsMedia
containsPhotos:&containsPhotos];
containsPhotos:&containsPhotos
containsVideos:&containsVideos];
}
if (containsMediaRef != NULL) {
*containsMediaRef = containsMedia;
@ -234,6 +290,9 @@
if (containsPhotosRef != NULL) {
*containsPhotosRef = containsPhotos;
}
if (containsVideosRef != NULL) {
*containsVideosRef = containsVideos;
}
}
#if !TARGET_OS_TV
@ -242,25 +301,77 @@
return ([self _validateRequiredValue:appInviteContent name:@"content" error:errorRef] &&
[self _validateRequiredValue:appInviteContent.appLinkURL name:@"appLinkURL" error:errorRef] &&
[self _validateNetworkURL:appInviteContent.appLinkURL name:@"appLinkURL" error:errorRef] &&
[self _validateNetworkURL:appInviteContent.appInvitePreviewImageURL name:@"appInvitePreviewImageURL" error:errorRef]);
[self _validateNetworkURL:appInviteContent.appInvitePreviewImageURL name:@"appInvitePreviewImageURL" error:errorRef] &&
[self validatePromoCodeWithError:appInviteContent error:errorRef]);
}
+ (BOOL)validatePromoCodeWithError:(FBSDKAppInviteContent *)appInviteContent error:(NSError *__autoreleasing *)errorRef
{
NSString *promoText = appInviteContent.promotionText;
NSString *promoCode = appInviteContent.promotionCode;
NSMutableCharacterSet *alphanumericWithSpaces = [NSMutableCharacterSet alphanumericCharacterSet];
[alphanumericWithSpaces formUnionWithCharacterSet:[NSCharacterSet whitespaceCharacterSet]];
if ([promoText length] > 0 || [promoCode length] > 0) {
// Check for validity of promo text and promo code.
if (!([promoText length] > 0 && [promoText length] <= 80)) {
if (errorRef != NULL) {
*errorRef = [FBSDKError invalidArgumentErrorWithName:@"promotionText" value:promoText message:@"Invalid value for promotionText, promotionText has to be between 1 and 80 characters long."];
}
return NO;
}
if (!([promoCode length] <= 10)) {
if (errorRef != NULL) {
*errorRef = [FBSDKError invalidArgumentErrorWithName:@"promotionCode" value:promoCode message:@"Invalid value for promotionCode, promotionCode has to be between 0 and 10 characters long and is required when promoCode is set."];
}
return NO;
}
if ([promoText rangeOfCharacterFromSet:[alphanumericWithSpaces invertedSet]].location != NSNotFound) {
if(errorRef != NULL) {
*errorRef = [FBSDKError invalidArgumentErrorWithName:@"promotionText" value:promoText message:@"Invalid value for promotionText, promotionText can contain only alphanumeric characters and spaces."];
}
return NO;
}
if ([promoCode length] > 0 && [promoCode rangeOfCharacterFromSet:[alphanumericWithSpaces invertedSet]].location != NSNotFound) {
if (errorRef != NULL) {
*errorRef = [FBSDKError invalidArgumentErrorWithName:@"promotionCode" value:promoCode message:@"Invalid value for promotionCode, promotionCode can contain only alphanumeric characters and spaces."];
}
return NO;
}
}
if (errorRef != NULL) {
*errorRef = nil;
}
return YES;
}
#endif
+ (BOOL)validateAssetLibraryURLWithShareVideoContent:(FBSDKShareVideoContent *)videoContent name:(NSString *)name error:(NSError *__autoreleasing *)errorRef
{
FBSDKShareVideo *video = videoContent.video;
NSURL *videoURL = video.videoURL;
if (!videoURL || [[videoURL.scheme lowercaseString] isEqualToString:@"assets-library"]) {
if (errorRef != NULL) {
*errorRef = nil;
return [self _validateAssetLibraryVideoURL:videoURL name:name error:errorRef];
}
+ (BOOL)validateAssetLibraryURLsWithShareMediaContent:(FBSDKShareMediaContent *)mediaContent name:(NSString *)name error:(NSError *__autoreleasing *)errorRef
{
for (id media in mediaContent.media) {
if ([media isKindOfClass:[FBSDKShareVideo class]]) {
FBSDKShareVideo *video = (FBSDKShareVideo *)media;
if (![self _validateAssetLibraryVideoURL:video.videoURL name:name error:errorRef]) {
return NO;
}
}
return YES;
} else {
if (errorRef != NULL) {
*errorRef = [FBSDKShareError invalidArgumentErrorWithName:name value:videoURL message:nil];
}
return NO;
}
return YES;
}
#if !TARGET_OS_TV
@ -344,6 +455,8 @@
return [self validateSharePhotoContent:(FBSDKSharePhotoContent *)shareContent error:errorRef];
} else if ([shareContent isKindOfClass:[FBSDKShareVideoContent class]]) {
return [self validateShareVideoContent:(FBSDKShareVideoContent *)shareContent error:errorRef];
} else if ([shareContent isKindOfClass:[FBSDKShareMediaContent class]]) {
return [self validateShareMediaContent:(FBSDKShareMediaContent *)shareContent error:errorRef];
} else if ([shareContent isKindOfClass:[FBSDKShareOpenGraphContent class]]) {
return [self validateShareOpenGraphContent:(FBSDKShareOpenGraphContent *)shareContent error:errorRef];
} else {
@ -386,6 +499,43 @@
return YES;
}
+ (BOOL)validateShareMediaContent:(FBSDKShareMediaContent *)mediaContent error:(NSError *__autoreleasing *)errorRef
{
NSArray *medias = mediaContent.media;
if (![self _validateRequiredValue:mediaContent name:@"shareContent" error:errorRef] ||
![self _validateArray:medias minCount:1 maxCount:20 name:@"photos" error:errorRef]) {
return NO;
}
for (id media in medias) {
if ([media isKindOfClass:[FBSDKSharePhoto class]]) {
FBSDKSharePhoto *photo = (FBSDKSharePhoto *)media;
if (!photo.image) {
if (errorRef != NULL) {
*errorRef = [FBSDKShareError invalidArgumentErrorWithName:@"media"
value:media
message:@"photos must have UIImages"];
}
return NO;
}
} else if ([media isKindOfClass:[FBSDKShareVideo class]]) {
FBSDKShareVideo *video = (FBSDKShareVideo *)media;
NSURL *videoURL = video.videoURL;
return ([self _validateRequiredValue:video name:@"video" error:errorRef] &&
[self _validateRequiredValue:videoURL name:@"videoURL" error:errorRef]);
} else {
if (errorRef != NULL) {
*errorRef = [FBSDKShareError invalidArgumentErrorWithName:@"media"
value:media
message:@"Only FBSDKSharePhoto and FBSDKShareVideo are allowed in `media` property"];
}
return NO;
}
}
return YES;
}
+ (BOOL)validateShareLinkContent:(FBSDKShareLinkContent *)linkContent error:(NSError *__autoreleasing *)errorRef
{
return ([self _validateRequiredValue:linkContent name:@"shareContent" error:errorRef] &&
@ -402,6 +552,14 @@
[self _validateRequiredValue:videoURL name:@"videoURL" error:errorRef]);
}
+ (BOOL)shareMediaContentContainsPhotosAndVideos:(FBSDKShareMediaContent *)shareMediaContent
{
BOOL containsPhotos = NO;
BOOL containsVideos = NO;
[self testShareContent:shareMediaContent containsMedia:NULL containsPhotos:&containsPhotos containsVideos:&containsVideos];
return containsVideos && containsPhotos;
}
#pragma mark - Object Lifecycle
- (instancetype)init
@ -414,6 +572,10 @@
+ (void)_addToParameters:(NSMutableDictionary *)parameters forShareContent:(id<FBSDKSharingContent>)shareContent
{
NSString *hashtagString = [self hashtagStringFromHashtag:shareContent.hashtag];
if (hashtagString != nil) {
[FBSDKInternalUtility dictionary:parameters setObject:@[hashtagString] forKey:@"hashtags"];
}
if ([shareContent isKindOfClass:[FBSDKShareOpenGraphContent class]]) {
FBSDKShareOpenGraphAction *action = ((FBSDKShareOpenGraphContent *)shareContent).action;
[action setArray:shareContent.peopleIDs forKey:@"tags"];
@ -565,25 +727,32 @@ forShareOpenGraphContent:(FBSDKShareOpenGraphContent *)openGraphContent
[value isKindOfClass:[FBSDKShareOpenGraphObject class]]);
}
+ (void)_testObject:(id)object containsMedia:(BOOL *)containsMediaRef containsPhotos:(BOOL *)containsPhotosRef
+ (void)_testObject:(id)object containsMedia:(BOOL *)containsMediaRef containsPhotos:(BOOL *)containsPhotosRef containsVideos:(BOOL *)containsVideosRef
{
BOOL containsMedia = NO;
BOOL containsPhotos = NO;
BOOL containsVideos = NO;
if ([object isKindOfClass:[FBSDKSharePhoto class]]) {
containsMedia = (((FBSDKSharePhoto *)object).image != nil);
containsPhotos = YES;
} else if ([object isKindOfClass:[FBSDKShareVideo class]]) {
containsMedia = YES;
containsVideos = YES;
} else if ([object isKindOfClass:[FBSDKShareOpenGraphValueContainer class]]) {
[self _testOpenGraphValueContainer:(FBSDKShareOpenGraphValueContainer *)object
containsMedia:&containsMedia
containsPhotos:&containsPhotos];
containsPhotos:&containsPhotos
containsVideos:&containsVideos];
} else if ([object isKindOfClass:[NSArray class]]) {
for (id item in (NSArray *)object) {
BOOL itemContainsMedia = NO;
BOOL itemContainsPhotos = NO;
[self _testObject:item containsMedia:&itemContainsMedia containsPhotos:&itemContainsPhotos];
BOOL itemContainsVideos = NO;
[self _testObject:item containsMedia:&itemContainsMedia containsPhotos:&itemContainsPhotos containsVideos:&itemContainsVideos];
containsMedia |= itemContainsMedia;
containsPhotos |= itemContainsPhotos;
if (containsMedia && containsPhotos) {
containsVideos |= itemContainsVideos;
if (containsMedia && containsPhotos && containsVideos) {
break;
}
}
@ -594,21 +763,28 @@ forShareOpenGraphContent:(FBSDKShareOpenGraphContent *)openGraphContent
if (containsPhotosRef != NULL) {
*containsPhotosRef = containsPhotos;
}
if (containsVideosRef != NULL) {
*containsVideosRef = containsVideos;
}
}
+ (void)_testOpenGraphValueContainer:(FBSDKShareOpenGraphValueContainer *)container
containsMedia:(BOOL *)containsMediaRef
containsPhotos:(BOOL *)containsPhotosRef
containsVideos:(BOOL *)containsVideosRef
{
__block BOOL containsMedia = NO;
__block BOOL containsPhotos = NO;
__block BOOL containsVideos = NO;
[container enumerateKeysAndObjectsUsingBlock:^(NSString *key, id object, BOOL *stop) {
BOOL itemContainsMedia = NO;
BOOL itemContainsPhotos = NO;
[self _testObject:object containsMedia:&itemContainsMedia containsPhotos:&itemContainsPhotos];
BOOL itemContainsVideos = NO;
[self _testObject:object containsMedia:&itemContainsMedia containsPhotos:&itemContainsPhotos containsVideos:&itemContainsVideos];
containsMedia |= itemContainsMedia;
containsPhotos |= itemContainsPhotos;
if (containsMedia && containsPhotos) {
containsVideos |= itemContainsVideos;
if (containsMedia && containsPhotos && containsVideosRef) {
*stop = YES;
}
}];
@ -618,6 +794,9 @@ forShareOpenGraphContent:(FBSDKShareOpenGraphContent *)openGraphContent
if (containsPhotosRef != NULL) {
*containsPhotosRef = containsPhotos;
}
if (containsVideosRef != NULL) {
*containsVideosRef = containsVideos;
}
}
+ (BOOL)_validateArray:(NSArray *)array
@ -729,4 +908,19 @@ forShareOpenGraphContent:(FBSDKShareOpenGraphContent *)openGraphContent
return NO;
}
+ (BOOL)_validateAssetLibraryVideoURL:(NSURL *)videoURL name:(NSString *)name error:(NSError *__autoreleasing *)errorRef
{
if (!videoURL || [[videoURL.scheme lowercaseString] isEqualToString:@"assets-library"]) {
if (errorRef != NULL) {
*errorRef = nil;
}
return YES;
} else {
if (errorRef != NULL) {
*errorRef = [FBSDKShareError invalidArgumentErrorWithName:name value:videoURL message:nil];
}
return NO;
}
}
@end

View File

@ -0,0 +1 @@
../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKAccessToken.h

View File

@ -0,0 +1 @@
../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/TokenCaching/FBSDKAccessTokenCache.h

View File

@ -0,0 +1 @@
../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/TokenCaching/FBSDKAccessTokenCacheV3.h

View File

@ -0,0 +1 @@
../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/TokenCaching/FBSDKAccessTokenCacheV3_17.h

View File

@ -0,0 +1 @@
../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/TokenCaching/FBSDKAccessTokenCacheV3_21.h

View File

@ -0,0 +1 @@
../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/TokenCaching/FBSDKAccessTokenCacheV4.h

View File

@ -0,0 +1 @@
../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/TokenCaching/FBSDKAccessTokenCaching.h

View File

@ -0,0 +1 @@
../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/AppEvents/FBSDKAppEvents+Internal.h

View File

@ -0,0 +1 @@
../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKAppEvents.h

View File

@ -0,0 +1 @@
../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/AppEvents/FBSDKAppEventsDeviceInfo.h

View File

@ -0,0 +1 @@
../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/AppEvents/FBSDKAppEventsState.h

View File

@ -0,0 +1 @@
../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/AppEvents/FBSDKAppEventsStateManager.h

View File

@ -0,0 +1 @@
../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/AppEvents/FBSDKAppEventsUtility.h

View File

@ -0,0 +1 @@
../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKAppLinkResolver.h

View File

@ -0,0 +1 @@
../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKAppLinkUtility.h

View File

@ -0,0 +1 @@
../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/FBSDKApplicationDelegate+Internal.h

View File

@ -0,0 +1 @@
../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKApplicationDelegate.h

View File

@ -0,0 +1 @@
../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/FBSDKAudioResourceLoader.h

View File

@ -0,0 +1 @@
../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/Base64/FBSDKBase64.h

View File

@ -0,0 +1 @@
../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/AppLink/FBSDKBoltsMeasurementEventListener.h

View File

@ -0,0 +1 @@
../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/BridgeAPI/FBSDKBridgeAPICrypto.h

View File

@ -0,0 +1 @@
../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/BridgeAPI/FBSDKBridgeAPIProtocol.h

View File

@ -0,0 +1 @@
../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/BridgeAPI/ProtocolVersions/FBSDKBridgeAPIProtocolNativeV1.h

View File

@ -0,0 +1 @@
../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/BridgeAPI/FBSDKBridgeAPIProtocolType.h

View File

@ -0,0 +1 @@
../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/BridgeAPI/ProtocolVersions/FBSDKBridgeAPIProtocolWebV1.h

View File

@ -0,0 +1 @@
../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/BridgeAPI/ProtocolVersions/FBSDKBridgeAPIProtocolWebV2.h

View File

@ -0,0 +1 @@
../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/BridgeAPI/FBSDKBridgeAPIRequest+Private.h

View File

@ -0,0 +1 @@
../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/BridgeAPI/FBSDKBridgeAPIRequest.h

View File

@ -0,0 +1 @@
../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/BridgeAPI/FBSDKBridgeAPIResponse.h

View File

@ -0,0 +1 @@
../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/UI/FBSDKButton+Subclass.h

View File

@ -0,0 +1 @@
../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKButton.h

View File

@ -0,0 +1 @@
../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/UI/FBSDKCloseIcon.h

View File

@ -0,0 +1 @@
../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/UI/FBSDKColor.h

View File

@ -0,0 +1 @@
../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKConstants.h

View File

@ -0,0 +1 @@
../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/FBSDKContainerViewController.h

View File

@ -0,0 +1 @@
../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKCopying.h

View File

@ -0,0 +1 @@
../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Internal/FBSDKCoreKit+Internal.h

View File

@ -0,0 +1 @@
../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit.h

View File

@ -1 +0,0 @@
../../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKAccessToken.h

View File

@ -1 +0,0 @@
../../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKAppEvents.h

View File

@ -1 +0,0 @@
../../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKAppLinkResolver.h

View File

@ -1 +0,0 @@
../../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKAppLinkUtility.h

View File

@ -1 +0,0 @@
../../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKApplicationDelegate.h

View File

@ -1 +0,0 @@
../../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKButton.h

View File

@ -1 +0,0 @@
../../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKConstants.h

View File

@ -1 +0,0 @@
../../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKCopying.h

View File

@ -1 +0,0 @@
../../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit.h

View File

@ -1 +0,0 @@
../../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKGraphErrorRecoveryProcessor.h

View File

@ -1 +0,0 @@
../../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKGraphRequest.h

View File

@ -1 +0,0 @@
../../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKGraphRequestConnection.h

View File

@ -1 +0,0 @@
../../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKGraphRequestDataAttachment.h

View File

@ -1 +0,0 @@
../../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKMacros.h

View File

@ -1 +0,0 @@
../../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKMutableCopying.h

View File

@ -1 +0,0 @@
../../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKProfile.h

View File

@ -1 +0,0 @@
../../../../FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/FBSDKProfilePictureView.h

Some files were not shown because too many files have changed in this diff Show More