Compare commits

..

No commits in common. "2.6.2" and "master" have entirely different histories.

441 changed files with 9691 additions and 19857 deletions

View File

@ -39,7 +39,7 @@
/* Begin PBXFileReference section */
0ABF8340F735722CEE937FA3 /* libPods-PNObject_Example.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-PNObject_Example.a"; sourceTree = BUILT_PRODUCTS_DIR; };
116AF818F8117B91EF290C9A /* Pods-PNObject_Example.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-PNObject_Example.release.xcconfig"; path = "Pods/Target Support Files/Pods-PNObject_Example/Pods-PNObject_Example.release.xcconfig"; sourceTree = "<group>"; };
2661CEE1F223361CD1DACC25 /* PNObject.podspec */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; name = PNObject.podspec; path = ../PNObject.podspec; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.ruby; };
2661CEE1F223361CD1DACC25 /* PNObject.podspec */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; name = PNObject.podspec; path = ../PNObject.podspec; sourceTree = "<group>"; };
3E392C278361604C1602CAF0 /* README.md */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = net.daringfireball.markdown; name = README.md; path = ../README.md; sourceTree = "<group>"; };
6003F58A195388D20070C39A /* PNObject_Example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = PNObject_Example.app; sourceTree = BUILT_PRODUCTS_DIR; };
6003F58D195388D20070C39A /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
@ -210,6 +210,7 @@
6003F586195388D20070C39A /* Sources */,
6003F587195388D20070C39A /* Frameworks */,
6003F588195388D20070C39A /* Resources */,
C40CC8D7B1996A567BE82827 /* [CP] Embed Pods Frameworks */,
614EA73ED5E0ED0F8684468C /* [CP] Copy Pods Resources */,
);
buildRules = (
@ -229,6 +230,8 @@
6003F5AA195388D20070C39A /* Sources */,
6003F5AB195388D20070C39A /* Frameworks */,
6003F5AC195388D20070C39A /* Resources */,
746A765B48FD98342716D81F /* [CP] Embed Pods Frameworks */,
21411FBE0FE21EC75B6AB1E3 /* [CP] Copy Pods Resources */,
);
buildRules = (
);
@ -304,6 +307,21 @@
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
21411FBE0FE21EC75B6AB1E3 /* [CP] Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "[CP] Copy Pods Resources";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-PNObject_Tests/Pods-PNObject_Tests-resources.sh\"\n";
showEnvVarsInLog = 0;
};
3FF38AA7E586B22171D1A118 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
@ -333,13 +351,43 @@
);
name = "[CP] Copy Pods Resources";
outputPaths = (
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/FacebookSDKStrings.bundle",
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-PNObject_Example/Pods-PNObject_Example-resources.sh\"\n";
showEnvVarsInLog = 0;
};
746A765B48FD98342716D81F /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "[CP] Embed Pods Frameworks";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-PNObject_Tests/Pods-PNObject_Tests-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
C40CC8D7B1996A567BE82827 /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "[CP] Embed Pods Frameworks";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-PNObject_Example/Pods-PNObject_Example-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
E4CE079F616C61EA34D08B8B /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;

View File

@ -1,8 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>

View File

@ -25,6 +25,7 @@
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
[FBSDKSettings setAppID:@"213761522305123"];
[[FBSDKApplicationDelegate sharedInstance] application:application didFinishLaunchingWithOptions:launchOptions];
@ -33,23 +34,21 @@
// Override point for customization after application launch.
[PNObjectConfig initSharedInstanceForEnvironments:@{EnvironmentDevelopment : @{BaseUrl:@"http://pnobject.local/",EndpointPath:@"api/v1/"},
EnvironmentStage : @{BaseUrl:@"https://pnobject.stage.it/",EndpointPath:@"api/v1/"},
EnvironmentStage : @{BaseUrl:@"http://pnobject.stage.it/",EndpointPath:@"api/v1/"},
EnvironmentProduction : @{BaseUrl:@"http://pnobject.prod.it/",EndpointPath:@"api/v1/"},
} userSubclass:[PNUser class] andStoreClientIdentifier:@"ftiuyvkbyfi789ptf78"];
} userSubclass:[PNUser class] withOauthMode:OAuthModeClientCredential];
/** Can user special char %@ to autoset EndpointPath to Oauth endpointPath */
[[PNObjectConfig sharedInstance] setClientID:@"******" clientSecret:@"******" oAuthEndpointAction:@"%@oauth-token" oauthMode:OAuthModeClientCredential refreshTokenEnabled:NO forEnv:EnvironmentStage];
[[PNObjectConfig sharedInstance] setClientID:@"******" clientSecret:@"******" oAuthEndpointAction:@"%@oauth-token" oauthMode:OAuthModePassword refreshTokenEnabled:NO forEnv:EnvironmentStage];
[[PNObjectConfig sharedInstance] setOauthUserName:@"admin" oauthPassword:@"admin" forEnv:EnvironmentStage];
[[PNObjectConfig sharedInstance] setClientID:@"xxxxxxxxx" clientSecret:@"xxxxxxxxxxxx" forEnv:EnvironmentStage];
[[PNObjectConfig sharedInstance] setClientID:@"xxxxxxxxx" clientSecret:@"xxxxxxxxxxxx" forEnv:EnvironmentProduction];
[[PNObjectConfig sharedInstance] setEnvironment:EnvironmentStage];
//[[PNObjectConfig sharedInstance] setHTTPHeaderValue:@"XMLHttpRequest" forKey:@"X-Request-With"];
NSLogDebug(@"%@",[[PNObjectConfig sharedInstance] baseUrl]);
NSLogDebug(@"%@",[[PNObjectConfig sharedInstance] endPointPath]);
NSLogDebug(@"%@",[[PNObjectConfig sharedInstance] endPointUrl]);
[[PNObjectConfig sharedInstance] loadManagersWithCredentials];
PNObjViewController *viewController = [[PNObjViewController alloc] init];

View File

@ -93,21 +93,11 @@
}
- (void) refreshTokenAction {
[[PNObjectConfig sharedInstance] refreshTokenForClientCredentialWithBlockSuccess:^(BOOL refreshSuccess) {
[PNUser loginCurrentUserWithUsername:@"test" password:@"test" withBlockSuccess:^(PNUser * _Nullable responseObject) {
NSLog(@"success");
} failure:^(NSError * _Nonnull error) {
NSLog(@"%@",error);
}];
} failure:^(NSError * _Nonnull error) {
}];
[[PNObjectConfig sharedInstance] refreshTokenForClientCredential];
}
- (void) cancelTokenAction {
[[PNObjectConfig sharedInstance] resetAllTokens];
[[PNObjectConfig sharedInstance] resetToken];
}
- (void) apiCallAction {

View File

@ -1,13 +1,13 @@
platform :ios, '9.0'
target 'PNObject_Example' do
pod 'PNObject', :path => '../'
pod 'PureLayout'
pod 'PNObject', :path => '../'
pod 'PureLayout'
target 'PNObject_Tests' do
target 'PNObject_Tests' do
inherit! :search_paths
pod 'Specta'
pod 'Expecta'
pod 'Expecta'
end
end

View File

@ -1,18 +1,18 @@
PODS:
- AFNetworking (3.2.1):
- AFNetworking/NSURLSession (= 3.2.1)
- AFNetworking/Reachability (= 3.2.1)
- AFNetworking/Security (= 3.2.1)
- AFNetworking/Serialization (= 3.2.1)
- AFNetworking/UIKit (= 3.2.1)
- AFNetworking/NSURLSession (3.2.1):
- AFNetworking (3.1.0):
- AFNetworking/NSURLSession (= 3.1.0)
- AFNetworking/Reachability (= 3.1.0)
- AFNetworking/Security (= 3.1.0)
- AFNetworking/Serialization (= 3.1.0)
- AFNetworking/UIKit (= 3.1.0)
- AFNetworking/NSURLSession (3.1.0):
- AFNetworking/Reachability
- AFNetworking/Security
- AFNetworking/Serialization
- AFNetworking/Reachability (3.2.1)
- AFNetworking/Security (3.2.1)
- AFNetworking/Serialization (3.2.1)
- AFNetworking/UIKit (3.2.1):
- AFNetworking/Reachability (3.1.0)
- AFNetworking/Security (3.1.0)
- AFNetworking/Serialization (3.1.0)
- AFNetworking/UIKit (3.1.0):
- AFNetworking/NSURLSession
- Bolts (1.9.0):
- Bolts/AppLinks (= 1.9.0)
@ -26,37 +26,24 @@ PODS:
- DJLocalization/Core (= 1.2.2)
- DJLocalization/Core (1.2.2)
- Expecta (1.0.6)
- FacebookSDK (4.38.0):
- Bolts (~> 1.9)
- FacebookSDK/CoreKit (= 4.38.0)
- FacebookSDK/MarketingKit (= 4.38.0)
- FacebookSDK/CoreKit (4.38.0):
- Bolts (~> 1.9)
- FBSDKCoreKit (4.29.0):
- Bolts (~> 1.7)
- FBSDKLoginKit (4.29.0):
- FBSDKCoreKit
- FacebookSDK/MarketingKit (4.38.0):
- Bolts (~> 1.9)
- FacebookSDK/CoreKit
- FBSDKMarketingKit
- FBSDKCoreKit (4.39.0):
- Bolts (~> 1.9)
- FBSDKLoginKit (4.39.0):
- FBSDKCoreKit
- FBSDKMarketingKit (4.38.0):
- FBSDKCoreKit
- FBSDKShareKit (4.39.0):
- FBSDKShareKit (4.29.0):
- FBSDKCoreKit
- NSDataAES (0.2.2)
- NSDate_Utils (1.1.0):
- DJLocalization
- NSString-Helper (1.2.0)
- NSString-Helper (1.0.5)
- nv-ios-http-status (0.0.1)
- PEAR-FileManager-iOS (1.3.1)
- PNObject (2.6.1):
- PNObject (1.3.4):
- AFNetworking
- CodFis-Helper
- DDDKeychainWrapper
- DJLocalization
- FacebookSDK
- FBSDKCoreKit
- FBSDKLoginKit
- FBSDKShareKit
- NSDataAES
@ -67,11 +54,11 @@ PODS:
- RZDataBinding
- StrongestPasswordValidator
- UIDevice-Utils
- PureLayout (3.1.4)
- RZDataBinding (2.1.1)
- PureLayout (3.0.2)
- RZDataBinding (2.1.0)
- Specta (1.0.7)
- StrongestPasswordValidator (0.1.2)
- UIDevice-Utils (1.0.9)
- UIDevice-Utils (1.0.0)
DEPENDENCIES:
- Expecta
@ -79,58 +66,32 @@ DEPENDENCIES:
- PureLayout
- Specta
SPEC REPOS:
https://github.com/cocoapods/specs.git:
- AFNetworking
- Bolts
- CodFis-Helper
- DDDKeychainWrapper
- DJLocalization
- Expecta
- FacebookSDK
- FBSDKCoreKit
- FBSDKLoginKit
- FBSDKMarketingKit
- FBSDKShareKit
- NSDataAES
- NSDate_Utils
- NSString-Helper
- nv-ios-http-status
- PEAR-FileManager-iOS
- PureLayout
- RZDataBinding
- Specta
- StrongestPasswordValidator
- UIDevice-Utils
EXTERNAL SOURCES:
PNObject:
:path: "../"
:path: ../
SPEC CHECKSUMS:
AFNetworking: b6f891fdfaed196b46c7a83cf209e09697b94057
AFNetworking: 5e0e199f73d8626b11e79750991f5d173d1f8b67
Bolts: ac6567323eac61e203f6a9763667d0f711be34c8
CodFis-Helper: 28be4c74d7202542459d72354f59b1215871de87
DDDKeychainWrapper: e681a4daba6448786fa83b4941f58102a33b1897
DJLocalization: 0c84029af375647d4104a42ae36be87194c46c47
Expecta: 3b6bd90a64b9a1dcb0b70aa0e10a7f8f631667d5
FacebookSDK: 73f54b8b94e09b05647cdef0af147f470cd3edc6
FBSDKCoreKit: 1e3981faefab8c88edfaa9eecd94aab02d99a9bc
FBSDKLoginKit: 30ba5039a2c53d65a75103889bc2deebdacd5a1f
FBSDKMarketingKit: e609f39d74ab273cf52e2f8b7e8829ed412b2827
FBSDKShareKit: 5a0021c30abb64df9eeba87351dd8a627874543b
FBSDKCoreKit: 6f139173dc63a1deaff4430a55f2fe5bb222d2af
FBSDKLoginKit: 56a057ca6822535ea0faa25f57a7c41edb697fd4
FBSDKShareKit: 18a2cd118aef11dd657fe7e8b64bae5c719088b2
NSDataAES: 967ea3337476a80e9838a533c25d570a06855ed0
NSDate_Utils: c858a89da6e204ecf53aca48dbccb4da4d25bc9e
NSString-Helper: 1c259caa6c845e79e0bb45ee25e34f95d86d2317
NSString-Helper: 459e1b6a62b3bf7db10f01b0d102548608e945c4
nv-ios-http-status: b6c2b5fc8656cc19e0d3000dadce2080b99d0e2f
PEAR-FileManager-iOS: 3bc403f68a53483f5629aa822f4649e40275c4d3
PNObject: 4dd707682a5933f247091a23e39bf9688ea7e367
PureLayout: f08c01b8dec00bb14a1fefa3de4c7d9c265df85e
RZDataBinding: 289e2fbdce8b9585afef69def83425c5d380ffbd
PNObject: 8dc560680a7a48060ed309b019ca4fc41505cc07
PureLayout: 4d550abe49a94f24c2808b9b95db9131685fe4cd
RZDataBinding: 6981e90ddaae2f5e02028323b1043f8c31013109
Specta: 3e1bd89c3517421982dc4d1c992503e48bd5fe66
StrongestPasswordValidator: 921e42615bdf353513c6f925bffd4fc29865dbd7
UIDevice-Utils: 6ba44475416a1e823f214a8ed26fc9a0761db096
UIDevice-Utils: ff37bd042127117572d6ce4c5ff074f4f54ab5ed
PODFILE CHECKSUM: eec9c921f7aee591fd1fdea1fd3e5a191b74a436
PODFILE CHECKSUM: fcd5d1cf3426c7c9c5b3e5edcd4b8e5402ee7f2e
COCOAPODS: 1.5.3
COCOAPODS: 1.3.1

View File

@ -1,37 +0,0 @@
// AFCompatibilityMacros.h
// Copyright (c) 20112016 Alamofire Software Foundation ( http://alamofire.org/ )
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission 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.
#ifndef AFCompatibilityMacros_h
#define AFCompatibilityMacros_h
#ifdef API_UNAVAILABLE
#define AF_API_UNAVAILABLE(x) API_UNAVAILABLE(x)
#else
#define AF_API_UNAVAILABLE(x)
#endif // API_UNAVAILABLE
#if __has_warning("-Wunguarded-availability-new")
#define AF_CAN_USE_AT_AVAILABLE 1
#else
#define AF_CAN_USE_AT_AVAILABLE 0
#endif
#endif /* AFCompatibilityMacros_h */

View File

@ -44,7 +44,7 @@
## Methods to Override
To change the behavior of all data task operation construction, which is also used in the `GET` / `POST` / et al. convenience methods, override `dataTaskWithRequest:uploadProgress:downloadProgress:completionHandler:`.
To change the behavior of all data task operation construction, which is also used in the `GET` / `POST` / et al. convenience methods, override `dataTaskWithRequest:completionHandler:`.
## Serialization
@ -94,15 +94,6 @@ NS_ASSUME_NONNULL_BEGIN
*/
@property (nonatomic, strong) AFHTTPResponseSerializer <AFURLResponseSerialization> * responseSerializer;
///-------------------------------
/// @name Managing Security Policy
///-------------------------------
/**
The security policy used by created session to evaluate server trust for secure connections. `AFURLSessionManager` uses the `defaultPolicy` unless otherwise specified. A security policy configured with `AFSSLPinningModePublicKey` or `AFSSLPinningModeCertificate` can only be applied on a session manager initialized with a secure base URL (i.e. https). Applying a security policy with pinning enabled on an insecure session manager throws an `Invalid Security Policy` exception.
*/
@property (nonatomic, strong) AFSecurityPolicy *securityPolicy;
///---------------------
/// @name Initialization
///---------------------

View File

@ -98,23 +98,6 @@
[super setResponseSerializer:responseSerializer];
}
@dynamic securityPolicy;
- (void)setSecurityPolicy:(AFSecurityPolicy *)securityPolicy {
if (securityPolicy.SSLPinningMode != AFSSLPinningModeNone && ![self.baseURL.scheme isEqualToString:@"https"]) {
NSString *pinningMode = @"Unknown Pinning Mode";
switch (securityPolicy.SSLPinningMode) {
case AFSSLPinningModeNone: pinningMode = @"AFSSLPinningModeNone"; break;
case AFSSLPinningModeCertificate: pinningMode = @"AFSSLPinningModeCertificate"; break;
case AFSSLPinningModePublicKey: pinningMode = @"AFSSLPinningModePublicKey"; break;
}
NSString *reason = [NSString stringWithFormat:@"A security policy configured with `%@` can only be applied on a manager with a secure base URL (i.e. https)", pinningMode];
@throw [NSException exceptionWithName:@"Invalid Security Policy" reason:reason userInfo:nil];
}
[super setSecurityPolicy:securityPolicy];
}
#pragma mark -
- (NSURLSessionDataTask *)GET:(NSString *)URLString
@ -203,9 +186,12 @@
NSMutableURLRequest *request = [self.requestSerializer multipartFormRequestWithMethod:@"POST" URLString:[[NSURL URLWithString:URLString relativeToURL:self.baseURL] absoluteString] parameters:parameters constructingBodyWithBlock:block error:&serializationError];
if (serializationError) {
if (failure) {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wgnu"
dispatch_async(self.completionQueue ?: dispatch_get_main_queue(), ^{
failure(nil, serializationError);
});
#pragma clang diagnostic pop
}
return nil;
@ -276,9 +262,12 @@
NSMutableURLRequest *request = [self.requestSerializer requestWithMethod:method URLString:[[NSURL URLWithString:URLString relativeToURL:self.baseURL] absoluteString] parameters:parameters error:&serializationError];
if (serializationError) {
if (failure) {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wgnu"
dispatch_async(self.completionQueue ?: dispatch_get_main_queue(), ^{
failure(nil, serializationError);
});
#pragma clang diagnostic pop
}
return nil;

View File

@ -107,16 +107,6 @@ NS_ASSUME_NONNULL_BEGIN
*/
- (instancetype)initWithReachability:(SCNetworkReachabilityRef)reachability NS_DESIGNATED_INITIALIZER;
/**
* Unavailable initializer
*/
+ (instancetype)new NS_UNAVAILABLE;
/**
* Unavailable initializer
*/
- (instancetype)init NS_UNAVAILABLE;
///--------------------------------------------------
/// @name Starting & Stopping Reachability Monitoring
///--------------------------------------------------

View File

@ -170,11 +170,8 @@ static void AFNetworkReachabilityReleaseCallback(const void *info) {
return self;
}
- (instancetype)init
- (instancetype)init NS_UNAVAILABLE
{
@throw [NSException exceptionWithName:NSGenericException
reason:@"`-init` unavailable. Use `-initWithReachability:` instead"
userInfo:nil];
return nil;
}

View File

@ -51,6 +51,8 @@ static BOOL AFSecKeyIsEqualToKey(SecKeyRef key1, SecKeyRef key2) {
static id AFPublicKeyForCertificate(NSData *certificate) {
id allowedPublicKey = nil;
SecCertificateRef allowedCertificate;
SecCertificateRef allowedCertificates[1];
CFArrayRef tempCertificates = nil;
SecPolicyRef policy = nil;
SecTrustRef allowedTrust = nil;
SecTrustResultType result;
@ -58,8 +60,11 @@ static id AFPublicKeyForCertificate(NSData *certificate) {
allowedCertificate = SecCertificateCreateWithData(NULL, (__bridge CFDataRef)certificate);
__Require_Quiet(allowedCertificate != NULL, _out);
allowedCertificates[0] = allowedCertificate;
tempCertificates = CFArrayCreate(NULL, (const void **)allowedCertificates, 1, NULL);
policy = SecPolicyCreateBasicX509();
__Require_noErr_Quiet(SecTrustCreateWithCertificates(allowedCertificate, policy, &allowedTrust), _out);
__Require_noErr_Quiet(SecTrustCreateWithCertificates(tempCertificates, policy, &allowedTrust), _out);
__Require_noErr_Quiet(SecTrustEvaluate(allowedTrust, &result), _out);
allowedPublicKey = (__bridge_transfer id)SecTrustCopyPublicKey(allowedTrust);
@ -73,6 +78,10 @@ _out:
CFRelease(policy);
}
if (tempCertificates) {
CFRelease(tempCertificates);
}
if (allowedCertificate) {
CFRelease(allowedCertificate);
}

View File

@ -60,7 +60,10 @@ NSString * AFPercentEscapedStringFromString(NSString *string) {
NSMutableString *escaped = @"".mutableCopy;
while (index < string.length) {
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wgnu"
NSUInteger length = MIN(string.length - index, batchSize);
#pragma GCC diagnostic pop
NSRange range = NSMakeRange(index, length);
// To avoid breaking up character sequences such as 👴🏻👮🏽
@ -186,7 +189,6 @@ static void *AFHTTPRequestSerializerObserverContext = &AFHTTPRequestSerializerOb
@interface AFHTTPRequestSerializer ()
@property (readwrite, nonatomic, strong) NSMutableSet *mutableObservedChangedKeyPaths;
@property (readwrite, nonatomic, strong) NSMutableDictionary *mutableHTTPRequestHeaders;
@property (readwrite, nonatomic, strong) dispatch_queue_t requestHeaderModificationQueue;
@property (readwrite, nonatomic, assign) AFHTTPRequestQueryStringSerializationStyle queryStringSerializationStyle;
@property (readwrite, nonatomic, copy) AFQueryStringSerializationBlock queryStringSerialization;
@end
@ -206,7 +208,6 @@ static void *AFHTTPRequestSerializerObserverContext = &AFHTTPRequestSerializerOb
self.stringEncoding = NSUTF8StringEncoding;
self.mutableHTTPRequestHeaders = [NSMutableDictionary dictionary];
self.requestHeaderModificationQueue = dispatch_queue_create("requestHeaderModificationQueue", DISPATCH_QUEUE_CONCURRENT);
// Accept-Language HTTP Header; see http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.4
NSMutableArray *acceptLanguagesComponents = [NSMutableArray array];
@ -218,6 +219,8 @@ static void *AFHTTPRequestSerializerObserverContext = &AFHTTPRequestSerializerOb
[self setValue:[acceptLanguagesComponents componentsJoinedByString:@", "] forHTTPHeaderField:@"Accept-Language"];
NSString *userAgent = nil;
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wgnu"
#if TARGET_OS_IOS
// User-Agent Header; see http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.43
userAgent = [NSString stringWithFormat:@"%@/%@ (%@; iOS %@; Scale/%0.2f)", [[NSBundle mainBundle] infoDictionary][(__bridge NSString *)kCFBundleExecutableKey] ?: [[NSBundle mainBundle] infoDictionary][(__bridge NSString *)kCFBundleIdentifierKey], [[NSBundle mainBundle] infoDictionary][@"CFBundleShortVersionString"] ?: [[NSBundle mainBundle] infoDictionary][(__bridge NSString *)kCFBundleVersionKey], [[UIDevice currentDevice] model], [[UIDevice currentDevice] systemVersion], [[UIScreen mainScreen] scale]];
@ -227,6 +230,7 @@ static void *AFHTTPRequestSerializerObserverContext = &AFHTTPRequestSerializerOb
#elif defined(__MAC_OS_X_VERSION_MIN_REQUIRED)
userAgent = [NSString stringWithFormat:@"%@/%@ (Mac OS X %@)", [[NSBundle mainBundle] infoDictionary][(__bridge NSString *)kCFBundleExecutableKey] ?: [[NSBundle mainBundle] infoDictionary][(__bridge NSString *)kCFBundleIdentifierKey], [[NSBundle mainBundle] infoDictionary][@"CFBundleShortVersionString"] ?: [[NSBundle mainBundle] infoDictionary][(__bridge NSString *)kCFBundleVersionKey], [[NSProcessInfo processInfo] operatingSystemVersionString]];
#endif
#pragma clang diagnostic pop
if (userAgent) {
if (![userAgent canBeConvertedToEncoding:NSASCIIStringEncoding]) {
NSMutableString *mutableUserAgent = [userAgent mutableCopy];
@ -302,27 +306,17 @@ static void *AFHTTPRequestSerializerObserverContext = &AFHTTPRequestSerializerOb
#pragma mark -
- (NSDictionary *)HTTPRequestHeaders {
NSDictionary __block *value;
dispatch_sync(self.requestHeaderModificationQueue, ^{
value = [NSDictionary dictionaryWithDictionary:self.mutableHTTPRequestHeaders];
});
return value;
return [NSDictionary dictionaryWithDictionary:self.mutableHTTPRequestHeaders];
}
- (void)setValue:(NSString *)value
forHTTPHeaderField:(NSString *)field
{
dispatch_barrier_async(self.requestHeaderModificationQueue, ^{
[self.mutableHTTPRequestHeaders setValue:value forKey:field];
});
[self.mutableHTTPRequestHeaders setValue:value forKey:field];
}
- (NSString *)valueForHTTPHeaderField:(NSString *)field {
NSString __block *value;
dispatch_sync(self.requestHeaderModificationQueue, ^{
value = [self.mutableHTTPRequestHeaders valueForKey:field];
});
return value;
return [self.mutableHTTPRequestHeaders valueForKey:field];
}
- (void)setAuthorizationHeaderFieldWithUsername:(NSString *)username
@ -334,9 +328,7 @@ forHTTPHeaderField:(NSString *)field
}
- (void)clearAuthorizationHeader {
dispatch_barrier_async(self.requestHeaderModificationQueue, ^{
[self.mutableHTTPRequestHeaders removeObjectForKey:@"Authorization"];
});
[self.mutableHTTPRequestHeaders removeObjectForKey:@"Authorization"];
}
#pragma mark -
@ -568,9 +560,7 @@ forHTTPHeaderField:(NSString *)field
}
- (void)encodeWithCoder:(NSCoder *)coder {
dispatch_sync(self.requestHeaderModificationQueue, ^{
[coder encodeObject:self.mutableHTTPRequestHeaders forKey:NSStringFromSelector(@selector(mutableHTTPRequestHeaders))];
});
[coder encodeObject:self.mutableHTTPRequestHeaders forKey:NSStringFromSelector(@selector(mutableHTTPRequestHeaders))];
[coder encodeInteger:self.queryStringSerializationStyle forKey:NSStringFromSelector(@selector(queryStringSerializationStyle))];
}
@ -578,9 +568,7 @@ forHTTPHeaderField:(NSString *)field
- (instancetype)copyWithZone:(NSZone *)zone {
AFHTTPRequestSerializer *serializer = [[[self class] allocWithZone:zone] init];
dispatch_sync(self.requestHeaderModificationQueue, ^{
serializer.mutableHTTPRequestHeaders = [self.mutableHTTPRequestHeaders mutableCopyWithZone:zone];
});
serializer.mutableHTTPRequestHeaders = [self.mutableHTTPRequestHeaders mutableCopyWithZone:zone];
serializer.queryStringSerializationStyle = self.queryStringSerializationStyle;
serializer.queryStringSerialization = self.queryStringSerialization;
@ -679,11 +667,6 @@ NSTimeInterval const kAFUploadStream3GSuggestedDelay = 0.2;
return self;
}
- (void)setRequest:(NSMutableURLRequest *)request
{
_request = [request mutableCopy];
}
- (BOOL)appendPartWithFileURL:(NSURL *)fileURL
name:(NSString *)name
error:(NSError * __autoreleasing *)error
@ -852,11 +835,14 @@ NSTimeInterval const kAFUploadStream3GSuggestedDelay = 0.2;
@end
@implementation AFMultipartBodyStream
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wimplicit-atomic-properties"
#if (defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 80000) || (defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && __MAC_OS_X_VERSION_MAX_ALLOWED >= 1100)
@synthesize delegate;
#endif
@synthesize streamStatus;
@synthesize streamError;
#pragma clang diagnostic pop
- (instancetype)initWithStringEncoding:(NSStringEncoding)encoding {
self = [super init];
@ -902,6 +888,8 @@ NSTimeInterval const kAFUploadStream3GSuggestedDelay = 0.2;
NSInteger totalNumberOfBytesRead = 0;
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wgnu"
while ((NSUInteger)totalNumberOfBytesRead < MIN(length, self.numberOfBytesInPacket)) {
if (!self.currentHTTPBodyPart || ![self.currentHTTPBodyPart hasBytesAvailable]) {
if (!(self.currentHTTPBodyPart = [self.HTTPBodyPartEnumerator nextObject])) {
@ -922,6 +910,7 @@ NSTimeInterval const kAFUploadStream3GSuggestedDelay = 0.2;
}
}
}
#pragma clang diagnostic pop
return totalNumberOfBytesRead;
}
@ -1102,6 +1091,8 @@ typedef enum {
return YES;
}
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wcovered-switch-default"
switch (self.inputStream.streamStatus) {
case NSStreamStatusNotOpen:
case NSStreamStatusOpening:
@ -1115,6 +1106,7 @@ typedef enum {
default:
return NO;
}
#pragma clang diagnostic pop
}
- (NSInteger)read:(uint8_t *)buffer
@ -1159,8 +1151,11 @@ typedef enum {
intoBuffer:(uint8_t *)buffer
maxLength:(NSUInteger)length
{
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wgnu"
NSRange range = NSMakeRange((NSUInteger)_phaseReadOffset, MIN([data length] - ((NSUInteger)_phaseReadOffset), length));
[data getBytes:buffer range:range];
#pragma clang diagnostic pop
_phaseReadOffset += range.length;
@ -1179,6 +1174,8 @@ typedef enum {
return YES;
}
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wcovered-switch-default"
switch (_phase) {
case AFEncapsulationBoundaryPhase:
_phase = AFHeaderPhase;
@ -1198,6 +1195,7 @@ typedef enum {
break;
}
_phaseReadOffset = 0;
#pragma clang diagnostic pop
return YES;
}
@ -1259,21 +1257,7 @@ typedef enum {
[mutableRequest setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
}
if (![NSJSONSerialization isValidJSONObject:parameters]) {
if (error) {
NSDictionary *userInfo = @{NSLocalizedFailureReasonErrorKey: NSLocalizedStringFromTable(@"The `parameters` argument is not valid JSON.", @"AFNetworking", nil)};
*error = [[NSError alloc] initWithDomain:AFURLRequestSerializationErrorDomain code:NSURLErrorCannotDecodeContentData userInfo:userInfo];
}
return nil;
}
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:parameters options:self.writingOptions error:error];
if (!jsonData) {
return nil;
}
[mutableRequest setHTTPBody:jsonData];
[mutableRequest setHTTPBody:[NSJSONSerialization dataWithJSONObject:parameters options:self.writingOptions error:error]];
}
return mutableRequest;
@ -1352,13 +1336,7 @@ typedef enum {
[mutableRequest setValue:@"application/x-plist" forHTTPHeaderField:@"Content-Type"];
}
NSData *plistData = [NSPropertyListSerialization dataWithPropertyList:parameters format:self.format options:self.writeOptions error:error];
if (!plistData) {
return nil;
}
[mutableRequest setHTTPBody:plistData];
[mutableRequest setHTTPBody:[NSPropertyListSerialization dataWithPropertyList:parameters format:self.format options:self.writeOptions error:error]];
}
return mutableRequest;

View File

@ -57,7 +57,10 @@ NS_ASSUME_NONNULL_BEGIN
- (instancetype)init;
@property (nonatomic, assign) NSStringEncoding stringEncoding DEPRECATED_MSG_ATTRIBUTE("The string encoding is never used. AFHTTPResponseSerializer only validates status codes and content types but does not try to decode the received data in any way.");
/**
The string encoding used to serialize data received from the server, when no string encoding is specified by the response. `NSUTF8StringEncoding` by default.
*/
@property (nonatomic, assign) NSStringEncoding stringEncoding;
/**
Creates and returns a serializer with default configuration.
@ -108,8 +111,6 @@ NS_ASSUME_NONNULL_BEGIN
- `application/json`
- `text/json`
- `text/javascript`
In RFC 7159 - Section 8.1, it states that JSON text is required to be encoded in UTF-8, UTF-16, or UTF-32, and the default encoding is UTF-8. NSJSONSerialization provides support for all the encodings listed in the specification, and recommends UTF-8 for efficiency. Using an unsupported encoding will result in serialization error. See the `NSJSONSerialization` documentation for more details.
*/
@interface AFJSONResponseSerializer : AFHTTPResponseSerializer
@ -165,7 +166,7 @@ NS_ASSUME_NONNULL_BEGIN
- (instancetype)init;
/**
Input and output options specifically intended for `NSXMLDocument` objects. For possible values, see the `NSXMLDocument` documentation section "Input and Output Options". `0` by default.
Input and output options specifically intended for `NSXMLDocument` objects. For possible values, see the `NSJSONSerialization` documentation section "NSJSONReadingOptions". `0` by default.
*/
@property (nonatomic, assign) NSUInteger options;

View File

@ -97,6 +97,8 @@ static id AFJSONObjectByRemovingKeysWithNullValues(id JSONObject, NSJSONReadingO
return nil;
}
self.stringEncoding = NSUTF8StringEncoding;
self.acceptableStatusCodes = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(200, 100)];
self.acceptableContentTypes = nil;
@ -240,28 +242,23 @@ static id AFJSONObjectByRemovingKeysWithNullValues(id JSONObject, NSJSONReadingO
}
}
id responseObject = nil;
NSError *serializationError = nil;
// Workaround for behavior of Rails to return a single space for `head :ok` (a workaround for a bug in Safari), which is not interpreted as valid input by NSJSONSerialization.
// See https://github.com/rails/rails/issues/1742
BOOL isSpace = [data isEqualToData:[NSData dataWithBytes:" " length:1]];
if (data.length == 0 || isSpace) {
if (data.length > 0 && !isSpace) {
responseObject = [NSJSONSerialization JSONObjectWithData:data options:self.readingOptions error:&serializationError];
} else {
return nil;
}
NSError *serializationError = nil;
id responseObject = [NSJSONSerialization JSONObjectWithData:data options:self.readingOptions error:&serializationError];
if (!responseObject)
{
if (error) {
*error = AFErrorWithUnderlyingError(serializationError, *error);
}
return nil;
if (self.removesKeysWithNullValues && responseObject) {
responseObject = AFJSONObjectByRemovingKeysWithNullValues(responseObject, self.readingOptions);
}
if (self.removesKeysWithNullValues) {
return AFJSONObjectByRemovingKeysWithNullValues(responseObject, self.readingOptions);
if (error) {
*error = AFErrorWithUnderlyingError(serializationError, *error);
}
return responseObject;
@ -291,7 +288,7 @@ static id AFJSONObjectByRemovingKeysWithNullValues(id JSONObject, NSJSONReadingO
#pragma mark - NSCopying
- (instancetype)copyWithZone:(NSZone *)zone {
AFJSONResponseSerializer *serializer = [super copyWithZone:zone];
AFJSONResponseSerializer *serializer = [[[self class] allocWithZone:zone] init];
serializer.readingOptions = self.readingOptions;
serializer.removesKeysWithNullValues = self.removesKeysWithNullValues;
@ -381,12 +378,8 @@ static id AFJSONObjectByRemovingKeysWithNullValues(id JSONObject, NSJSONReadingO
NSError *serializationError = nil;
NSXMLDocument *document = [[NSXMLDocument alloc] initWithData:data options:self.options error:&serializationError];
if (!document)
{
if (error) {
*error = AFErrorWithUnderlyingError(serializationError, *error);
}
return nil;
if (error) {
*error = AFErrorWithUnderlyingError(serializationError, *error);
}
return document;
@ -414,7 +407,7 @@ static id AFJSONObjectByRemovingKeysWithNullValues(id JSONObject, NSJSONReadingO
#pragma mark - NSCopying
- (instancetype)copyWithZone:(NSZone *)zone {
AFXMLDocumentResponseSerializer *serializer = [super copyWithZone:zone];
AFXMLDocumentResponseSerializer *serializer = [[[self class] allocWithZone:zone] init];
serializer.options = self.options;
return serializer;
@ -465,20 +458,15 @@ static id AFJSONObjectByRemovingKeysWithNullValues(id JSONObject, NSJSONReadingO
}
}
if (!data) {
return nil;
}
id responseObject;
NSError *serializationError = nil;
id responseObject = [NSPropertyListSerialization propertyListWithData:data options:self.readOptions format:NULL error:&serializationError];
if (data) {
responseObject = [NSPropertyListSerialization propertyListWithData:data options:self.readOptions format:NULL error:&serializationError];
}
if (!responseObject)
{
if (error) {
*error = AFErrorWithUnderlyingError(serializationError, *error);
}
return nil;
if (error) {
*error = AFErrorWithUnderlyingError(serializationError, *error);
}
return responseObject;
@ -508,7 +496,7 @@ static id AFJSONObjectByRemovingKeysWithNullValues(id JSONObject, NSJSONReadingO
#pragma mark - NSCopying
- (instancetype)copyWithZone:(NSZone *)zone {
AFPropertyListResponseSerializer *serializer = [super copyWithZone:zone];
AFPropertyListResponseSerializer *serializer = [[[self class] allocWithZone:zone] init];
serializer.format = self.format;
serializer.readOptions = self.readOptions;
@ -734,7 +722,7 @@ static UIImage * AFInflatedImageFromResponseWithDataAtScale(NSHTTPURLResponse *r
#pragma mark - NSCopying
- (instancetype)copyWithZone:(NSZone *)zone {
AFImageResponseSerializer *serializer = [super copyWithZone:zone];
AFImageResponseSerializer *serializer = [[[self class] allocWithZone:zone] init];
#if TARGET_OS_IOS || TARGET_OS_TV || TARGET_OS_WATCH
serializer.imageScale = self.imageScale;
@ -808,7 +796,7 @@ static UIImage * AFInflatedImageFromResponseWithDataAtScale(NSHTTPURLResponse *r
#pragma mark - NSCopying
- (instancetype)copyWithZone:(NSZone *)zone {
AFCompoundResponseSerializer *serializer = [super copyWithZone:zone];
AFCompoundResponseSerializer *serializer = [[[self class] allocWithZone:zone] init];
serializer.responseSerializers = self.responseSerializers;
return serializer;

View File

@ -25,7 +25,6 @@
#import "AFURLResponseSerialization.h"
#import "AFURLRequestSerialization.h"
#import "AFSecurityPolicy.h"
#import "AFCompatibilityMacros.h"
#if !TARGET_OS_WATCH
#import "AFNetworkReachabilityManager.h"
#endif
@ -209,7 +208,7 @@ NS_ASSUME_NONNULL_BEGIN
@param completionHandler A block object to be executed when the task finishes. This block has no return value and takes three arguments: the server response, the response object created by that serializer, and the error that occurred, if any.
*/
- (NSURLSessionDataTask *)dataTaskWithRequest:(NSURLRequest *)request
completionHandler:(nullable void (^)(NSURLResponse *response, id _Nullable responseObject, NSError * _Nullable error))completionHandler DEPRECATED_ATTRIBUTE;
completionHandler:(nullable void (^)(NSURLResponse *response, id _Nullable responseObject, NSError * _Nullable error))completionHandler;
/**
Creates an `NSURLSessionDataTask` with the specified request.
@ -355,7 +354,7 @@ NS_ASSUME_NONNULL_BEGIN
@param block A block object to be executed when an HTTP request is attempting to perform a redirection to a different URL. The block returns the request to be made for the redirection, and takes four arguments: the session, the task, the redirection response, and the request corresponding to the redirection response.
*/
- (void)setTaskWillPerformHTTPRedirectionBlock:(nullable NSURLRequest * _Nullable (^)(NSURLSession *session, NSURLSessionTask *task, NSURLResponse *response, NSURLRequest *request))block;
- (void)setTaskWillPerformHTTPRedirectionBlock:(nullable NSURLRequest * (^)(NSURLSession *session, NSURLSessionTask *task, NSURLResponse *response, NSURLRequest *request))block;
/**
Sets a block to be executed when a session task has received a request specific authentication challenge, as handled by the `NSURLSessionTaskDelegate` method `URLSession:task:didReceiveChallenge:completionHandler:`.
@ -415,7 +414,7 @@ NS_ASSUME_NONNULL_BEGIN
@param block A block object to be executed once all messages enqueued for a session have been delivered. The block has no return value and takes a single argument: the session.
*/
- (void)setDidFinishEventsForBackgroundURLSessionBlock:(nullable void (^)(NSURLSession *session))block AF_API_UNAVAILABLE(macos);
- (void)setDidFinishEventsForBackgroundURLSessionBlock:(nullable void (^)(NSURLSession *session))block;
///-----------------------------------------------
/// @name Setting Download Task Delegate Callbacks

View File

@ -85,6 +85,8 @@ static NSString * const AFURLSessionManagerLockName = @"com.alamofire.networking
static NSUInteger const AFMaximumNumberOfAttemptsToRecreateBackgroundSessionUploadTask = 3;
static void * AFTaskStateChangedContext = &AFTaskStateChangedContext;
typedef void (^AFURLSessionDidBecomeInvalidBlock)(NSURLSession *session, NSError *error);
typedef NSURLSessionAuthChallengeDisposition (^AFURLSessionDidReceiveAuthenticationChallengeBlock)(NSURLSession *session, NSURLAuthenticationChallenge *challenge, NSURLCredential * __autoreleasing *credential);
@ -112,7 +114,6 @@ typedef void (^AFURLSessionTaskCompletionHandler)(NSURLResponse *response, id re
#pragma mark -
@interface AFURLSessionManagerTaskDelegate : NSObject <NSURLSessionTaskDelegate, NSURLSessionDataDelegate, NSURLSessionDownloadDelegate>
- (instancetype)initWithTask:(NSURLSessionTask *)task;
@property (nonatomic, weak) AFURLSessionManager *manager;
@property (nonatomic, strong) NSMutableData *mutableData;
@property (nonatomic, strong) NSProgress *uploadProgress;
@ -126,56 +127,113 @@ typedef void (^AFURLSessionTaskCompletionHandler)(NSURLResponse *response, id re
@implementation AFURLSessionManagerTaskDelegate
- (instancetype)initWithTask:(NSURLSessionTask *)task {
- (instancetype)init {
self = [super init];
if (!self) {
return nil;
}
_mutableData = [NSMutableData data];
_uploadProgress = [[NSProgress alloc] initWithParent:nil userInfo:nil];
_downloadProgress = [[NSProgress alloc] initWithParent:nil userInfo:nil];
self.mutableData = [NSMutableData data];
self.uploadProgress = [[NSProgress alloc] initWithParent:nil userInfo:nil];
self.uploadProgress.totalUnitCount = NSURLSessionTransferSizeUnknown;
__weak __typeof__(task) weakTask = task;
for (NSProgress *progress in @[ _uploadProgress, _downloadProgress ])
{
progress.totalUnitCount = NSURLSessionTransferSizeUnknown;
progress.cancellable = YES;
progress.cancellationHandler = ^{
[weakTask cancel];
};
progress.pausable = YES;
progress.pausingHandler = ^{
[weakTask suspend];
};
#if AF_CAN_USE_AT_AVAILABLE
if (@available(iOS 9, macOS 10.11, *))
#else
if ([progress respondsToSelector:@selector(setResumingHandler:)])
#endif
{
progress.resumingHandler = ^{
[weakTask resume];
};
}
[progress addObserver:self
forKeyPath:NSStringFromSelector(@selector(fractionCompleted))
options:NSKeyValueObservingOptionNew
context:NULL];
}
self.downloadProgress = [[NSProgress alloc] initWithParent:nil userInfo:nil];
self.downloadProgress.totalUnitCount = NSURLSessionTransferSizeUnknown;
return self;
}
- (void)dealloc {
[self.downloadProgress removeObserver:self forKeyPath:NSStringFromSelector(@selector(fractionCompleted))];
[self.uploadProgress removeObserver:self forKeyPath:NSStringFromSelector(@selector(fractionCompleted))];
}
#pragma mark - NSProgress Tracking
- (void)setupProgressForTask:(NSURLSessionTask *)task {
__weak __typeof__(task) weakTask = task;
self.uploadProgress.totalUnitCount = task.countOfBytesExpectedToSend;
self.downloadProgress.totalUnitCount = task.countOfBytesExpectedToReceive;
[self.uploadProgress setCancellable:YES];
[self.uploadProgress setCancellationHandler:^{
__typeof__(weakTask) strongTask = weakTask;
[strongTask cancel];
}];
[self.uploadProgress setPausable:YES];
[self.uploadProgress setPausingHandler:^{
__typeof__(weakTask) strongTask = weakTask;
[strongTask suspend];
}];
if ([self.uploadProgress respondsToSelector:@selector(setResumingHandler:)]) {
[self.uploadProgress setResumingHandler:^{
__typeof__(weakTask) strongTask = weakTask;
[strongTask resume];
}];
}
[self.downloadProgress setCancellable:YES];
[self.downloadProgress setCancellationHandler:^{
__typeof__(weakTask) strongTask = weakTask;
[strongTask cancel];
}];
[self.downloadProgress setPausable:YES];
[self.downloadProgress setPausingHandler:^{
__typeof__(weakTask) strongTask = weakTask;
[strongTask suspend];
}];
if ([self.downloadProgress respondsToSelector:@selector(setResumingHandler:)]) {
[self.downloadProgress setResumingHandler:^{
__typeof__(weakTask) strongTask = weakTask;
[strongTask resume];
}];
}
[task addObserver:self
forKeyPath:NSStringFromSelector(@selector(countOfBytesReceived))
options:NSKeyValueObservingOptionNew
context:NULL];
[task addObserver:self
forKeyPath:NSStringFromSelector(@selector(countOfBytesExpectedToReceive))
options:NSKeyValueObservingOptionNew
context:NULL];
[task addObserver:self
forKeyPath:NSStringFromSelector(@selector(countOfBytesSent))
options:NSKeyValueObservingOptionNew
context:NULL];
[task addObserver:self
forKeyPath:NSStringFromSelector(@selector(countOfBytesExpectedToSend))
options:NSKeyValueObservingOptionNew
context:NULL];
[self.downloadProgress addObserver:self
forKeyPath:NSStringFromSelector(@selector(fractionCompleted))
options:NSKeyValueObservingOptionNew
context:NULL];
[self.uploadProgress addObserver:self
forKeyPath:NSStringFromSelector(@selector(fractionCompleted))
options:NSKeyValueObservingOptionNew
context:NULL];
}
- (void)cleanUpProgressForTask:(NSURLSessionTask *)task {
[task removeObserver:self forKeyPath:NSStringFromSelector(@selector(countOfBytesReceived))];
[task removeObserver:self forKeyPath:NSStringFromSelector(@selector(countOfBytesExpectedToReceive))];
[task removeObserver:self forKeyPath:NSStringFromSelector(@selector(countOfBytesSent))];
[task removeObserver:self forKeyPath:NSStringFromSelector(@selector(countOfBytesExpectedToSend))];
[self.downloadProgress removeObserver:self forKeyPath:NSStringFromSelector(@selector(fractionCompleted))];
[self.uploadProgress removeObserver:self forKeyPath:NSStringFromSelector(@selector(fractionCompleted))];
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context {
if ([object isEqual:self.downloadProgress]) {
if ([object isKindOfClass:[NSURLSessionTask class]] || [object isKindOfClass:[NSURLSessionDownloadTask class]]) {
if ([keyPath isEqualToString:NSStringFromSelector(@selector(countOfBytesReceived))]) {
self.downloadProgress.completedUnitCount = [change[NSKeyValueChangeNewKey] longLongValue];
} else if ([keyPath isEqualToString:NSStringFromSelector(@selector(countOfBytesExpectedToReceive))]) {
self.downloadProgress.totalUnitCount = [change[NSKeyValueChangeNewKey] longLongValue];
} else if ([keyPath isEqualToString:NSStringFromSelector(@selector(countOfBytesSent))]) {
self.uploadProgress.completedUnitCount = [change[NSKeyValueChangeNewKey] longLongValue];
} else if ([keyPath isEqualToString:NSStringFromSelector(@selector(countOfBytesExpectedToSend))]) {
self.uploadProgress.totalUnitCount = [change[NSKeyValueChangeNewKey] longLongValue];
}
}
else if ([object isEqual:self.downloadProgress]) {
if (self.downloadProgressBlock) {
self.downloadProgressBlock(object);
}
@ -193,6 +251,8 @@ typedef void (^AFURLSessionTaskCompletionHandler)(NSURLResponse *response, id re
task:(NSURLSessionTask *)task
didCompleteWithError:(NSError *)error
{
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wgnu"
__strong AFURLSessionManager *manager = self.manager;
__block id responseObject = nil;
@ -254,60 +314,33 @@ didCompleteWithError:(NSError *)error
});
});
}
#pragma clang diagnostic pop
}
#pragma mark - NSURLSessionDataDelegate
#pragma mark - NSURLSessionDataTaskDelegate
- (void)URLSession:(__unused NSURLSession *)session
dataTask:(__unused NSURLSessionDataTask *)dataTask
didReceiveData:(NSData *)data
{
self.downloadProgress.totalUnitCount = dataTask.countOfBytesExpectedToReceive;
self.downloadProgress.completedUnitCount = dataTask.countOfBytesReceived;
[self.mutableData appendData:data];
}
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task
didSendBodyData:(int64_t)bytesSent
totalBytesSent:(int64_t)totalBytesSent
totalBytesExpectedToSend:(int64_t)totalBytesExpectedToSend{
self.uploadProgress.totalUnitCount = task.countOfBytesExpectedToSend;
self.uploadProgress.completedUnitCount = task.countOfBytesSent;
}
#pragma mark - NSURLSessionDownloadDelegate
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask
didWriteData:(int64_t)bytesWritten
totalBytesWritten:(int64_t)totalBytesWritten
totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite{
self.downloadProgress.totalUnitCount = totalBytesExpectedToWrite;
self.downloadProgress.completedUnitCount = totalBytesWritten;
}
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask
didResumeAtOffset:(int64_t)fileOffset
expectedTotalBytes:(int64_t)expectedTotalBytes{
self.downloadProgress.totalUnitCount = expectedTotalBytes;
self.downloadProgress.completedUnitCount = fileOffset;
}
#pragma mark - NSURLSessionDownloadTaskDelegate
- (void)URLSession:(NSURLSession *)session
downloadTask:(NSURLSessionDownloadTask *)downloadTask
didFinishDownloadingToURL:(NSURL *)location
{
NSError *fileManagerError = nil;
self.downloadFileURL = nil;
if (self.downloadTaskDidFinishDownloading) {
self.downloadFileURL = self.downloadTaskDidFinishDownloading(session, downloadTask, location);
if (self.downloadFileURL) {
NSError *fileManagerError = nil;
[[NSFileManager defaultManager] moveItemAtURL:location toURL:self.downloadFileURL error:&fileManagerError];
if (![[NSFileManager defaultManager] moveItemAtURL:location toURL:self.downloadFileURL error:&fileManagerError]) {
if (fileManagerError) {
[[NSNotificationCenter defaultCenter] postNotificationName:AFURLSessionDownloadTaskDidFailToMoveFileNotification object:downloadTask userInfo:fileManagerError.userInfo];
}
}
@ -454,7 +487,7 @@ static NSString * const AFNSURLSessionTaskDidSuspendNotification = @"com.alamofi
@property (readwrite, nonatomic, strong) NSLock *lock;
@property (readwrite, nonatomic, copy) AFURLSessionDidBecomeInvalidBlock sessionDidBecomeInvalid;
@property (readwrite, nonatomic, copy) AFURLSessionDidReceiveAuthenticationChallengeBlock sessionDidReceiveAuthenticationChallenge;
@property (readwrite, nonatomic, copy) AFURLSessionDidFinishEventsForBackgroundURLSessionBlock didFinishEventsForBackgroundURLSession AF_API_UNAVAILABLE(macos);
@property (readwrite, nonatomic, copy) AFURLSessionDidFinishEventsForBackgroundURLSessionBlock didFinishEventsForBackgroundURLSession;
@property (readwrite, nonatomic, copy) AFURLSessionTaskWillPerformHTTPRedirectionBlock taskWillPerformHTTPRedirection;
@property (readwrite, nonatomic, copy) AFURLSessionTaskDidReceiveAuthenticationChallengeBlock taskDidReceiveAuthenticationChallenge;
@property (readwrite, nonatomic, copy) AFURLSessionTaskNeedNewBodyStreamBlock taskNeedNewBodyStream;
@ -575,6 +608,7 @@ static NSString * const AFNSURLSessionTaskDidSuspendNotification = @"com.alamofi
[self.lock lock];
self.mutableTaskDelegatesKeyedByTaskIdentifier[@(task.taskIdentifier)] = delegate;
[delegate setupProgressForTask:task];
[self addNotificationObserverForTask:task];
[self.lock unlock];
}
@ -584,7 +618,7 @@ static NSString * const AFNSURLSessionTaskDidSuspendNotification = @"com.alamofi
downloadProgress:(nullable void (^)(NSProgress *downloadProgress)) downloadProgressBlock
completionHandler:(void (^)(NSURLResponse *response, id responseObject, NSError *error))completionHandler
{
AFURLSessionManagerTaskDelegate *delegate = [[AFURLSessionManagerTaskDelegate alloc] initWithTask:dataTask];
AFURLSessionManagerTaskDelegate *delegate = [[AFURLSessionManagerTaskDelegate alloc] init];
delegate.manager = self;
delegate.completionHandler = completionHandler;
@ -599,7 +633,7 @@ static NSString * const AFNSURLSessionTaskDidSuspendNotification = @"com.alamofi
progress:(void (^)(NSProgress *uploadProgress)) uploadProgressBlock
completionHandler:(void (^)(NSURLResponse *response, id responseObject, NSError *error))completionHandler
{
AFURLSessionManagerTaskDelegate *delegate = [[AFURLSessionManagerTaskDelegate alloc] initWithTask:uploadTask];
AFURLSessionManagerTaskDelegate *delegate = [[AFURLSessionManagerTaskDelegate alloc] init];
delegate.manager = self;
delegate.completionHandler = completionHandler;
@ -615,7 +649,7 @@ static NSString * const AFNSURLSessionTaskDidSuspendNotification = @"com.alamofi
destination:(NSURL * (^)(NSURL *targetPath, NSURLResponse *response))destination
completionHandler:(void (^)(NSURLResponse *response, NSURL *filePath, NSError *error))completionHandler
{
AFURLSessionManagerTaskDelegate *delegate = [[AFURLSessionManagerTaskDelegate alloc] initWithTask:downloadTask];
AFURLSessionManagerTaskDelegate *delegate = [[AFURLSessionManagerTaskDelegate alloc] init];
delegate.manager = self;
delegate.completionHandler = completionHandler;
@ -635,7 +669,9 @@ static NSString * const AFNSURLSessionTaskDidSuspendNotification = @"com.alamofi
- (void)removeDelegateForTask:(NSURLSessionTask *)task {
NSParameterAssert(task);
AFURLSessionManagerTaskDelegate *delegate = [self delegateForTask:task];
[self.lock lock];
[delegate cleanUpProgressForTask:task];
[self removeNotificationObserverForTask:task];
[self.mutableTaskDelegatesKeyedByTaskIdentifier removeObjectForKey:@(task.taskIdentifier)];
[self.lock unlock];
@ -684,11 +720,13 @@ static NSString * const AFNSURLSessionTaskDidSuspendNotification = @"com.alamofi
#pragma mark -
- (void)invalidateSessionCancelingTasks:(BOOL)cancelPendingTasks {
if (cancelPendingTasks) {
[self.session invalidateAndCancel];
} else {
[self.session finishTasksAndInvalidate];
}
dispatch_async(dispatch_get_main_queue(), ^{
if (cancelPendingTasks) {
[self.session invalidateAndCancel];
} else {
[self.session finishTasksAndInvalidate];
}
});
}
#pragma mark -
@ -743,21 +781,16 @@ static NSString * const AFNSURLSessionTaskDidSuspendNotification = @"com.alamofi
__block NSURLSessionUploadTask *uploadTask = nil;
url_session_manager_create_task_safely(^{
uploadTask = [self.session uploadTaskWithRequest:request fromFile:fileURL];
// uploadTask may be nil on iOS7 because uploadTaskWithRequest:fromFile: may return nil despite being documented as nonnull (https://devforums.apple.com/message/926113#926113)
if (!uploadTask && self.attemptsToRecreateUploadTasksForBackgroundSessions && self.session.configuration.identifier) {
for (NSUInteger attempts = 0; !uploadTask && attempts < AFMaximumNumberOfAttemptsToRecreateBackgroundSessionUploadTask; attempts++) {
uploadTask = [self.session uploadTaskWithRequest:request fromFile:fileURL];
}
}
});
if (uploadTask) {
[self addDelegateForUploadTask:uploadTask
progress:uploadProgressBlock
completionHandler:completionHandler];
if (!uploadTask && self.attemptsToRecreateUploadTasksForBackgroundSessions && self.session.configuration.identifier) {
for (NSUInteger attempts = 0; !uploadTask && attempts < AFMaximumNumberOfAttemptsToRecreateBackgroundSessionUploadTask; attempts++) {
uploadTask = [self.session uploadTaskWithRequest:request fromFile:fileURL];
}
}
[self addDelegateForUploadTask:uploadTask progress:uploadProgressBlock completionHandler:completionHandler];
return uploadTask;
}
@ -841,11 +874,9 @@ static NSString * const AFNSURLSessionTaskDidSuspendNotification = @"com.alamofi
self.sessionDidReceiveAuthenticationChallenge = block;
}
#if !TARGET_OS_OSX
- (void)setDidFinishEventsForBackgroundURLSessionBlock:(void (^)(NSURLSession *session))block {
self.didFinishEventsForBackgroundURLSession = block;
}
#endif
#pragma mark -
@ -914,12 +945,9 @@ static NSString * const AFNSURLSessionTaskDidSuspendNotification = @"com.alamofi
return self.dataTaskDidReceiveResponse != nil;
} else if (selector == @selector(URLSession:dataTask:willCacheResponse:completionHandler:)) {
return self.dataTaskWillCacheResponse != nil;
}
#if !TARGET_OS_OSX
else if (selector == @selector(URLSessionDidFinishEventsForBackgroundURLSession:)) {
} else if (selector == @selector(URLSessionDidFinishEventsForBackgroundURLSession:)) {
return self.didFinishEventsForBackgroundURLSession != nil;
}
#endif
return [[self class] instancesRespondToSelector:selector];
}
@ -1046,12 +1074,6 @@ totalBytesExpectedToSend:(int64_t)totalBytesExpectedToSend
}
}
AFURLSessionManagerTaskDelegate *delegate = [self delegateForTask:task];
if (delegate) {
[delegate URLSession:session task:task didSendBodyData:bytesSent totalBytesSent:totalBytesSent totalBytesExpectedToSend:totalBytesExpectedToSend];
}
if (self.taskDidSendBodyData) {
self.taskDidSendBodyData(session, task, bytesSent, totalBytesSent, totalUnitCount);
}
@ -1137,7 +1159,6 @@ didBecomeDownloadTask:(NSURLSessionDownloadTask *)downloadTask
}
}
#if !TARGET_OS_OSX
- (void)URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession *)session {
if (self.didFinishEventsForBackgroundURLSession) {
dispatch_async(dispatch_get_main_queue(), ^{
@ -1145,7 +1166,6 @@ didBecomeDownloadTask:(NSURLSessionDownloadTask *)downloadTask
});
}
}
#endif
#pragma mark - NSURLSessionDownloadDelegate
@ -1159,8 +1179,8 @@ didFinishDownloadingToURL:(NSURL *)location
if (fileURL) {
delegate.downloadFileURL = fileURL;
NSError *error = nil;
if (![[NSFileManager defaultManager] moveItemAtURL:location toURL:fileURL error:&error]) {
[[NSFileManager defaultManager] moveItemAtURL:location toURL:fileURL error:&error];
if (error) {
[[NSNotificationCenter defaultCenter] postNotificationName:AFURLSessionDownloadTaskDidFailToMoveFileNotification object:downloadTask userInfo:error.userInfo];
}
@ -1179,13 +1199,6 @@ didFinishDownloadingToURL:(NSURL *)location
totalBytesWritten:(int64_t)totalBytesWritten
totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite
{
AFURLSessionManagerTaskDelegate *delegate = [self delegateForTask:downloadTask];
if (delegate) {
[delegate URLSession:session downloadTask:downloadTask didWriteData:bytesWritten totalBytesWritten:totalBytesWritten totalBytesExpectedToWrite:totalBytesExpectedToWrite];
}
if (self.downloadTaskDidWriteData) {
self.downloadTaskDidWriteData(session, downloadTask, bytesWritten, totalBytesWritten, totalBytesExpectedToWrite);
}
@ -1196,13 +1209,6 @@ totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite
didResumeAtOffset:(int64_t)fileOffset
expectedTotalBytes:(int64_t)expectedTotalBytes
{
AFURLSessionManagerTaskDelegate *delegate = [self delegateForTask:downloadTask];
if (delegate) {
[delegate URLSession:session downloadTask:downloadTask didResumeAtOffset:fileOffset expectedTotalBytes:expectedTotalBytes];
}
if (self.downloadTaskDidResume) {
self.downloadTaskDidResume(session, downloadTask, fileOffset, expectedTotalBytes);
}

View File

@ -1,4 +1,4 @@
Copyright (c) 2011-2016 Alamofire Software Foundation (http://alamofire.org/)
Copyright (c) 20112016 Alamofire Software Foundation (http://alamofire.org/)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View File

@ -9,7 +9,7 @@
[![Platform](https://img.shields.io/cocoapods/p/AFNetworking.svg?style=flat)](http://cocoadocs.org/docsets/AFNetworking)
[![Twitter](https://img.shields.io/badge/twitter-@AFNetworking-blue.svg?style=flat)](http://twitter.com/AFNetworking)
AFNetworking is a delightful networking library for iOS, macOS, watchOS, and tvOS. It's built on top of the [Foundation URL Loading System](http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/URLLoadingSystem/URLLoadingSystem.html), extending the powerful high-level networking abstractions built into Cocoa. It has a modular architecture with well-designed, feature-rich APIs that are a joy to use.
AFNetworking is a delightful networking library for iOS and Mac OS X. It's built on top of the [Foundation URL Loading System](http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/URLLoadingSystem/URLLoadingSystem.html), extending the powerful high-level networking abstractions built into Cocoa. It has a modular architecture with well-designed, feature-rich APIs that are a joy to use.
Perhaps the most important feature of all, however, is the amazing community of developers who use and contribute to AFNetworking every day. AFNetworking powers some of the most popular and critically-acclaimed apps on the iPhone, iPad, and Mac.
@ -51,9 +51,7 @@ To integrate AFNetworking into your Xcode project using CocoaPods, specify it in
source 'https://github.com/CocoaPods/Specs.git'
platform :ios, '8.0'
target 'TargetName' do
pod 'AFNetworking', '~> 3.0'
end
```
Then, run the following command:
@ -83,7 +81,7 @@ Run `carthage` to build the framework and drag the built `AFNetworking.framework
## Requirements
| AFNetworking Version | Minimum iOS Target | Minimum macOS Target | Minimum watchOS Target | Minimum tvOS Target | Notes |
| AFNetworking Version | Minimum iOS Target | Minimum OS X Target | Minimum watchOS Target | Minimum tvOS Target | Notes |
|:--------------------:|:---------------------------:|:----------------------------:|:----------------------------:|:----------------------------:|:-------------------------------------------------------------------------:|
| 3.x | iOS 7 | OS X 10.9 | watchOS 2.0 | tvOS 9.0 | Xcode 7+ is required. `NSURLConnectionOperation` support has been removed. |
| 2.6 -> 2.6.3 | iOS 7 | OS X 10.9 | watchOS 2.0 | n/a | Xcode 7+ is required. |
@ -91,7 +89,7 @@ Run `carthage` to build the framework and drag the built `AFNetworking.framework
| 1.x | iOS 5 | Mac OS X 10.7 | n/a | n/a |
| 0.10.x | iOS 4 | Mac OS X 10.6 | n/a | n/a |
(macOS projects must support [64-bit with modern Cocoa runtime](https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtVersionsPlatforms.html)).
(OS X projects must support [64-bit with modern Cocoa runtime](https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtVersionsPlatforms.html)).
> Programming in Swift? Try [Alamofire](https://github.com/Alamofire/Alamofire) for a more conventional set of APIs.
@ -112,7 +110,7 @@ Run `carthage` to build the framework and drag the built `AFNetworking.framework
- `AFHTTPResponseSerializer`
- `AFJSONResponseSerializer`
- `AFXMLParserResponseSerializer`
- `AFXMLDocumentResponseSerializer` _(macOS)_
- `AFXMLDocumentResponseSerializer` _(Mac OS X)_
- `AFPropertyListResponseSerializer`
- `AFImageResponseSerializer`
- `AFCompoundResponseSerializer`
@ -319,4 +317,4 @@ If you believe you have identified a security vulnerability with AFNetworking, y
## License
AFNetworking is released under the MIT license. See [LICENSE](https://github.com/AFNetworking/AFNetworking/blob/master/LICENSE) for details.
AFNetworking is released under the MIT license. See LICENSE for details.

View File

@ -72,17 +72,6 @@ NS_ASSUME_NONNULL_BEGIN
*/
@protocol AFImageRequestCache <AFImageCache>
/**
Asks if the image should be cached using an identifier created from the request and additional identifier.
@param image The image to be cached.
@param request The unique URL request identifing the image asset.
@param identifier The additional identifier to apply to the URL request to identify the image.
@return A BOOL indicating whether or not the image should be added to the cache. YES will cache, NO will prevent caching.
*/
- (BOOL)shouldCacheImage:(UIImage *)image forRequest:(NSURLRequest *)request withAdditionalIdentifier:(nullable NSString *)identifier;
/**
Adds the image to the cache using an identifier created from the request and additional identifier.

View File

@ -196,10 +196,6 @@
return key;
}
- (BOOL)shouldCacheImage:(UIImage *)image forRequest:(NSURLRequest *)request withAdditionalIdentifier:(nullable NSString *)identifier {
return YES;
}
@end
#endif

View File

@ -81,11 +81,6 @@ typedef NS_ENUM(NSInteger, AFImageDownloadPrioritization) {
*/
+ (NSURLCache *)defaultURLCache;
/**
The default `NSURLSessionConfiguration` with common usage parameter values.
*/
+ (NSURLSessionConfiguration *)defaultURLSessionConfiguration;
/**
Default initializer
@ -93,15 +88,6 @@ typedef NS_ENUM(NSInteger, AFImageDownloadPrioritization) {
*/
- (instancetype)init;
/**
Initializer with specific `URLSessionConfiguration`
@param configuration The `NSURLSessionConfiguration` to be be used
@return An instance of `AFImageDownloader` initialized with default values and custom `NSURLSessionConfiguration`
*/
- (instancetype)initWithSessionConfiguration:(NSURLSessionConfiguration *)configuration;
/**
Initializes the `AFImageDownloader` instance with the given session manager, download prioritization, maximum active download count and image cache.

View File

@ -106,20 +106,10 @@
@end
@implementation AFImageDownloader
+ (NSURLCache *)defaultURLCache {
// It's been discovered that a crash will occur on certain versions
// of iOS if you customize the cache.
//
// More info can be found here: https://devforums.apple.com/message/1102182#1102182
//
// When iOS 7 support is dropped, this should be modified to use
// NSProcessInfo methods instead.
if ([[[UIDevice currentDevice] systemVersion] compare:@"8.2" options:NSNumericSearch] == NSOrderedAscending) {
return [NSURLCache sharedURLCache];
}
return [[NSURLCache alloc] initWithMemoryCapacity:20 * 1024 * 1024
diskCapacity:150 * 1024 * 1024
diskPath:@"com.alamofire.imagedownloader"];
@ -143,11 +133,7 @@
- (instancetype)init {
NSURLSessionConfiguration *defaultConfiguration = [self.class defaultURLSessionConfiguration];
return [self initWithSessionConfiguration:defaultConfiguration];
}
- (instancetype)initWithSessionConfiguration:(NSURLSessionConfiguration *)configuration {
AFHTTPSessionManager *sessionManager = [[AFHTTPSessionManager alloc] initWithSessionConfiguration:configuration];
AFHTTPSessionManager *sessionManager = [[AFHTTPSessionManager alloc] initWithSessionConfiguration:defaultConfiguration];
sessionManager.responseSerializer = [AFImageResponseSerializer serializer];
return [self initWithSessionManager:sessionManager
@ -249,12 +235,10 @@
createdTask = [self.sessionManager
dataTaskWithRequest:request
uploadProgress:nil
downloadProgress:nil
completionHandler:^(NSURLResponse * _Nonnull response, id _Nullable responseObject, NSError * _Nullable error) {
dispatch_async(self.responseQueue, ^{
__strong __typeof__(weakSelf) strongSelf = weakSelf;
AFImageDownloaderMergedTask *mergedTask = strongSelf.mergedTasks[URLIdentifier];
AFImageDownloaderMergedTask *mergedTask = self.mergedTasks[URLIdentifier];
if ([mergedTask.identifier isEqual:mergedTaskIdentifier]) {
mergedTask = [strongSelf safelyRemoveMergedTaskWithURLIdentifier:URLIdentifier];
if (error) {
@ -266,9 +250,7 @@
}
}
} else {
if ([strongSelf.imageCache shouldCacheImage:responseObject forRequest:request withAdditionalIdentifier:nil]) {
[strongSelf.imageCache addImage:responseObject forRequest:request withAdditionalIdentifier:nil];
}
[strongSelf.imageCache addImage:responseObject forRequest:request withAdditionalIdentifier:nil];
for (AFImageDownloaderResponseHandler *handler in mergedTask.responseHandlers) {
if (handler.successBlock) {

View File

@ -147,7 +147,10 @@ typedef void (^AFNetworkActivityActionBlock)(BOOL networkActivityIndicatorVisibl
- (void)decrementActivityCount {
[self willChangeValueForKey:@"activityCount"];
@synchronized(self) {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wgnu"
_activityCount = MAX(_activityCount - 1, 0);
#pragma clang diagnostic pop
}
[self didChangeValueForKey:@"activityCount"];
@ -191,9 +194,8 @@ typedef void (^AFNetworkActivityActionBlock)(BOOL networkActivityIndicatorVisibl
[self startCompletionDelayTimer];
break;
}
[self didChangeValueForKey:@"currentState"];
}
[self didChangeValueForKey:@"currentState"];
}
}

View File

@ -71,12 +71,16 @@
if (task) {
if (task.state != NSURLSessionTaskStateCompleted) {
UIActivityIndicatorView *activityIndicatorView = self.activityIndicatorView;
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wreceiver-is-weak"
#pragma clang diagnostic ignored "-Warc-repeated-use-of-weak"
if (task.state == NSURLSessionTaskStateRunning) {
[activityIndicatorView startAnimating];
[self.activityIndicatorView startAnimating];
} else {
[activityIndicatorView stopAnimating];
[self.activityIndicatorView stopAnimating];
}
#pragma clang diagnostic pop
[notificationCenter addObserver:self selector:@selector(af_startAnimating) name:AFNetworkingTaskDidResumeNotification object:task];
[notificationCenter addObserver:self selector:@selector(af_stopAnimating) name:AFNetworkingTaskDidCompleteNotification object:task];
@ -89,13 +93,19 @@
- (void)af_startAnimating {
dispatch_async(dispatch_get_main_queue(), ^{
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wreceiver-is-weak"
[self.activityIndicatorView startAnimating];
#pragma clang diagnostic pop
});
}
- (void)af_stopAnimating {
dispatch_async(dispatch_get_main_queue(), ^{
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wreceiver-is-weak"
[self.activityIndicatorView stopAnimating];
#pragma clang diagnostic pop
});
}

View File

@ -103,7 +103,10 @@ static const char * af_backgroundImageDownloadReceiptKeyForState(UIControlState
+ (AFImageDownloader *)sharedImageDownloader {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wgnu"
return objc_getAssociatedObject(self, @selector(sharedImageDownloader)) ?: [AFImageDownloader defaultInstance];
#pragma clang diagnostic pop
}
+ (void)setSharedImageDownloader:(AFImageDownloader *)imageDownloader {

View File

@ -48,7 +48,11 @@
@implementation UIImageView (AFNetworking)
+ (AFImageDownloader *)sharedImageDownloader {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wgnu"
return objc_getAssociatedObject(self, @selector(sharedImageDownloader)) ?: [AFImageDownloader defaultInstance];
#pragma clang diagnostic pop
}
+ (void)setSharedImageDownloader:(AFImageDownloader *)imageDownloader {
@ -77,11 +81,8 @@
{
if ([urlRequest URL] == nil) {
[self cancelImageDownloadTask];
self.image = placeholderImage;
if (failure) {
NSError *error = [NSError errorWithDomain:NSURLErrorDomain code:NSURLErrorBadURL userInfo:nil];
failure(urlRequest, nil, error);
}
return;
}

View File

@ -55,10 +55,6 @@ static void * AFTaskCountOfBytesReceivedContext = &AFTaskCountOfBytesReceivedCon
- (void)setProgressWithUploadProgressOfTask:(NSURLSessionUploadTask *)task
animated:(BOOL)animated
{
if (task.state == NSURLSessionTaskStateCompleted) {
return;
}
[task addObserver:self forKeyPath:@"state" options:(NSKeyValueObservingOptions)0 context:AFTaskCountOfBytesSentContext];
[task addObserver:self forKeyPath:@"countOfBytesSent" options:(NSKeyValueObservingOptions)0 context:AFTaskCountOfBytesSentContext];
@ -68,10 +64,6 @@ static void * AFTaskCountOfBytesReceivedContext = &AFTaskCountOfBytesReceivedCon
- (void)setProgressWithDownloadProgressOfTask:(NSURLSessionDownloadTask *)task
animated:(BOOL)animated
{
if (task.state == NSURLSessionTaskStateCompleted) {
return;
}
[task addObserver:self forKeyPath:@"state" options:(NSKeyValueObservingOptions)0 context:AFTaskCountOfBytesReceivedContext];
[task addObserver:self forKeyPath:@"countOfBytesReceived" options:(NSKeyValueObservingOptions)0 context:AFTaskCountOfBytesReceivedContext];

View File

@ -71,16 +71,19 @@
[notificationCenter removeObserver:self name:AFNetworkingTaskDidCompleteNotification object:nil];
if (task) {
UIRefreshControl *refreshControl = self.refreshControl;
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wreceiver-is-weak"
#pragma clang diagnostic ignored "-Warc-repeated-use-of-weak"
if (task.state == NSURLSessionTaskStateRunning) {
[refreshControl beginRefreshing];
[self.refreshControl beginRefreshing];
[notificationCenter addObserver:self selector:@selector(af_beginRefreshing) name:AFNetworkingTaskDidResumeNotification object:task];
[notificationCenter addObserver:self selector:@selector(af_endRefreshing) name:AFNetworkingTaskDidCompleteNotification object:task];
[notificationCenter addObserver:self selector:@selector(af_endRefreshing) name:AFNetworkingTaskDidSuspendNotification object:task];
} else {
[refreshControl endRefreshing];
[self.refreshControl endRefreshing];
}
#pragma clang diagnostic pop
}
}
@ -88,13 +91,19 @@
- (void)af_beginRefreshing {
dispatch_async(dispatch_get_main_queue(), ^{
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wreceiver-is-weak"
[self.refreshControl beginRefreshing];
#pragma clang diagnostic pop
});
}
- (void)af_endRefreshing {
dispatch_async(dispatch_get_main_queue(), ^{
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wreceiver-is-weak"
[self.refreshControl endRefreshing];
#pragma clang diagnostic pop
});
}

View File

@ -58,7 +58,10 @@
_af_defaultHTTPSessionManager.responseSerializer = [AFHTTPResponseSerializer serializer];
});
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wgnu"
return objc_getAssociatedObject(self, @selector(sessionManager)) ?: _af_defaultHTTPSessionManager;
#pragma clang diagnostic pop
}
- (void)setSessionManager:(AFHTTPSessionManager *)sessionManager {
@ -72,7 +75,10 @@
_af_defaultResponseSerializer = [AFHTTPResponseSerializer serializer];
});
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wgnu"
return objc_getAssociatedObject(self, @selector(responseSerializer)) ?: _af_defaultResponseSerializer;
#pragma clang diagnostic pop
}
- (void)setResponseSerializer:(AFHTTPResponseSerializer<AFURLResponseSerialization> *)responseSerializer {
@ -119,28 +125,27 @@
self.af_URLSessionTask = nil;
__weak __typeof(self)weakSelf = self;
__block NSURLSessionDataTask *dataTask;
NSURLSessionDataTask *dataTask;
dataTask = [self.sessionManager
dataTaskWithRequest:request
uploadProgress:nil
downloadProgress:nil
completionHandler:^(NSURLResponse * _Nonnull response, id _Nonnull responseObject, NSError * _Nullable error) {
__strong __typeof(weakSelf) strongSelf = weakSelf;
if (error) {
if (failure) {
failure(error);
}
} else {
if (success) {
success((NSHTTPURLResponse *)response, responseObject);
}
[strongSelf loadData:responseObject MIMEType:MIMEType textEncodingName:textEncodingName baseURL:[dataTask.currentRequest URL]];
GET:request.URL.absoluteString
parameters:nil
progress:nil
success:^(NSURLSessionDataTask * _Nonnull task, id _Nonnull responseObject) {
__strong __typeof(weakSelf) strongSelf = weakSelf;
if (success) {
success((NSHTTPURLResponse *)task.response, responseObject);
}
[strongSelf loadData:responseObject MIMEType:MIMEType textEncodingName:textEncodingName baseURL:[task.currentRequest URL]];
if ([strongSelf.delegate respondsToSelector:@selector(webViewDidFinishLoad:)]) {
[strongSelf.delegate webViewDidFinishLoad:strongSelf];
}
}
}];
if ([strongSelf.delegate respondsToSelector:@selector(webViewDidStartLoad:)]) {
[strongSelf.delegate webViewDidFinishLoad:strongSelf];
}
}
failure:^(NSURLSessionDataTask * _Nonnull task, NSError * _Nonnull error) {
if (failure) {
failure(error);
}
}];
self.af_URLSessionTask = dataTask;
if (progress != nil) {
*progress = [self.sessionManager downloadProgressForTask:dataTask];

View File

@ -20,8 +20,7 @@
#import <FBSDKCoreKit/FBSDKCopying.h>
#import <FBSDKCoreKit/FBSDKGraphRequestConnection.h>
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0
#import <FBSDKCoreKit/FBSDKMacros.h>
/**
Notification indicating that the `currentAccessToken` has changed.
@ -30,20 +29,7 @@
`FBSDKAccessTokenChangeOldKey` and
`FBSDKAccessTokenChangeNewKey`.
*/
FOUNDATION_EXPORT NSNotificationName const FBSDKAccessTokenDidChangeNotification;
#else
/**
Notification indicating that the `currentAccessToken` has changed.
the userInfo dictionary of the notification will contain keys
`FBSDKAccessTokenChangeOldKey` and
`FBSDKAccessTokenChangeNewKey`.
*/
FOUNDATION_EXPORT NSString *const FBSDKAccessTokenDidChangeNotification;
#endif
FBSDK_EXTERN NSString *const FBSDKAccessTokenDidChangeNotification;
/**
A key in the notification's userInfo that will be set
@ -58,33 +44,21 @@ FOUNDATION_EXPORT NSString *const FBSDKAccessTokenDidChangeNotification;
of an access token, this key will also exist since the access token
is moving from a null state (no user) to a non-null state (user).
*/
FOUNDATION_EXPORT NSString *const FBSDKAccessTokenDidChangeUserIDKey;
FOUNDATION_EXPORT NSString *const FBSDKAccessTokenDidChangeUserID
DEPRECATED_MSG_ATTRIBUTE("Renamed `FBSDKAccessTokenDidChangeUserIDKey`");
FBSDK_EXTERN NSString *const FBSDKAccessTokenDidChangeUserID;
/*
key in notification's userInfo object for getting the old token.
If there was no old token, the key will not be present.
*/
FOUNDATION_EXPORT NSString *const FBSDKAccessTokenChangeOldKey;
FBSDK_EXTERN NSString *const FBSDKAccessTokenChangeOldKey;
/*
key in notification's userInfo object for getting the new token.
If there is no new token, the key will not be present.
*/
FOUNDATION_EXPORT NSString *const FBSDKAccessTokenChangeNewKey;
/*
A key in the notification's userInfo that will be set
if and only if the token has expired.
*/
FOUNDATION_EXPORT NSString *const FBSDKAccessTokenDidExpireKey;
FOUNDATION_EXPORT NSString *const FBSDKAccessTokenDidExpire
DEPRECATED_MSG_ATTRIBUTE("Renamed `FBSDKAccessTokenDidExpireKey`");
FBSDK_EXTERN NSString *const FBSDKAccessTokenChangeNewKey;
/**
@ -97,11 +71,6 @@ DEPRECATED_MSG_ATTRIBUTE("Renamed `FBSDKAccessTokenDidExpireKey`");
*/
@property (readonly, copy, nonatomic) NSString *appID;
/**
Returns the expiration date for data access
*/
@property (readonly, copy, nonatomic) NSDate *dataAccessExpirationDate;
/**
Returns the known declined permissions.
*/
@ -132,56 +101,20 @@ DEPRECATED_MSG_ATTRIBUTE("Renamed `FBSDKAccessTokenDidExpireKey`");
*/
@property (readonly, copy, nonatomic) NSString *userID;
/**
Returns whether the access token is expired by checking its expirationDate property
*/
@property (readonly, assign, nonatomic, getter = isExpired) BOOL expired;
/**
Returns whether user data access is still active for the given access token
*/
@property (readonly, assign, nonatomic, getter = isDataAccessExpired) BOOL dataAccessExpired;
- (instancetype)init NS_UNAVAILABLE;
+ (instancetype)new NS_UNAVAILABLE;
/**
Initializes a new instance.
@param tokenString the opaque token string.
@param permissions the granted permissions. Note this is converted to NSSet and is only
an NSArray for the convenience of literal syntax.
@param declinedPermissions the declined permissions. Note this is converted to NSSet and is only
an NSArray for the convenience of literal syntax.
@param appID the app ID.
@param userID the user ID.
@param expirationDate the optional expiration date (defaults to distantFuture).
@param refreshDate the optional date the token was last refreshed (defaults to today).
This initializer should only be used for advanced apps that
manage tokens explicitly. Typical login flows only need to use `FBSDKLoginManager`
along with `+currentAccessToken`.
*/
- (instancetype)initWithTokenString:(NSString *)tokenString
permissions:(NSArray *)permissions
declinedPermissions:(NSArray *)declinedPermissions
appID:(NSString *)appID
userID:(NSString *)userID
expirationDate:(NSDate *)expirationDate
refreshDate:(NSDate *)refreshDate;
/**
Initializes a new instance.
@param tokenString the opaque token string.
@param permissions the granted permissions. Note this is converted to NSSet and is only
- Parameter tokenString: the opaque token string.
- Parameter permissions: the granted permissions. Note this is converted to NSSet and is only
an NSArray for the convenience of literal syntax.
@param declinedPermissions the declined permissions. Note this is converted to NSSet and is only
- Parameter declinedPermissions: the declined permissions. Note this is converted to NSSet and is only
an NSArray for the convenience of literal syntax.
@param appID the app ID.
@param userID the user ID.
@param expirationDate the optional expiration date (defaults to distantFuture).
@param refreshDate the optional date the token was last refreshed (defaults to today).
@param dataAccessExpirationDate the date which data access will expire for the given user
(defaults to distantFuture).
- Parameter appID: the app ID.
- Parameter userID: the user ID.
- Parameter expirationDate: the optional expiration date (defaults to distantFuture).
- Parameter refreshDate: the optional date the token was last refreshed (defaults to today).
This initializer should only be used for advanced apps that
manage tokens explicitly. Typical login flows only need to use `FBSDKLoginManager`
@ -194,19 +127,18 @@ DEPRECATED_MSG_ATTRIBUTE("Renamed `FBSDKAccessTokenDidExpireKey`");
userID:(NSString *)userID
expirationDate:(NSDate *)expirationDate
refreshDate:(NSDate *)refreshDate
dataAccessExpirationDate:(NSDate *)dataAccessExpirationDate
NS_DESIGNATED_INITIALIZER;
/**
Convenience getter to determine if a permission has been granted
@param permission The permission to check.
- Parameter permission: The permission to check.
*/
- (BOOL)hasGranted:(NSString *)permission;
/**
Compares the receiver to another FBSDKAccessToken
@param token The other token
@return YES if the receiver's values are equal to the other token's values; otherwise NO
- Parameter token: The other token
- Returns: YES if the receiver's values are equal to the other token's values; otherwise NO
*/
- (BOOL)isEqualToAccessToken:(FBSDKAccessToken *)token;
@ -218,15 +150,9 @@ NS_DESIGNATED_INITIALIZER;
*/
+ (FBSDKAccessToken *)currentAccessToken;
/**
Returns YES if currentAccessToken is not nil AND currentAccessToken is not expired
*/
+ (BOOL)currentAccessTokenIsActive;
/**
Sets the "global" access token that represents the currently logged in user.
@param token The access token to set.
- Parameter token: The access token to set.
This will broadcast a notification and save the token to the app keychain.
*/
@ -235,7 +161,7 @@ NS_DESIGNATED_INITIALIZER;
/**
Refresh the current access token's permission state and extend the token's expiration date,
if possible.
@param completionHandler an optional callback handler that can surface any errors related to permission refreshing.
- Parameter completionHandler: an optional callback handler that can surface any errors related to permission refreshing.
On a successful refresh, the currentAccessToken will be updated so you typically only need to
observe the `FBSDKAccessTokenDidChangeNotification` notification.

View File

@ -23,22 +23,10 @@
#import "FBSDKMath.h"
#import "FBSDKSettings+Internal.h"
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0
NSNotificationName const FBSDKAccessTokenDidChangeNotification = @"com.facebook.sdk.FBSDKAccessTokenData.FBSDKAccessTokenDidChangeNotification";
#else
NSString *const FBSDKAccessTokenDidChangeNotification = @"com.facebook.sdk.FBSDKAccessTokenData.FBSDKAccessTokenDidChangeNotification";
#endif
NSString *const FBSDKAccessTokenDidChangeUserIDKey = @"FBSDKAccessTokenDidChangeUserID";
NSString *const FBSDKAccessTokenDidChangeUserID = @"FBSDKAccessTokenDidChangeUserID";
NSString *const FBSDKAccessTokenChangeNewKey = @"FBSDKAccessToken";
NSString *const FBSDKAccessTokenChangeOldKey = @"FBSDKAccessTokenOld";
NSString *const FBSDKAccessTokenDidExpireKey = @"FBSDKAccessTokenDidExpire";
NSString *const FBSDKAccessTokenDidExpire = @"FBSDKAccessTokenDidExpire";
static FBSDKAccessToken *g_currentAccessToken;
@ -49,27 +37,12 @@ static FBSDKAccessToken *g_currentAccessToken;
#define FBSDK_ACCESSTOKEN_USERID_KEY @"userID"
#define FBSDK_ACCESSTOKEN_REFRESHDATE_KEY @"refreshDate"
#define FBSDK_ACCESSTOKEN_EXPIRATIONDATE_KEY @"expirationDate"
#define FBSDK_ACCESSTOKEN_DATA_EXPIRATIONDATE_KEY @"dataAccessExpirationDate"
@implementation FBSDKAccessToken
- (instancetype)initWithTokenString:(NSString *)tokenString
permissions:(NSArray *)permissions
declinedPermissions:(NSArray *)declinedPermissions
appID:(NSString *)appID
userID:(NSString *)userID
expirationDate:(NSDate *)expirationDate
refreshDate:(NSDate *)refreshDate
- (instancetype)init NS_UNAVAILABLE
{
return [self initWithTokenString:tokenString
permissions:permissions
declinedPermissions:declinedPermissions
appID:appID
userID:userID
expirationDate:expirationDate
refreshDate:refreshDate
dataAccessExpirationDate:[NSDate distantFuture]];
assert(0);
}
- (instancetype)initWithTokenString:(NSString *)tokenString
@ -79,7 +52,6 @@ static FBSDKAccessToken *g_currentAccessToken;
userID:(NSString *)userID
expirationDate:(NSDate *)expirationDate
refreshDate:(NSDate *)refreshDate
dataAccessExpirationDate:(NSDate *)dataAccessExpirationDate
{
if ((self = [super init])) {
_tokenString = [tokenString copy];
@ -89,7 +61,6 @@ static FBSDKAccessToken *g_currentAccessToken;
_userID = [userID copy];
_expirationDate = [expirationDate copy] ?: [NSDate distantFuture];
_refreshDate = [refreshDate copy] ?: [NSDate date];
_dataAccessExpirationDate = [dataAccessExpirationDate copy] ?: [NSDate distantFuture];
}
return self;
}
@ -97,17 +68,6 @@ static FBSDKAccessToken *g_currentAccessToken;
- (BOOL)hasGranted:(NSString *)permission
{
return [self.permissions containsObject:permission];
}
- (BOOL)isDataAccessExpired
{
return [self.dataAccessExpirationDate compare:NSDate.date] == NSOrderedAscending;
}
- (BOOL)isExpired
{
return [self.expirationDate compare:NSDate.date] == NSOrderedAscending;
}
+ (FBSDKAccessToken *)currentAccessToken
@ -121,9 +81,8 @@ static FBSDKAccessToken *g_currentAccessToken;
NSMutableDictionary *userInfo = [NSMutableDictionary dictionary];
[FBSDKInternalUtility dictionary:userInfo setObject:token forKey:FBSDKAccessTokenChangeNewKey];
[FBSDKInternalUtility dictionary:userInfo setObject:g_currentAccessToken forKey:FBSDKAccessTokenChangeOldKey];
// We set this flag also when the current Access Token was not valid, since there might be legacy code relying on it
if (![g_currentAccessToken.userID isEqualToString:token.userID] || ![self currentAccessTokenIsActive]) {
userInfo[FBSDKAccessTokenDidChangeUserIDKey] = @YES;
if (![g_currentAccessToken.userID isEqualToString:token.userID]) {
userInfo[FBSDKAccessTokenDidChangeUserID] = @YES;
}
g_currentAccessToken = token;
@ -134,19 +93,13 @@ static FBSDKAccessToken *g_currentAccessToken;
[FBSDKInternalUtility deleteFacebookCookies];
}
[FBSDKSettings accessTokenCache].accessToken = token;
[[FBSDKSettings accessTokenCache] cacheAccessToken:token];
[[NSNotificationCenter defaultCenter] postNotificationName:FBSDKAccessTokenDidChangeNotification
object:[self class]
userInfo:userInfo];
}
}
+ (BOOL)currentAccessTokenIsActive
{
FBSDKAccessToken *currentAccessToken = [self currentAccessToken];
return currentAccessToken != nil && !currentAccessToken.isExpired;
}
+ (void)refreshCurrentAccessToken:(FBSDKGraphRequestHandler)completionHandler
{
if ([FBSDKAccessToken currentAccessToken]) {
@ -155,7 +108,7 @@ static FBSDKAccessToken *g_currentAccessToken;
[connection start];
} else {
if (completionHandler) {
completionHandler(nil, nil, [NSError fbErrorWithCode:FBSDKErrorAccessTokenRequired message:@"No current access token to refresh"]);
completionHandler(nil, nil, [FBSDKError errorWithCode:FBSDKAccessTokenRequiredErrorCode message:@"No current access token to refresh"]);
}
}
}
@ -165,14 +118,13 @@ static FBSDKAccessToken *g_currentAccessToken;
- (NSUInteger)hash
{
NSUInteger subhashes[] = {
self.tokenString.hash,
self.permissions.hash,
self.declinedPermissions.hash,
self.appID.hash,
self.userID.hash,
self.refreshDate.hash,
self.expirationDate.hash,
self.dataAccessExpirationDate.hash
[self.tokenString hash],
[self.permissions hash],
[self.declinedPermissions hash],
[self.appID hash],
[self.userID hash],
[self.refreshDate hash],
[self.expirationDate hash]
};
return [FBSDKMath hashWithIntegerArray:subhashes count:sizeof(subhashes) / sizeof(subhashes[0])];
}
@ -197,8 +149,7 @@ static FBSDKAccessToken *g_currentAccessToken;
[FBSDKInternalUtility object:self.appID isEqualToObject:token.appID] &&
[FBSDKInternalUtility object:self.userID isEqualToObject:token.userID] &&
[FBSDKInternalUtility object:self.refreshDate isEqualToObject:token.refreshDate] &&
[FBSDKInternalUtility object:self.expirationDate isEqualToObject:token.expirationDate] &&
[FBSDKInternalUtility object:self.dataAccessExpirationDate isEqualToObject:token.dataAccessExpirationDate] );
[FBSDKInternalUtility object:self.expirationDate isEqualToObject:token.expirationDate] );
}
#pragma mark - NSCopying
@ -216,7 +167,7 @@ static FBSDKAccessToken *g_currentAccessToken;
return YES;
}
- (instancetype)initWithCoder:(NSCoder *)decoder
- (id)initWithCoder:(NSCoder *)decoder
{
NSString *appID = [decoder decodeObjectOfClass:[NSString class] forKey:FBSDK_ACCESSTOKEN_APPID_KEY];
NSSet *declinedPermissions = [decoder decodeObjectOfClass:[NSSet class] forKey:FBSDK_ACCESSTOKEN_DECLINEDPERMISSIONS_KEY];
@ -225,16 +176,14 @@ static FBSDKAccessToken *g_currentAccessToken;
NSString *userID = [decoder decodeObjectOfClass:[NSString class] forKey:FBSDK_ACCESSTOKEN_USERID_KEY];
NSDate *refreshDate = [decoder decodeObjectOfClass:[NSDate class] forKey:FBSDK_ACCESSTOKEN_REFRESHDATE_KEY];
NSDate *expirationDate = [decoder decodeObjectOfClass:[NSDate class] forKey:FBSDK_ACCESSTOKEN_EXPIRATIONDATE_KEY];
NSDate *dataAccessExpirationDate = [decoder decodeObjectOfClass:[NSDate class] forKey:FBSDK_ACCESSTOKEN_DATA_EXPIRATIONDATE_KEY];
return [self initWithTokenString:tokenString
permissions:permissions.allObjects
declinedPermissions:declinedPermissions.allObjects
permissions:[permissions allObjects]
declinedPermissions:[declinedPermissions allObjects]
appID:appID
userID:userID
expirationDate:expirationDate
refreshDate:refreshDate
dataAccessExpirationDate:dataAccessExpirationDate];
refreshDate:refreshDate];
}
- (void)encodeWithCoder:(NSCoder *)encoder
@ -246,7 +195,6 @@ static FBSDKAccessToken *g_currentAccessToken;
[encoder encodeObject:self.userID forKey:FBSDK_ACCESSTOKEN_USERID_KEY];
[encoder encodeObject:self.expirationDate forKey:FBSDK_ACCESSTOKEN_EXPIRATIONDATE_KEY];
[encoder encodeObject:self.refreshDate forKey:FBSDK_ACCESSTOKEN_REFRESHDATE_KEY];
[encoder encodeObject:self.dataAccessExpirationDate forKey:FBSDK_ACCESSTOKEN_DATA_EXPIRATIONDATE_KEY];
}
@end

View File

@ -18,29 +18,18 @@
#import <Foundation/Foundation.h>
#if !TARGET_OS_TV
#import <WebKit/WebKit.h>
#endif
#import <FBSDKCoreKit/FBSDKGraphRequestConnection.h>
#import "FBSDKMacros.h"
@class FBSDKAccessToken;
@class FBSDKGraphRequest;
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0
/** NSNotificationCenter name indicating a result of a failed log flush attempt. The posted object will be an NSError instance. */
FOUNDATION_EXPORT NSNotificationName const FBSDKAppEventsLoggingResultNotification;
#else
/** NSNotificationCenter name indicating a result of a failed log flush attempt. The posted object will be an NSError instance. */
FOUNDATION_EXPORT NSString *const FBSDKAppEventsLoggingResultNotification;
#endif
FBSDK_EXTERN NSString *const FBSDKAppEventsLoggingResultNotification;
/** optional plist key ("FacebookLoggingOverrideAppID") for setting `loggingOverrideAppID` */
FOUNDATION_EXPORT NSString *const FBSDKAppEventsOverrideAppIDBundleKey;
FBSDK_EXTERN NSString *const FBSDKAppEventsOverrideAppIDBundleKey;
/**
@ -62,115 +51,46 @@ typedef NS_ENUM(NSUInteger, FBSDKAppEventsFlushBehavior)
};
/**
NS_ENUM(NSUInteger, FBSDKProductAvailability)
Specifies product availability for Product Catalog product item update
*/
typedef NS_ENUM(NSUInteger, FBSDKProductAvailability)
{
/**
* Item ships immediately
*/
FBSDKProductAvailabilityInStock = 0,
/**
* No plan to restock
*/
FBSDKProductAvailabilityOutOfStock,
/**
* Available in future
*/
FBSDKProductAvailabilityPreOrder,
/**
* Ships in 1-2 weeks
*/
FBSDKProductAvailabilityAvailableForOrder,
/**
* Discontinued
*/
FBSDKProductAvailabilityDiscontinued,
};
/**
NS_ENUM(NSUInteger, FBSDKProductCondition)
Specifies product condition for Product Catalog product item update
*/
typedef NS_ENUM(NSUInteger, FBSDKProductCondition)
{
FBSDKProductConditionNew = 0,
FBSDKProductConditionRefurbished,
FBSDKProductConditionUsed,
};
/**
@methodgroup Predefined event names for logging events common to many apps. Logging occurs through the `logEvent` family of methods on `FBSDKAppEvents`.
Common event parameters are provided in the `FBSDKAppEventsParameterNames*` constants.
*/
/** Log this event when the user has achieved a level in the app. */
FOUNDATION_EXPORT NSString *const FBSDKAppEventNameAchievedLevel;
FBSDK_EXTERN NSString *const FBSDKAppEventNameAchievedLevel;
/** Log this event when the user has entered their payment info. */
FOUNDATION_EXPORT NSString *const FBSDKAppEventNameAddedPaymentInfo;
FBSDK_EXTERN NSString *const FBSDKAppEventNameAddedPaymentInfo;
/** Log this event when the user has added an item to their cart. The valueToSum passed to logEvent should be the item's price. */
FOUNDATION_EXPORT NSString *const FBSDKAppEventNameAddedToCart;
FBSDK_EXTERN NSString *const FBSDKAppEventNameAddedToCart;
/** Log this event when the user has added an item to their wishlist. The valueToSum passed to logEvent should be the item's price. */
FOUNDATION_EXPORT NSString *const FBSDKAppEventNameAddedToWishlist;
FBSDK_EXTERN NSString *const FBSDKAppEventNameAddedToWishlist;
/** Log this event when a user has completed registration with the app. */
FOUNDATION_EXPORT NSString *const FBSDKAppEventNameCompletedRegistration;
FBSDK_EXTERN NSString *const FBSDKAppEventNameCompletedRegistration;
/** Log this event when the user has completed a tutorial in the app. */
FOUNDATION_EXPORT NSString *const FBSDKAppEventNameCompletedTutorial;
FBSDK_EXTERN NSString *const FBSDKAppEventNameCompletedTutorial;
/** Log this event when the user has entered the checkout process. The valueToSum passed to logEvent should be the total price in the cart. */
FOUNDATION_EXPORT NSString *const FBSDKAppEventNameInitiatedCheckout;
FBSDK_EXTERN NSString *const FBSDKAppEventNameInitiatedCheckout;
/** Log this event when the user has rated an item in the app. The valueToSum passed to logEvent should be the numeric rating. */
FOUNDATION_EXPORT NSString *const FBSDKAppEventNameRated;
FBSDK_EXTERN NSString *const FBSDKAppEventNameRated;
/** Log this event when a user has performed a search within the app. */
FOUNDATION_EXPORT NSString *const FBSDKAppEventNameSearched;
FBSDK_EXTERN NSString *const FBSDKAppEventNameSearched;
/** Log this event when the user has spent app credits. The valueToSum passed to logEvent should be the number of credits spent. */
FOUNDATION_EXPORT NSString *const FBSDKAppEventNameSpentCredits;
FBSDK_EXTERN NSString *const FBSDKAppEventNameSpentCredits;
/** Log this event when the user has unlocked an achievement in the app. */
FOUNDATION_EXPORT NSString *const FBSDKAppEventNameUnlockedAchievement;
FBSDK_EXTERN NSString *const FBSDKAppEventNameUnlockedAchievement;
/** Log this event when a user has viewed a form of content in the app. */
FOUNDATION_EXPORT NSString *const FBSDKAppEventNameViewedContent;
/** A telephone/SMS, email, chat or other type of contact between a customer and your business. */
FOUNDATION_EXPORT NSString *const FBSDKAppEventNameContact;
/** The customization of products through a configuration tool or other application your business owns. */
FOUNDATION_EXPORT NSString *const FBSDKAppEventNameCustomizeProduct;
/** The donation of funds to your organization or cause. */
FOUNDATION_EXPORT NSString *const FBSDKAppEventNameDonate;
/** When a person finds one of your locations via web or application, with an intention to visit (example: find product at a local store). */
FOUNDATION_EXPORT NSString *const FBSDKAppEventNameFindLocation;
/** The booking of an appointment to visit one of your locations. */
FOUNDATION_EXPORT NSString *const FBSDKAppEventNameSchedule;
/** The start of a free trial of a product or service you offer (example: trial subscription). */
FOUNDATION_EXPORT NSString *const FBSDKAppEventNameStartTrial;
/** The submission of an application for a product, service or program you offer (example: credit card, educational program or job). */
FOUNDATION_EXPORT NSString *const FBSDKAppEventNameSubmitApplication;
/** The start of a paid subscription for a product or service you offer. */
FOUNDATION_EXPORT NSString *const FBSDKAppEventNameSubscribe;
/** Log this event when the user views an ad. */
FOUNDATION_EXPORT NSString *const FBSDKAppEventNameAdImpression;
/** Log this event when the user clicks an ad. */
FOUNDATION_EXPORT NSString *const FBSDKAppEventNameAdClick;
FBSDK_EXTERN NSString *const FBSDKAppEventNameViewedContent;
/**
@methodgroup Predefined event name parameters for common additional information to accompany events logged through the `logEvent` family
@ -183,104 +103,40 @@ FOUNDATION_EXPORT NSString *const FBSDKAppEventNameAdClick;
* Example:
* "[{\"id\": \"1234\", \"quantity\": 2, \"item_price\": 5.99}, {\"id\": \"5678\", \"quantity\": 1, \"item_price\": 9.99}]"
*/
FOUNDATION_EXPORT NSString *const FBSDKAppEventParameterNameContent;
FBSDK_EXTERN NSString *const FBSDKAppEventParameterNameContent;
/** Parameter key used to specify an ID for the specific piece of content being logged about. Could be an EAN, article identifier, etc., depending on the nature of the app. */
FOUNDATION_EXPORT NSString *const FBSDKAppEventParameterNameContentID;
FBSDK_EXTERN NSString *const FBSDKAppEventParameterNameContentID;
/** Parameter key used to specify a generic content type/family for the logged event, e.g. "music", "photo", "video". Options to use will vary based upon what the app is all about. */
FOUNDATION_EXPORT NSString *const FBSDKAppEventParameterNameContentType;
FBSDK_EXTERN NSString *const FBSDKAppEventParameterNameContentType;
/** Parameter key used to specify currency used with logged event. E.g. "USD", "EUR", "GBP". See ISO-4217 for specific values. One reference for these is <http://en.wikipedia.org/wiki/ISO_4217>. */
FOUNDATION_EXPORT NSString *const FBSDKAppEventParameterNameCurrency;
FBSDK_EXTERN NSString *const FBSDKAppEventParameterNameCurrency;
/** Parameter key used to specify a description appropriate to the event being logged. E.g., the name of the achievement unlocked in the `FBAppEventNameAchievementUnlocked` event. */
FOUNDATION_EXPORT NSString *const FBSDKAppEventParameterNameDescription;
FBSDK_EXTERN NSString *const FBSDKAppEventParameterNameDescription;
/** Parameter key used to specify the level achieved in a `FBAppEventNameAchieved` event. */
FOUNDATION_EXPORT NSString *const FBSDKAppEventParameterNameLevel;
FBSDK_EXTERN NSString *const FBSDKAppEventParameterNameLevel;
/** Parameter key used to specify the maximum rating available for the `FBAppEventNameRate` event. E.g., "5" or "10". */
FOUNDATION_EXPORT NSString *const FBSDKAppEventParameterNameMaxRatingValue;
FBSDK_EXTERN NSString *const FBSDKAppEventParameterNameMaxRatingValue;
/** Parameter key used to specify how many items are being processed for an `FBAppEventNameInitiatedCheckout` or `FBAppEventNamePurchased` event. */
FOUNDATION_EXPORT NSString *const FBSDKAppEventParameterNameNumItems;
FBSDK_EXTERN NSString *const FBSDKAppEventParameterNameNumItems;
/** Parameter key used to specify whether payment info is available for the `FBAppEventNameInitiatedCheckout` event. `FBSDKAppEventParameterValueYes` and `FBSDKAppEventParameterValueNo` are good canonical values to use for this parameter. */
FOUNDATION_EXPORT NSString *const FBSDKAppEventParameterNamePaymentInfoAvailable;
FBSDK_EXTERN NSString *const FBSDKAppEventParameterNamePaymentInfoAvailable;
/** Parameter key used to specify method user has used to register for the app, e.g., "Facebook", "email", "Twitter", etc */
FOUNDATION_EXPORT NSString *const FBSDKAppEventParameterNameRegistrationMethod;
FBSDK_EXTERN NSString *const FBSDKAppEventParameterNameRegistrationMethod;
/** Parameter key used to specify the string provided by the user for a search operation. */
FOUNDATION_EXPORT NSString *const FBSDKAppEventParameterNameSearchString;
FBSDK_EXTERN NSString *const FBSDKAppEventParameterNameSearchString;
/** Parameter key used to specify whether the activity being logged about was successful or not. `FBSDKAppEventParameterValueYes` and `FBSDKAppEventParameterValueNo` are good canonical values to use for this parameter. */
FOUNDATION_EXPORT NSString *const FBSDKAppEventParameterNameSuccess;
/**
@methodgroup Predefined event name parameters for common additional information to accompany events logged through the `logProductItem` method on `FBSDKAppEvents`.
*/
/** Parameter key used to specify the product item's custom label 0. */
FOUNDATION_EXPORT NSString *const FBSDKAppEventParameterProductCustomLabel0;
/** Parameter key used to specify the product item's custom label 1. */
FOUNDATION_EXPORT NSString *const FBSDKAppEventParameterProductCustomLabel1;
/** Parameter key used to specify the product item's custom label 2. */
FOUNDATION_EXPORT NSString *const FBSDKAppEventParameterProductCustomLabel2;
/** Parameter key used to specify the product item's custom label 3. */
FOUNDATION_EXPORT NSString *const FBSDKAppEventParameterProductCustomLabel3;
/** Parameter key used to specify the product item's custom label 4. */
FOUNDATION_EXPORT NSString *const FBSDKAppEventParameterProductCustomLabel4;
/** Parameter key used to specify the product item's AppLink app URL for iOS. */
FOUNDATION_EXPORT NSString *const FBSDKAppEventParameterProductAppLinkIOSUrl;
/** Parameter key used to specify the product item's AppLink app ID for iOS App Store. */
FOUNDATION_EXPORT NSString *const FBSDKAppEventParameterProductAppLinkIOSAppStoreID;
/** Parameter key used to specify the product item's AppLink app name for iOS. */
FOUNDATION_EXPORT NSString *const FBSDKAppEventParameterProductAppLinkIOSAppName;
/** Parameter key used to specify the product item's AppLink app URL for iPhone. */
FOUNDATION_EXPORT NSString *const FBSDKAppEventParameterProductAppLinkIPhoneUrl;
/** Parameter key used to specify the product item's AppLink app ID for iPhone App Store. */
FOUNDATION_EXPORT NSString *const FBSDKAppEventParameterProductAppLinkIPhoneAppStoreID;
/** Parameter key used to specify the product item's AppLink app name for iPhone. */
FOUNDATION_EXPORT NSString *const FBSDKAppEventParameterProductAppLinkIPhoneAppName;
/** Parameter key used to specify the product item's AppLink app URL for iPad. */
FOUNDATION_EXPORT NSString *const FBSDKAppEventParameterProductAppLinkIPadUrl;
/** Parameter key used to specify the product item's AppLink app ID for iPad App Store. */
FOUNDATION_EXPORT NSString *const FBSDKAppEventParameterProductAppLinkIPadAppStoreID;
/** Parameter key used to specify the product item's AppLink app name for iPad. */
FOUNDATION_EXPORT NSString *const FBSDKAppEventParameterProductAppLinkIPadAppName;
/** Parameter key used to specify the product item's AppLink app URL for Android. */
FOUNDATION_EXPORT NSString *const FBSDKAppEventParameterProductAppLinkAndroidUrl;
/** Parameter key used to specify the product item's AppLink fully-qualified package name for intent generation. */
FOUNDATION_EXPORT NSString *const FBSDKAppEventParameterProductAppLinkAndroidPackage;
/** Parameter key used to specify the product item's AppLink app name for Android. */
FOUNDATION_EXPORT NSString *const FBSDKAppEventParameterProductAppLinkAndroidAppName;
/** Parameter key used to specify the product item's AppLink app URL for Windows Phone. */
FOUNDATION_EXPORT NSString *const FBSDKAppEventParameterProductAppLinkWindowsPhoneUrl;
/** Parameter key used to specify the product item's AppLink app ID, as a GUID, for App Store. */
FOUNDATION_EXPORT NSString *const FBSDKAppEventParameterProductAppLinkWindowsPhoneAppID;
/** Parameter key used to specify the product item's AppLink app name for Windows Phone. */
FOUNDATION_EXPORT NSString *const FBSDKAppEventParameterProductAppLinkWindowsPhoneAppName;
FBSDK_EXTERN NSString *const FBSDKAppEventParameterNameSuccess;
/*
@methodgroup Predefined values to assign to event parameters that accompany events logged through the `logEvent` family
@ -288,19 +144,11 @@ FOUNDATION_EXPORT NSString *const FBSDKAppEventParameterProductAppLinkWindowsPho
*/
/** Yes-valued parameter value to be used with parameter keys that need a Yes/No value */
FOUNDATION_EXPORT NSString *const FBSDKAppEventParameterValueYes;
FBSDK_EXTERN NSString *const FBSDKAppEventParameterValueYes;
/** No-valued parameter value to be used with parameter keys that need a Yes/No value */
FOUNDATION_EXPORT NSString *const FBSDKAppEventParameterValueNo;
FBSDK_EXTERN NSString *const FBSDKAppEventParameterValueNo;
/** Parameter key used to specify the type of ad in an FBSDKAppEventNameAdImpression
* or FBSDKAppEventNameAdClick event.
* E.g. "banner", "interstitial", "rewarded_video", "native" */
FOUNDATION_EXPORT NSString *const FBSDKAppEventParameterNameAdType;
/** Parameter key used to specify the unique ID for all events within a subscription
* in an FBSDKAppEventNameSubscribe or FBSDKAppEventNameStartTrial event. */
FOUNDATION_EXPORT NSString *const FBSDKAppEventParameterNameOrderID;
/**
@ -361,7 +209,7 @@ FOUNDATION_EXPORT NSString *const FBSDKAppEventParameterNameOrderID;
Log an event with just an eventName.
@param eventName The name of the event to record. Limitations on number of events and name length
- Parameter eventName: The name of the event to record. Limitations on number of events and name length
are given in the `FBSDKAppEvents` documentation.
*/
@ -371,10 +219,10 @@ FOUNDATION_EXPORT NSString *const FBSDKAppEventParameterNameOrderID;
Log an event with an eventName and a numeric value to be aggregated with other events of this name.
@param eventName The name of the event to record. Limitations on number of events and name length
- Parameter eventName: The name of the event to record. Limitations on number of events and name length
are given in the `FBSDKAppEvents` documentation. Common event names are provided in `FBAppEventName*` constants.
@param valueToSum Amount to be aggregated into all events of this eventName, and App Insights will report
- Parameter valueToSum: Amount to be aggregated into all events of this eventName, and App Insights will report
the cumulative and average value of this amount.
*/
+ (void)logEvent:(NSString *)eventName
@ -386,10 +234,10 @@ FOUNDATION_EXPORT NSString *const FBSDKAppEventParameterNameOrderID;
Log an event with an eventName and a set of key/value pairs in the parameters dictionary.
Parameter limitations are described above.
@param eventName The name of the event to record. Limitations on number of events and name construction
- Parameter eventName: The name of the event to record. Limitations on number of events and name construction
are given in the `FBSDKAppEvents` documentation. Common event names are provided in `FBAppEventName*` constants.
@param parameters Arbitrary parameter dictionary of characteristics. The keys to this dictionary must
- Parameter parameters: Arbitrary parameter dictionary of characteristics. The keys to this dictionary must
be NSString's, and the values are expected to be NSString or NSNumber. Limitations on the number of
parameters and name construction are given in the `FBSDKAppEvents` documentation. Commonly used parameter names
are provided in `FBSDKAppEventParameterName*` constants.
@ -402,13 +250,13 @@ FOUNDATION_EXPORT NSString *const FBSDKAppEventParameterNameOrderID;
Log an event with an eventName, a numeric value to be aggregated with other events of this name,
and a set of key/value pairs in the parameters dictionary.
@param eventName The name of the event to record. Limitations on number of events and name construction
- Parameter eventName: The name of the event to record. Limitations on number of events and name construction
are given in the `FBSDKAppEvents` documentation. Common event names are provided in `FBAppEventName*` constants.
@param valueToSum Amount to be aggregated into all events of this eventName, and App Insights will report
- Parameter valueToSum: Amount to be aggregated into all events of this eventName, and App Insights will report
the cumulative and average value of this amount.
@param parameters Arbitrary parameter dictionary of characteristics. The keys to this dictionary must
- Parameter parameters: Arbitrary parameter dictionary of characteristics. The keys to this dictionary must
be NSString's, and the values are expected to be NSString or NSNumber. Limitations on the number of
parameters and name construction are given in the `FBSDKAppEvents` documentation. Commonly used parameter names
are provided in `FBSDKAppEventParameterName*` constants.
@ -425,19 +273,19 @@ FOUNDATION_EXPORT NSString *const FBSDKAppEventParameterNameOrderID;
and a set of key/value pairs in the parameters dictionary. Providing session lets the developer
target a particular <FBSession>. If nil is provided, then `[FBSession activeSession]` will be used.
@param eventName The name of the event to record. Limitations on number of events and name construction
- Parameter eventName: The name of the event to record. Limitations on number of events and name construction
are given in the `FBSDKAppEvents` documentation. Common event names are provided in `FBAppEventName*` constants.
@param valueToSum Amount to be aggregated into all events of this eventName, and App Insights will report
- Parameter valueToSum: Amount to be aggregated into all events of this eventName, and App Insights will report
the cumulative and average value of this amount. Note that this is an NSNumber, and a value of `nil` denotes
that this event doesn't have a value associated with it for summation.
@param parameters Arbitrary parameter dictionary of characteristics. The keys to this dictionary must
- Parameter parameters: Arbitrary parameter dictionary of characteristics. The keys to this dictionary must
be NSString's, and the values are expected to be NSString or NSNumber. Limitations on the number of
parameters and name construction are given in the `FBSDKAppEvents` documentation. Commonly used parameter names
are provided in `FBSDKAppEventParameterName*` constants.
@param accessToken The optional access token to log the event as.
- Parameter accessToken: The optional access token to log the event as.
*/
+ (void)logEvent:(NSString *)eventName
valueToSum:(NSNumber *)valueToSum
@ -452,10 +300,10 @@ FOUNDATION_EXPORT NSString *const FBSDKAppEventParameterNameOrderID;
Log a purchase of the specified amount, in the specified currency.
@param purchaseAmount Purchase amount to be logged, as expressed in the specified currency. This value
- Parameter purchaseAmount: Purchase amount to be logged, as expressed in the specified currency. This value
will be rounded to the thousandths place (e.g., 12.34567 becomes 12.346).
@param currency Currency, is denoted as, e.g. "USD", "EUR", "GBP". See ISO-4217 for
- Parameter currency: Currency, is denoted as, e.g. "USD", "EUR", "GBP". See ISO-4217 for
specific values. One reference for these is <http://en.wikipedia.org/wiki/ISO_4217>.
@ -471,13 +319,13 @@ FOUNDATION_EXPORT NSString *const FBSDKAppEventParameterNameOrderID;
Log a purchase of the specified amount, in the specified currency, also providing a set of
additional characteristics describing the purchase.
@param purchaseAmount Purchase amount to be logged, as expressed in the specified currency.This value
- Parameter purchaseAmount: Purchase amount to be logged, as expressed in the specified currency.This value
will be rounded to the thousandths place (e.g., 12.34567 becomes 12.346).
@param currency Currency, is denoted as, e.g. "USD", "EUR", "GBP". See ISO-4217 for
- Parameter currency: Currency, is denoted as, e.g. "USD", "EUR", "GBP". See ISO-4217 for
specific values. One reference for these is <http://en.wikipedia.org/wiki/ISO_4217>.
@param parameters Arbitrary parameter dictionary of characteristics. The keys to this dictionary must
- Parameter parameters: Arbitrary parameter dictionary of characteristics. The keys to this dictionary must
be NSString's, and the values are expected to be NSString or NSNumber. Limitations on the number of
parameters and name construction are given in the `FBSDKAppEvents` documentation. Commonly used parameter names
are provided in `FBSDKAppEventParameterName*` constants.
@ -496,18 +344,18 @@ FOUNDATION_EXPORT NSString *const FBSDKAppEventParameterNameOrderID;
Log a purchase of the specified amount, in the specified currency, also providing a set of
additional characteristics describing the purchase, as well as an <FBSession> to log to.
@param purchaseAmount Purchase amount to be logged, as expressed in the specified currency.This value
- Parameter purchaseAmount: Purchase amount to be logged, as expressed in the specified currency.This value
will be rounded to the thousandths place (e.g., 12.34567 becomes 12.346).
@param currency Currency, is denoted as, e.g. "USD", "EUR", "GBP". See ISO-4217 for
- Parameter currency: Currency, is denoted as, e.g. "USD", "EUR", "GBP". See ISO-4217 for
specific values. One reference for these is <http://en.wikipedia.org/wiki/ISO_4217>.
@param parameters Arbitrary parameter dictionary of characteristics. The keys to this dictionary must
- Parameter parameters: Arbitrary parameter dictionary of characteristics. The keys to this dictionary must
be NSString's, and the values are expected to be NSString or NSNumber. Limitations on the number of
parameters and name construction are given in the `FBSDKAppEvents` documentation. Commonly used parameter names
are provided in `FBSDKAppEventParameterName*` constants.
@param accessToken The optional access token to log the event as.
- Parameter accessToken: The optional access token to log the event as.
This event immediately triggers a flush of the `FBSDKAppEvents` event queue, unless the `flushBehavior` is set
@ -527,58 +375,18 @@ FOUNDATION_EXPORT NSString *const FBSDKAppEventParameterNameOrderID;
/**
Log an app event that tracks that the application was open via Push Notification.
@param payload Notification payload received via `UIApplicationDelegate`.
- Parameter payload: Notification payload received via `UIApplicationDelegate`.
*/
+ (void)logPushNotificationOpen:(NSDictionary *)payload;
/**
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.
- Parameter payload: Notification payload received via `UIApplicationDelegate`.
- Parameter action: Name of the action that was taken.
*/
+ (void)logPushNotificationOpen:(NSDictionary *)payload action:(NSString *)action;
/**
Uploads product catalog product item as an app event
@param itemID Unique ID for the item. Can be a variant for a product.
Max size is 100.
@param availability If item is in stock. Accepted values are:
in stock - Item ships immediately
out of stock - No plan to restock
preorder - Available in future
available for order - Ships in 1-2 weeks
discontinued - Discontinued
@param condition Product condition: new, refurbished or used.
@param description Short text describing product. Max size is 5000.
@param imageLink Link to item image used in ad.
@param link Link to merchant's site where someone can buy the item.
@param title Title of item.
@param priceAmount Amount of purchase, in the currency specified by the 'currency'
parameter. This value will be rounded to the thousandths place
(e.g., 12.34567 becomes 12.346).
@param currency Currency used to specify the amount.
E.g. "USD", "EUR", "GBP". See ISO-4217 for specific values. One reference for these is <http://en.wikipedia.org/wiki/ISO_4217>
@param gtin Global Trade Item Number including UPC, EAN, JAN and ISBN
@param mpn Unique manufacture ID for product
@param brand Name of the brand
Note: Either gtin, mpn or brand is required.
@param parameters Optional fields for deep link specification.
*/
+ (void)logProductItem:(NSString *)itemID
availability:(FBSDKProductAvailability)availability
condition:(FBSDKProductCondition)condition
description:(NSString *)description
imageLink:(NSString *)imageLink
link:(NSString *)link
title:(NSString *)title
priceAmount:(double)priceAmount
currency:(NSString *)currency
gtin:(NSString *)gtin
mpn:(NSString *)mpn
brand:(NSString *)brand
parameters:(NSDictionary *)parameters;
/**
Notifies the events system that the app has launched and, when appropriate, logs an "activated app" event.
@ -601,7 +409,7 @@ FOUNDATION_EXPORT NSString *const FBSDKAppEventParameterNameOrderID;
+ (void)activateApp;
/*
* Push Notifications Registration and Uninstall Tracking
* Push Notifications Registration
*/
/**
@ -611,21 +419,10 @@ FOUNDATION_EXPORT NSString *const FBSDKAppEventParameterNameOrderID;
Sets and sends a device token from `NSData` representation that you get from `UIApplicationDelegate.-application:didRegisterForRemoteNotificationsWithDeviceToken:`.
@param deviceToken Device token data.
- Parameter deviceToken: Device token data.
*/
+ (void)setPushNotificationsDeviceToken:(NSData *)deviceToken;
/**
Sets and sends device token string to register the current application for push notifications.
Sets and sends a device token string
@param deviceTokenString Device token string.
*/
+ (void)setPushNotificationsDeviceTokenString:(NSString *)deviceTokenString;
/*
* Control over event batching/flushing
*/
@ -640,7 +437,7 @@ FOUNDATION_EXPORT NSString *const FBSDKAppEventParameterNameOrderID;
Set the current event flushing behavior specifying when events are sent back to Facebook servers.
@param flushBehavior The desired `FBSDKAppEventsFlushBehavior` to be used.
- Parameter flushBehavior: The desired `FBSDKAppEventsFlushBehavior` to be used.
*/
+ (void)setFlushBehavior:(FBSDKAppEventsFlushBehavior)flushBehavior;
@ -657,7 +454,7 @@ FOUNDATION_EXPORT NSString *const FBSDKAppEventParameterNameOrderID;
This should be set before any other calls are made to `FBSDKAppEvents`. Thus, you should set it in your application
delegate's `application:didFinishLaunchingWithOptions:` delegate.
@param appID The Facebook App ID to be used for App Event logging.
- Parameter appID: The Facebook App ID to be used for App Event logging.
*/
+ (void)setLoggingOverrideAppID:(NSString *)appID;
@ -665,7 +462,7 @@ FOUNDATION_EXPORT NSString *const FBSDKAppEventParameterNameOrderID;
Get the 'override' App ID for App Event logging.
@see setLoggingOverrideAppID:
- See:setLoggingOverrideAppID:
*/
+ (NSString *)loggingOverrideAppID;
@ -682,7 +479,7 @@ FOUNDATION_EXPORT NSString *const FBSDKAppEventParameterNameOrderID;
Callers will send this ID back to their own servers, collect up a set to create a Facebook Custom Audience with,
and then use the resultant Custom Audience to target ads.
@param accessToken The access token to use to establish the user's identity for users logged into Facebook through this app.
- Parameter accessToken: The access token to use to establish the user's identity for users logged into Facebook through this app.
If `nil`, then the `[FBSDKAccessToken currentAccessToken]` is used.
@ -709,114 +506,18 @@ FOUNDATION_EXPORT NSString *const FBSDKAppEventParameterNameOrderID;
*/
+ (void)setUserID:(NSString *)userID;
/*
Clears the custom user ID to associate with all app events.
*/
+ (void)clearUserID;
/*
Returns the set custom user ID.
*/
+ (NSString *)userID;
/*
Sets custom user data to associate with all app events. All user data are hashed
and used to match Facebook user from this instance of an application.
The user data will be persisted between application instances.
@param userData user data to identify the user. User data should be formated as
a NSDictionary of data type name and value.
Supported data types and names are:
Email: em
First Name: fn
Last Name: ln
Phone: ph
Date of Birth: db
Gender: ge
City: ct
State: st
Zip: zp
Country: country
*/
+ (void)setUserData:(NSDictionary *)userData
DEPRECATED_MSG_ATTRIBUTE("Renamed `setUserEmail:firstName: ...`");
/*
Sets custom user data to associate with all app events. All user data are hashed
and used to match Facebook user from this instance of an application.
The user data will be persisted between application instances.
@param email user's email
@param firstName user's first name
@param lastName user's last name
@param phone user's phone
@param dateOfBirth user's date of birth
@param gender user's gender
@param city user's city
@param state user's state
@param zip user's zip
@param country user's country
*/
+ (void)setUserEmail:(NSString *)email
firstName:(NSString *)firstName
lastName:(NSString *)lastName
phone:(NSString *)phone
dateOfBirth:(NSString *)dateOfBirth
gender:(NSString *)gender
city:(NSString *)city
state:(NSString *)state
zip:(NSString *)zip
country:(NSString *)country;
/*
Returns the set user data else nil
*/
+ (NSString *)getUserData;
/*
Clears the current user data
*/
+ (void)clearUserData;
/*
Sends a request to update the properties for the current user, set by `setUserID:`
You must call `FBSDKAppEvents setUserID:` before making this call.
@param properties the custom user properties
@param handler the optional completion handler
- Parameter properties: the custom user properties
- Parameter handler: the optional completion handler
*/
+ (void)updateUserProperties:(NSDictionary *)properties handler:(FBSDKGraphRequestHandler)handler;
#if !TARGET_OS_TV
/*
Intended to be used as part of a hybrid webapp.
If you call this method, the FB SDK will inject a new JavaScript object into your webview.
If the FB Pixel is used within the webview, and references the app ID of this app,
then it will detect the presence of this injected JavaScript object
and pass Pixel events back to the FB SDK for logging using the AppEvents framework.
@param webView The webview to augment with the additional JavaScript behaviour
*/
+ (void)augmentHybridWKWebView:(WKWebView *)webView;
#endif
/*
* Unity helper functions
*/
/**
Set if the Unity is already initialized
@param isUnityInit whether Unity is initialized.
*/
+ (void)setIsUnityInit:(BOOL)isUnityInit;
/*
Send event binding to Unity
*/
+ (void)sendEventBindingsToUnity;
@end

View File

@ -19,8 +19,6 @@
#import "FBSDKAppEvents.h"
#import "FBSDKAppEvents+Internal.h"
#import <objc/runtime.h>
#import <UIKit/UIApplication.h>
#import "FBSDKAccessToken.h"
@ -28,7 +26,6 @@
#import "FBSDKAppEventsStateManager.h"
#import "FBSDKAppEventsUtility.h"
#import "FBSDKConstants.h"
#import "FBSDKDynamicFrameworkLoader.h"
#import "FBSDKError.h"
#import "FBSDKGraphRequest+Internal.h"
#import "FBSDKInternalUtility.h"
@ -39,12 +36,6 @@
#import "FBSDKSettings.h"
#import "FBSDKTimeSpentData.h"
#import "FBSDKUtility.h"
#import "FBSDKUserDataStore.h"
#if !TARGET_OS_TV
#import "FBSDKEventBindingManager.h"
#import "FBSDKHybridAppEventsScriptMessageHandler.h"
#endif
//
// Public event names
@ -56,23 +47,13 @@ NSString *const FBSDKAppEventNameViewedContent = @"fb_mobile_content_v
NSString *const FBSDKAppEventNameSearched = @"fb_mobile_search";
NSString *const FBSDKAppEventNameRated = @"fb_mobile_rate";
NSString *const FBSDKAppEventNameCompletedTutorial = @"fb_mobile_tutorial_completion";
NSString *const FBSDKAppEventNameContact = @"Contact";
NSString *const FBSDKAppEventNameCustomizeProduct = @"CustomizeProduct";
NSString *const FBSDKAppEventNameDonate = @"Donate";
NSString *const FBSDKAppEventNameFindLocation = @"FindLocation";
NSString *const FBSDKAppEventNameSchedule = @"Schedule";
NSString *const FBSDKAppEventNameStartTrial = @"StartTrial";
NSString *const FBSDKAppEventNameSubmitApplication = @"SubmitApplication";
NSString *const FBSDKAppEventNameSubscribe = @"Subscribe";
NSString *const FBSDKAppEventNameAdImpression = @"AdImpression";
NSString *const FBSDKAppEventNameAdClick = @"AdClick";
NSString *const FBSDKAppEventParameterLaunchSource = @"fb_mobile_launch_source";
// Ecommerce related
NSString *const FBSDKAppEventNameAddedToCart = @"fb_mobile_add_to_cart";
NSString *const FBSDKAppEventNameAddedToWishlist = @"fb_mobile_add_to_wishlist";
NSString *const FBSDKAppEventNameInitiatedCheckout = @"fb_mobile_initiated_checkout";
NSString *const FBSDKAppEventNameAddedPaymentInfo = @"fb_mobile_add_payment_info";
NSString *const FBSDKAppEventNameProductCatalogUpdate = @"fb_mobile_catalog_update";
// Gaming related
NSString *const FBSDKAppEventNameAchievedLevel = @"fb_mobile_level_achieved";
@ -95,34 +76,6 @@ NSString *const FBSDKAppEventParameterNamePaymentInfoAvailable = @"fb_payment_
NSString *const FBSDKAppEventParameterNameNumItems = @"fb_num_items";
NSString *const FBSDKAppEventParameterNameLevel = @"fb_level";
NSString *const FBSDKAppEventParameterNameDescription = @"fb_description";
NSString *const FBSDKAppEventParameterLaunchSource = @"fb_mobile_launch_source";
NSString *const FBSDKAppEventParameterNameAdType = @"ad_type";
NSString *const FBSDKAppEventParameterNameOrderID = @"fb_order_id";
//
// Public event parameter names for DPA Catalog
//
NSString *const FBSDKAppEventParameterProductCustomLabel0 = @"fb_product_custom_label_0";
NSString *const FBSDKAppEventParameterProductCustomLabel1 = @"fb_product_custom_label_1";
NSString *const FBSDKAppEventParameterProductCustomLabel2 = @"fb_product_custom_label_2";
NSString *const FBSDKAppEventParameterProductCustomLabel3 = @"fb_product_custom_label_3";
NSString *const FBSDKAppEventParameterProductCustomLabel4 = @"fb_product_custom_label_4";
NSString *const FBSDKAppEventParameterProductAppLinkIOSUrl = @"fb_product_applink_ios_url";
NSString *const FBSDKAppEventParameterProductAppLinkIOSAppStoreID = @"fb_product_applink_ios_app_store_id";
NSString *const FBSDKAppEventParameterProductAppLinkIOSAppName = @"fb_product_applink_ios_app_name";
NSString *const FBSDKAppEventParameterProductAppLinkIPhoneUrl = @"fb_product_applink_iphone_url";
NSString *const FBSDKAppEventParameterProductAppLinkIPhoneAppStoreID = @"fb_product_applink_iphone_app_store_id";
NSString *const FBSDKAppEventParameterProductAppLinkIPhoneAppName = @"fb_product_applink_iphone_app_name";
NSString *const FBSDKAppEventParameterProductAppLinkIPadUrl = @"fb_product_applink_ipad_url";
NSString *const FBSDKAppEventParameterProductAppLinkIPadAppStoreID = @"fb_product_applink_ipad_app_store_id";
NSString *const FBSDKAppEventParameterProductAppLinkIPadAppName = @"fb_product_applink_ipad_app_name";
NSString *const FBSDKAppEventParameterProductAppLinkAndroidUrl = @"fb_product_applink_android_url";
NSString *const FBSDKAppEventParameterProductAppLinkAndroidPackage = @"fb_product_applink_android_package";
NSString *const FBSDKAppEventParameterProductAppLinkAndroidAppName = @"fb_product_applink_android_app_name";
NSString *const FBSDKAppEventParameterProductAppLinkWindowsPhoneUrl = @"fb_product_applink_windows_phone_url";
NSString *const FBSDKAppEventParameterProductAppLinkWindowsPhoneAppID = @"fb_product_applink_windows_phone_app_id";
NSString *const FBSDKAppEventParameterProductAppLinkWindowsPhoneAppName = @"fb_product_applink_windows_phone_app_name";
//
// Public event parameter values
@ -169,7 +122,6 @@ NSString *const FBSDKAppEventNameFBSDKLikeButtonImpression = @"fb_like_bu
NSString *const FBSDKAppEventNameFBSDKLoginButtonImpression = @"fb_login_button_impression";
NSString *const FBSDKAppEventNameFBSDKSendButtonImpression = @"fb_send_button_impression";
NSString *const FBSDKAppEventNameFBSDKShareButtonImpression = @"fb_share_button_impression";
NSString *const FBSDKAppEventNameFBSDKLiveStreamingButtonImpression = @"fb_live_streaming_button_impression";
NSString *const FBSDKAppEventNameFBSDKSmartLoginService = @"fb_smart_login_service";
@ -177,7 +129,6 @@ NSString *const FBSDKAppEventNameFBSDKLikeButtonDidTap = @"fb_like_button_did_t
NSString *const FBSDKAppEventNameFBSDKLoginButtonDidTap = @"fb_login_button_did_tap";
NSString *const FBSDKAppEventNameFBSDKSendButtonDidTap = @"fb_send_button_did_tap";
NSString *const FBSDKAppEventNameFBSDKShareButtonDidTap = @"fb_share_button_did_tap";
NSString *const FBSDKAppEventNameFBSDKLiveStreamingButtonDidTap = @"fb_live_streaming_button_did_tap";
NSString *const FBSDKAppEventNameFBSDKLikeControlDidDisable = @"fb_like_control_did_disable";
NSString *const FBSDKAppEventNameFBSDKLikeControlDidLike = @"fb_like_control_did_like";
@ -198,16 +149,6 @@ NSString *const FBSDKAppEventNameFBSDKEventAppInviteShareDialogShow = @"fb_app
NSString *const FBSDKAppEventNameFBSessionFASLoginDialogResult = @"fb_mobile_login_fas_dialog_result";
NSString *const FBSDKAppEventNameFBSDKLiveStreamingStart = @"fb_sdk_live_streaming_start";
NSString *const FBSDKAppEventNameFBSDKLiveStreamingStop = @"fb_sdk_live_streaming_stop";
NSString *const FBSDKAppEventNameFBSDKLiveStreamingPause = @"fb_sdk_live_streaming_pause";
NSString *const FBSDKAppEventNameFBSDKLiveStreamingResume = @"fb_sdk_live_streaming_resume";
NSString *const FBSDKAppEventNameFBSDKLiveStreamingError = @"fb_sdk_live_streaming_error";
NSString *const FBSDKAppEventNameFBSDKLiveStreamingUpdateStatus = @"fb_sdk_live_streaming_update_status";
NSString *const FBSDKAppEventNameFBSDKLiveStreamingVideoID = @"fb_sdk_live_streaming_video_id";
NSString *const FBSDKAppEventNameFBSDKLiveStreamingMic = @"fb_sdk_live_streaming_mic";
NSString *const FBSDKAppEventNameFBSDKLiveStreamingCamera = @"fb_sdk_live_streaming_camera";
// Event Parameters internal to this file
NSString *const FBSDKAppEventParameterDialogOutcome = @"fb_dialog_outcome";
NSString *const FBSDKAppEventParameterDialogErrorMessage = @"fb_dialog_outcome_error_message";
@ -221,26 +162,6 @@ NSString *const FBSDKAppEventParameterLogTime = @"_logTime";
NSString *const FBSDKAppEventParameterEventName = @"_eventName";
NSString *const FBSDKAppEventParameterImplicitlyLogged = @"_implicitlyLogged";
NSString *const FBSDKAppEventParameterLiveStreamingPrevStatus = @"live_streaming_prev_status";
NSString *const FBSDKAppEventParameterLiveStreamingStatus = @"live_streaming_status";
NSString *const FBSDKAppEventParameterLiveStreamingError = @"live_streaming_error";
NSString *const FBSDKAppEventParameterLiveStreamingVideoID = @"live_streaming_video_id";
NSString *const FBSDKAppEventParameterLiveStreamingMicEnabled = @"live_streaming_mic_enabled";
NSString *const FBSDKAppEventParameterLiveStreamingCameraEnabled = @"live_streaming_camera_enabled";
NSString *const FBSDKAppEventParameterProductItemID = @"fb_product_item_id";
NSString *const FBSDKAppEventParameterProductAvailability = @"fb_product_availability";
NSString *const FBSDKAppEventParameterProductCondition = @"fb_product_condition";
NSString *const FBSDKAppEventParameterProductDescription = @"fb_product_description";
NSString *const FBSDKAppEventParameterProductImageLink = @"fb_product_image_link";
NSString *const FBSDKAppEventParameterProductLink = @"fb_product_link";
NSString *const FBSDKAppEventParameterProductTitle = @"fb_product_title";
NSString *const FBSDKAppEventParameterProductGTIN = @"fb_product_gtin";
NSString *const FBSDKAppEventParameterProductMPN = @"fb_product_mpn";
NSString *const FBSDKAppEventParameterProductBrand = @"fb_product_brand";
NSString *const FBSDKAppEventParameterProductPriceAmount = @"fb_product_price_amount";
NSString *const FBSDKAppEventParameterProductPriceCurrency = @"fb_product_price_currency";
// Event parameter values internal to this file
NSString *const FBSDKAppEventsDialogOutcomeValue_Completed = @"Completed";
NSString *const FBSDKAppEventsDialogOutcomeValue_Cancelled = @"Cancelled";
@ -265,16 +186,8 @@ NSString *const FBSDKAppEventsDialogShareContentTypeMessengerMediaTemplate
NSString *const FBSDKAppEventsDialogShareContentTypeMessengerOpenGraphMusicTemplate = @"OpenGraphMusicTemplate";
NSString *const FBSDKAppEventsDialogShareContentTypeUnknown = @"Unknown";
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0
NSNotificationName const FBSDKAppEventsLoggingResultNotification = @"com.facebook.sdk:FBSDKAppEventsLoggingResultNotification";
#else
NSString *const FBSDKAppEventsLoggingResultNotification = @"com.facebook.sdk:FBSDKAppEventsLoggingResultNotification";
#endif
NSString *const FBSDKAppEventsOverrideAppIDBundleKey = @"FacebookLoggingOverrideAppID";
//
@ -292,52 +205,31 @@ static NSString *const FBSDKAppEventParameterPushAction = @"fb_push_action";
static NSString *const FBSDKAppEventsPushPayloadKey = @"fb_push_payload";
static NSString *const FBSDKAppEventsPushPayloadCampaignKey = @"campaign";
//
// Augmentation of web browser constants
//
NSString *const FBSDKAppEventsWKWebViewMessagesPixelIDKey = @"pixelID";
NSString *const FBSDKAppEventsWKWebViewMessagesHandlerKey = @"fbmqHandler";
NSString *const FBSDKAppEventsWKWebViewMessagesEventKey = @"event";
NSString *const FBSDKAppEventsWKWebViewMessagesParamsKey = @"params";
NSString *const FBSDKAPPEventsWKWebViewMessagesProtocolKey = @"fbmq-0.1";
#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
#define USER_ID_USER_DEFAULTS_KEY @"com.facebook.sdk.appevents.userid"
#define FBUnityUtilityClassName "FBUnityUtility"
#define FBUnityUtilityUpdateBindingsSelector @"triggerUpdateBindings:"
#define UNINSTALL_TRACKING_DEVICE_ID_KEY @"device_id"
#define UNINSTALL_TRACKING_PLATFORM_KEY @"platform"
#define UNINSTALL_TRACKING_DEVICE_TOKEN_KEY @"device_token"
#define UNINSTALL_TRACKING_TOKEN_ENDPOINT @"app_push_device_token"
static NSString *g_overrideAppID = nil;
@interface FBSDKAppEvents ()
@property (nonatomic, assign) FBSDKAppEventsFlushBehavior flushBehavior;
@property (nonatomic, readwrite) FBSDKAppEventsFlushBehavior flushBehavior;
//for testing only.
@property (nonatomic, assign) BOOL disableTimer;
@property (nonatomic, copy) NSString *pushNotificationsDeviceTokenString;
@property (nonatomic, strong) dispatch_source_t flushTimer;
@end
@implementation FBSDKAppEvents
{
BOOL _explicitEventsLoggedYet;
NSTimer *_flushTimer;
NSTimer *_attributionIDRecheckTimer;
FBSDKServerConfiguration *_serverConfiguration;
FBSDKAppEventsState *_appEventsState;
#if !TARGET_OS_TV
FBSDKEventBindingManager *_eventBindingManager;
#endif
NSString *_userID;
BOOL _isUnityInit;
}
#pragma mark - Object Lifecycle
@ -354,45 +246,50 @@ static NSString *g_overrideAppID = nil;
self = [super init];
if (self) {
_flushBehavior = FBSDKAppEventsFlushBehaviorAuto;
_flushTimer = [NSTimer timerWithTimeInterval:FLUSH_PERIOD_IN_SECONDS
target:self
selector:@selector(flushTimerFired:)
userInfo:nil
repeats:YES];
_attributionIDRecheckTimer = [NSTimer timerWithTimeInterval:APP_SUPPORTS_ATTRIBUTION_ID_RECHECK_PERIOD
target:self
selector:@selector(appSettingsFetchStateResetTimerFired:)
userInfo:nil
repeats:YES];
[[NSRunLoop mainRunLoop] addTimer:_flushTimer forMode:NSDefaultRunLoopMode];
[[NSRunLoop mainRunLoop] addTimer:_attributionIDRecheckTimer forMode:NSDefaultRunLoopMode];
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:@selector(applicationMovingFromActiveStateOrTerminating)
name:UIApplicationWillResignActiveNotification
object:NULL];
typeof(self) __weak weakSelf = self;
self.flushTimer = [FBSDKUtility startGCDTimerWithInterval:FLUSH_PERIOD_IN_SECONDS
block:^{
[weakSelf flushTimerFired:nil];
}];
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:@selector(applicationMovingFromActiveStateOrTerminating)
name:UIApplicationWillTerminateNotification
object:NULL];
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:@selector(applicationDidBecomeActive)
name:UIApplicationDidBecomeActiveNotification
object:NULL];
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
_userID = [defaults stringForKey:USER_ID_USER_DEFAULTS_KEY];
[self fetchServerConfiguration:nil];
}
return self;
}
- (void)registerNotifications {
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:@selector(applicationMovingFromActiveStateOrTerminating)
name:UIApplicationWillResignActiveNotification
object:NULL];
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:@selector(applicationMovingFromActiveStateOrTerminating)
name:UIApplicationWillTerminateNotification
object:NULL];
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:@selector(applicationDidBecomeActive)
name:UIApplicationDidBecomeActiveNotification
object:NULL];
}
- (void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
[FBSDKUtility stopGCDTimer:self.flushTimer];
// technically these timers retain self so there's a cycle but
// we're a singleton anyway.
[_flushTimer invalidate];
[_attributionIDRecheckTimer invalidate];
}
#pragma mark - Public Methods
@ -425,7 +322,7 @@ static NSString *g_overrideAppID = nil;
parameters:(NSDictionary *)parameters
{
[FBSDKAppEvents logEvent:eventName
valueToSum:@(valueToSum)
valueToSum:[NSNumber numberWithDouble:valueToSum]
parameters:parameters
accessToken:nil];
}
@ -477,7 +374,7 @@ static NSString *g_overrideAppID = nil;
}
[FBSDKAppEvents logEvent:FBSDKAppEventNamePurchased
valueToSum:@(purchaseAmount)
valueToSum:[NSNumber numberWithDouble:purchaseAmount]
parameters:newParameters
accessToken:accessToken];
@ -517,109 +414,6 @@ static NSString *g_overrideAppID = nil;
[self logEvent:FBSDKAppEventNamePushOpened parameters:parameters];
}
/*
* Uploads product catalog product item as an app event
*/
+ (void)logProductItem:(NSString *)itemID
availability:(FBSDKProductAvailability)availability
condition:(FBSDKProductCondition)condition
description:(NSString *)description
imageLink:(NSString *)imageLink
link:(NSString *)link
title:(NSString *)title
priceAmount:(double)priceAmount
currency:(NSString *)currency
gtin:(NSString *)gtin
mpn:(NSString *)mpn
brand:(NSString *)brand
parameters:(NSDictionary *)parameters {
if (itemID == nil) {
[FBSDKLogger singleShotLogEntry:FBSDKLoggingBehaviorDeveloperErrors
logEntry:@"itemID cannot be null"];
return;
} else if (description == nil) {
[FBSDKLogger singleShotLogEntry:FBSDKLoggingBehaviorDeveloperErrors
logEntry:@"description cannot be null"];
return;
} else if (imageLink == nil) {
[FBSDKLogger singleShotLogEntry:FBSDKLoggingBehaviorDeveloperErrors
logEntry:@"imageLink cannot be null"];
return;
} else if (link == nil) {
[FBSDKLogger singleShotLogEntry:FBSDKLoggingBehaviorDeveloperErrors
logEntry:@"link cannot be null"];
return;
} else if (title == nil) {
[FBSDKLogger singleShotLogEntry:FBSDKLoggingBehaviorDeveloperErrors
logEntry:@"title cannot be null"];
return;
} else if (currency == nil) {
[FBSDKLogger singleShotLogEntry:FBSDKLoggingBehaviorDeveloperErrors
logEntry:@"currency cannot be null"];
return;
} else if (gtin == nil && mpn == nil && brand == nil) {
[FBSDKLogger singleShotLogEntry:FBSDKLoggingBehaviorDeveloperErrors
logEntry:@"Either gtin, mpn or brand is required"];
return;
}
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
if (nil != parameters) {
[dict setValuesForKeysWithDictionary:parameters];
}
dict[FBSDKAppEventParameterProductItemID] = itemID;
NSString *avail = nil;
switch (availability) {
case FBSDKProductAvailabilityInStock:
avail = @"IN_STOCK"; break;
case FBSDKProductAvailabilityOutOfStock:
avail = @"OUT_OF_STOCK"; break;
case FBSDKProductAvailabilityPreOrder:
avail = @"PREORDER"; break;
case FBSDKProductAvailabilityAvailableForOrder:
avail = @"AVALIABLE_FOR_ORDER"; break;
case FBSDKProductAvailabilityDiscontinued:
avail = @"DISCONTINUED"; break;
}
if (avail) {
dict[FBSDKAppEventParameterProductAvailability] = avail;
}
NSString *cond = nil;
switch (condition) {
case FBSDKProductConditionNew:
cond = @"NEW"; break;
case FBSDKProductConditionRefurbished:
cond = @"REFURBISHED"; break;
case FBSDKProductConditionUsed:
cond = @"USED"; break;
}
if (cond) {
dict[FBSDKAppEventParameterProductCondition] = cond;
}
dict[FBSDKAppEventParameterProductDescription] = description;
dict[FBSDKAppEventParameterProductImageLink] = imageLink;
dict[FBSDKAppEventParameterProductLink] = link;
dict[FBSDKAppEventParameterProductTitle] = title;
dict[FBSDKAppEventParameterProductPriceAmount] = [NSString stringWithFormat:@"%.3lf", priceAmount];
dict[FBSDKAppEventParameterProductPriceCurrency] = currency;
if (gtin) {
dict[FBSDKAppEventParameterProductGTIN] = gtin;
}
if (mpn) {
dict[FBSDKAppEventParameterProductMPN] = mpn;
}
if (brand) {
dict[FBSDKAppEventParameterProductBrand] = brand;
}
[FBSDKAppEvents logEvent:FBSDKAppEventNameProductCatalogUpdate
parameters:dict];
}
+ (void)activateApp
{
[FBSDKAppEventsUtility ensureOnMainThread:NSStringFromSelector(_cmd) className:NSStringFromClass(self)];
@ -634,17 +428,11 @@ static NSString *g_overrideAppID = nil;
// when appropriate, result in logging an "activated app" and "deactivated app" (for the
// previous session) App Event.
[FBSDKTimeSpentData restore:YES];
[FBSDKUserDataStore initStore];
}
+ (void)setPushNotificationsDeviceToken:(NSData *)deviceToken
{
NSString *deviceTokenString = [FBSDKInternalUtility hexadecimalStringFromData:deviceToken];
[FBSDKAppEvents setPushNotificationsDeviceTokenString:deviceTokenString];
}
+ (void)setPushNotificationsDeviceTokenString:(NSString *)deviceTokenString
{
if (deviceTokenString == nil) {
[FBSDKAppEvents singleton].pushNotificationsDeviceTokenString = nil;
return;
@ -659,23 +447,6 @@ static NSString *g_overrideAppID = nil;
if ([FBSDKAppEvents flushBehavior] != FBSDKAppEventsFlushBehaviorExplicitOnly) {
[[FBSDKAppEvents singleton] flushForReason:FBSDKAppEventsFlushReasonEagerlyFlushingEvent];
}
// Update device push token for uninstall tracking
[FBSDKServerConfigurationManager loadServerConfigurationWithCompletionBlock:^(FBSDKServerConfiguration *serverConfiguration, NSError *error) {
if (serverConfiguration.uninstallTrackingEnabled) {
FBSDKGraphRequest *request = [[FBSDKGraphRequest alloc]
initWithGraphPath:[NSString stringWithFormat:@"%@/%@",
[FBSDKSettings appID], UNINSTALL_TRACKING_TOKEN_ENDPOINT]
parameters:@{
UNINSTALL_TRACKING_DEVICE_TOKEN_KEY: deviceTokenString,
UNINSTALL_TRACKING_PLATFORM_KEY: @"ios",
// advertiserID could be 0s if user select limit ad tracking
UNINSTALL_TRACKING_DEVICE_ID_KEY: [FBSDKAppEventsUtility advertiserID] ?: @""
}
HTTPMethod:@"POST"];
[request startWithCompletionHandler:nil];
}
}];
}
}
@ -720,70 +491,18 @@ static NSString *g_overrideAppID = nil;
[defaults synchronize];
}
+ (void)clearUserID
{
[self setUserID:nil];
}
+ (NSString *)userID
{
return [[self class] singleton]->_userID;
}
+ (void)setUserData:(NSDictionary*)userData
{
[FBSDKUserDataStore setUserDataAndHash:userData];
}
+ (void)setUserEmail:(NSString *)email
firstName:(NSString *)firstName
lastName:(NSString *)lastName
phone:(NSString *)phone
dateOfBirth:(NSString *)dateOfBirth
gender:(NSString *)gender
city:(NSString *)city
state:(NSString *)state
zip:(NSString *)zip
country:(NSString *)country
{
[FBSDKUserDataStore setUserDataAndHash:email
firstName:firstName
lastName:lastName
phone:phone
dateOfBirth:dateOfBirth
gender:gender
city:city
state:state
zip:zip
country:country];
}
+ (NSString*)getUserData
{
return [FBSDKUserDataStore getHashedUserData];
}
+ (void)clearUserData
{
[FBSDKUserDataStore setUserDataAndHash:nil
firstName:nil
lastName:nil
phone:nil
dateOfBirth:nil
gender:nil
city:nil
state:nil
zip:nil
country:nil];
}
+ (void)updateUserProperties:(NSDictionary *)properties handler:(FBSDKGraphRequestHandler)handler
{
NSString *userID = [[self class] userID];
if (userID.length == 0) {
[FBSDKLogger singleShotLogEntry:FBSDKLoggingBehaviorDeveloperErrors logEntry:@"Missing [FBSDKAppEvents userID] for [FBSDKAppEvents updateUserProperties:]"];
NSError *error = [NSError fbRequiredArgumentErrorWithName:@"userID" message:@"Missing [FBSDKAppEvents userID] for [FBSDKAppEvents updateUserProperties:]"];
NSError *error = [FBSDKError requiredArgumentErrorWithName:@"userID" message:@"Missing [FBSDKAppEvents userID] for [FBSDKAppEvents updateUserProperties:]"];
if (handler) {
handler(nil, nil, error);
}
@ -798,7 +517,7 @@ static NSString *g_overrideAppID = nil;
__block NSError *invalidObjectError;
NSString *dataJSONString = [FBSDKInternalUtility JSONStringForObject:@[dataDictionary] error:&error invalidObjectHandler:^id(id object, BOOL *stop) {
*stop = YES;
invalidObjectError = [NSError fbUnknownErrorWithMessage:@"The values in the properties dictionary must be NSStrings or NSNumbers"];
invalidObjectError = [FBSDKError unknownErrorWithMessage:@"The values in the properties dictionary must be NSStrings or NSNumbers"];
return nil;
}];
if (!error) {
@ -823,62 +542,6 @@ static NSString *g_overrideAppID = nil;
[request startWithCompletionHandler:handler];
}
#if !TARGET_OS_TV
+ (void)augmentHybridWKWebView:(WKWebView *)webView {
// Ensure we can instantiate WebKit before trying this
Class WKWebViewClass = fbsdkdfl_WKWebViewClass();
if (WKWebViewClass != nil && [webView isKindOfClass:WKWebViewClass]) {
Class WKUserScriptClass = fbsdkdfl_WKUserScriptClass();
if (WKUserScriptClass != nil) {
WKUserContentController *controller = webView.configuration.userContentController;
FBSDKHybridAppEventsScriptMessageHandler *scriptHandler = [[FBSDKHybridAppEventsScriptMessageHandler alloc] init];
[controller addScriptMessageHandler:scriptHandler name:FBSDKAppEventsWKWebViewMessagesHandlerKey];
NSString *js = [NSString stringWithFormat:@"window.fbmq_%@={'sendEvent': function(pixel_id,event_name,custom_data){var msg={\"%@\":pixel_id, \"%@\":event_name,\"%@\":custom_data};window.webkit.messageHandlers[\"%@\"].postMessage(msg);}, 'getProtocol':function(){return \"%@\";}}",
[[self singleton] appID],
FBSDKAppEventsWKWebViewMessagesPixelIDKey,
FBSDKAppEventsWKWebViewMessagesEventKey,
FBSDKAppEventsWKWebViewMessagesParamsKey,
FBSDKAppEventsWKWebViewMessagesHandlerKey,
FBSDKAPPEventsWKWebViewMessagesProtocolKey
];
[controller addUserScript:[[WKUserScriptClass alloc] initWithSource:js injectionTime:WKUserScriptInjectionTimeAtDocumentStart forMainFrameOnly:NO]];
}
}
else {
[FBSDKAppEventsUtility logAndNotify:@"You must call augmentHybridWKWebView with WebKit linked to your project and a WKWebView instance"];
}
}
#endif
+ (void)setIsUnityInit:(BOOL)isUnityInit
{
[FBSDKAppEvents singleton]->_isUnityInit = isUnityInit;
}
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
+ (void)sendEventBindingsToUnity
{
// Send event bindings to Unity only Unity is initialized
if ([FBSDKAppEvents singleton]->_isUnityInit
&& [FBSDKAppEvents singleton]->_serverConfiguration
&& [NSJSONSerialization isValidJSONObject:[FBSDKAppEvents singleton]->_serverConfiguration.eventBindings]
) {
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:[FBSDKAppEvents singleton]->_serverConfiguration.eventBindings ?: @""
options:0
error:nil];
NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
Class classFBUnityUtility = objc_lookUpClass(FBUnityUtilityClassName);
SEL updateBindingSelector = NSSelectorFromString(FBUnityUtilityUpdateBindingsSelector);
if ([classFBUnityUtility respondsToSelector:updateBindingSelector]) {
[classFBUnityUtility performSelector:updateBindingSelector withObject:jsonString];
}
}
}
#pragma clang diagnostic pop
#pragma mark - Internal Methods
+ (void)logImplicitEvent:(NSString *)eventName
@ -931,10 +594,6 @@ static NSString *g_overrideAppID = nil;
- (void)publishInstall
{
NSString *appID = [self appID];
if (appID.length == 0) {
[FBSDKLogger singleShotLogEntry:FBSDKLoggingBehaviorDeveloperErrors logEntry:@"Missing [FBSDKAppEvents appID] for [FBSDKAppEvents publishInstall:]"];
return;
}
NSString *lastAttributionPingString = [NSString stringWithFormat:@"com.facebook.sdk:lastAttributionPing%@", appID];
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
if ([defaults objectForKey:lastAttributionPingString]) {
@ -943,7 +602,7 @@ static NSString *g_overrideAppID = nil;
[self fetchServerConfiguration:^{
NSDictionary *params = [FBSDKAppEventsUtility activityParametersDictionaryForEvent:@"MOBILE_APP_INSTALL"
implicitEventsOnly:NO
shouldAccessAdvertisingID:self->_serverConfiguration.isAdvertisingIDEnabled];
shouldAccessAdvertisingID:_serverConfiguration.isAdvertisingIDEnabled];
NSString *path = [NSString stringWithFormat:@"%@/activities", appID];
FBSDKGraphRequest *request = [[FBSDKGraphRequest alloc] initWithGraphPath:path
parameters:params
@ -961,42 +620,27 @@ static NSString *g_overrideAppID = nil;
}];
}
#if !TARGET_OS_TV
- (void)enableCodelessEvents {
if (_serverConfiguration.isCodelessEventsEnabled) {
if (!_eventBindingManager) {
_eventBindingManager = [[FBSDKEventBindingManager alloc] init];
[_eventBindingManager start];
}
if ([FBSDKInternalUtility isUnity]) {
[FBSDKAppEvents sendEventBindingsToUnity];
} else {
[_eventBindingManager updateBindings:[FBSDKEventBindingManager
parseArray:_serverConfiguration.eventBindings]];
}
}
}
#endif
// app events can use a server configuration up to 24 hours old to minimize network traffic.
- (void)fetchServerConfiguration:(void (^)(void))callback
{
[FBSDKServerConfigurationManager loadServerConfigurationWithCompletionBlock:^(FBSDKServerConfiguration *serverConfiguration, NSError *error) {
self->_serverConfiguration = serverConfiguration;
if (_serverConfiguration == nil) {
[FBSDKServerConfigurationManager loadServerConfigurationWithCompletionBlock:^(FBSDKServerConfiguration *serverConfiguration, NSError *error) {
_serverConfiguration = serverConfiguration;
if (self->_serverConfiguration.implicitPurchaseLoggingEnabled) {
[FBSDKPaymentObserver startObservingTransactions];
} else {
[FBSDKPaymentObserver stopObservingTransactions];
}
#if !TARGET_OS_TV
[self enableCodelessEvents];
#endif
if (callback) {
callback();
}
}];
if (_serverConfiguration.implicitPurchaseLoggingEnabled) {
[FBSDKPaymentObserver startObservingTransactions];
} else {
[FBSDKPaymentObserver stopObservingTransactions];
}
if (callback) {
callback();
}
}];
return;
}
if (callback) {
callback();
}
}
- (void)instanceLogEvent:(NSString *)eventName
@ -1139,21 +783,15 @@ static NSString *g_overrideAppID = nil;
- (void)flushOnMainQueue:(FBSDKAppEventsState *)appEventsState
forReason:(FBSDKAppEventsFlushReason)reason
{
if (appEventsState.events.count == 0) {
return;
}
if (appEventsState.appID.length == 0) {
[FBSDKLogger singleShotLogEntry:FBSDKLoggingBehaviorDeveloperErrors logEntry:@"Missing [FBSDKAppEvents appEventsState.appID] for [FBSDKAppEvents flushOnMainQueue:]"];
return;
}
[FBSDKAppEventsUtility ensureOnMainThread:NSStringFromSelector(_cmd) className:NSStringFromClass([self class])];
[self fetchServerConfiguration:^(void) {
NSString *receipt_data = [appEventsState extractReceiptData];
NSString *encodedEvents = [appEventsState JSONStringForEvents:self->_serverConfiguration.implicitLoggingEnabled];
NSString *JSONString = [appEventsState JSONStringForEvents:_serverConfiguration.implicitLoggingEnabled];
NSData *encodedEvents = [JSONString dataUsingEncoding:NSUTF8StringEncoding];
if (!encodedEvents) {
[FBSDKLogger singleShotLogEntry:FBSDKLoggingBehaviorAppEvents
logEntry:@"FBSDKAppEvents: Flushing skipped - no events after removing implicitly logged ones.\n"];
@ -1162,13 +800,13 @@ static NSString *g_overrideAppID = nil;
NSMutableDictionary *postParameters = [FBSDKAppEventsUtility
activityParametersDictionaryForEvent:@"CUSTOM_APP_EVENTS"
implicitEventsOnly:appEventsState.areAllEventsImplicit
shouldAccessAdvertisingID:self->_serverConfiguration.advertisingIDEnabled];
NSInteger length = receipt_data.length;
shouldAccessAdvertisingID:_serverConfiguration.advertisingIDEnabled];
NSInteger length = [receipt_data length];
if (length > 0) {
postParameters[@"receipt_data"] = receipt_data;
}
postParameters[@"custom_events"] = encodedEvents;
postParameters[@"custom_events_file"] = encodedEvents;
if (appEventsState.numSkipped > 0) {
postParameters[@"num_skipped_events"] = [NSString stringWithFormat:@"%lu", (unsigned long)appEventsState.numSkipped];
}
@ -1228,14 +866,13 @@ static NSString *g_overrideAppID = nil;
// We interpret a 400 coming back from FBRequestConnection as a server error due to improper data being
// sent down. Otherwise we assume no connectivity, or another condition where we could treat it as no connectivity.
// Adding 404 as having wrong/missing appID results in 404 and that is not a connectivity issue
flushResult = (errorCode == 400 || errorCode == 404) ? FlushResultServerError : FlushResultNoConnectivity;
flushResult = errorCode == 400 ? FlushResultServerError : FlushResultNoConnectivity;
}
if (flushResult == FlushResultServerError) {
// Only log events that developer can do something with (i.e., if parameters are incorrect).
// as opposed to cases where the token is bad.
if ([error.userInfo[FBSDKGraphRequestErrorKey] unsignedIntegerValue] == FBSDKGraphRequestErrorOther) {
if ([error.userInfo[FBSDKGraphRequestErrorCategoryKey] unsignedIntegerValue] == FBSDKGraphRequestErrorCategoryOther) {
NSString *message = [NSString stringWithFormat:@"Failed to send AppEvents: %@", error];
[FBSDKAppEventsUtility logAndNotify:message allowLogAsDeveloperError:!appEventsState.areAllEventsImplicit];
}
@ -1261,7 +898,7 @@ static NSString *g_overrideAppID = nil;
break;
case FlushResultServerError:
resultString = [NSString stringWithFormat:@"Server Error - %@", error.description];
resultString = [NSString stringWithFormat:@"Server Error - %@", [error description]];
break;
}
@ -1277,6 +914,11 @@ static NSString *g_overrideAppID = nil;
}
}
- (void)appSettingsFetchStateResetTimerFired:(id)arg
{
_serverConfiguration = nil;
}
- (void)applicationDidBecomeActive
{
[FBSDKAppEventsUtility ensureOnMainThread:NSStringFromSelector(_cmd) className:NSStringFromClass([self class])];

View File

@ -1,63 +0,0 @@
// 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 "FBSDKAppLinkTarget.h"
NS_ASSUME_NONNULL_BEGIN
/*! The version of the App Link protocol that this library supports */
FOUNDATION_EXPORT NSString *const FBSDKAppLinkVersion;
/*!
Contains App Link metadata relevant for navigation on this device
derived from the HTML at a given URL.
*/
@interface FBSDKAppLink : NSObject
/*!
Creates a FBSDKAppLink with the given list of FBSDKAppLinkTargets and target URL.
Generally, this will only be used by implementers of the FBSDKAppLinkResolving protocol,
as these implementers will produce App Link metadata for a given URL.
@param sourceURL the URL from which this App Link is derived
@param targets an ordered list of FBSDKAppLinkTargets for this platform derived
from App Link metadata.
@param webURL the fallback web URL, if any, for the app link.
*/
+ (instancetype)appLinkWithSourceURL:(NSURL *)sourceURL
targets:(NSArray<FBSDKAppLinkTarget *> *)targets
webURL:(nullable NSURL *)webURL;
/*! The URL from which this FBSDKAppLink was derived */
@property (nonatomic, strong, readonly) NSURL *sourceURL;
/*!
The ordered list of targets applicable to this platform that will be used
for navigation.
*/
@property (nonatomic, copy, readonly) NSArray<FBSDKAppLinkTarget *> *targets;
/*! The fallback web URL to use if no targets are installed on this device. */
@property (nonatomic, strong, readonly, nullable) NSURL *webURL;
@end
NS_ASSUME_NONNULL_END

View File

@ -1,70 +0,0 @@
// 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 "FBSDKAppLink_Internal.h"
NSString *const FBSDKAppLinkDataParameterName = @"al_applink_data";
NSString *const FBSDKAppLinkTargetKeyName = @"target_url";
NSString *const FBSDKAppLinkUserAgentKeyName = @"user_agent";
NSString *const FBSDKAppLinkExtrasKeyName = @"extras";
NSString *const FBSDKAppLinkRefererAppLink = @"referer_app_link";
NSString *const FBSDKAppLinkRefererAppName = @"app_name";
NSString *const FBSDKAppLinkRefererUrl = @"url";
NSString *const FBSDKAppLinkVersionKeyName = @"version";
NSString *const FBSDKAppLinkVersion = @"1.0";
@interface FBSDKAppLink ()
@property (nonatomic, strong) NSURL *sourceURL;
@property (nonatomic, copy) NSArray<FBSDKAppLinkTarget *> *targets;
@property (nonatomic, strong) NSURL *webURL;
@property (nonatomic, assign, getter=isBackToReferrer) BOOL backToReferrer;
@end
@implementation FBSDKAppLink
+ (instancetype)appLinkWithSourceURL:(NSURL *)sourceURL
targets:(NSArray<FBSDKAppLinkTarget *> *)targets
webURL:(NSURL *)webURL
isBackToReferrer:(BOOL)isBackToReferrer {
FBSDKAppLink *link = [[self alloc] initWithIsBackToReferrer:isBackToReferrer];
link.sourceURL = sourceURL;
link.targets = [targets copy];
link.webURL = webURL;
return link;
}
+ (instancetype)appLinkWithSourceURL:(NSURL *)sourceURL
targets:(NSArray<FBSDKAppLinkTarget *> *)targets
webURL:(NSURL *)webURL {
return [self appLinkWithSourceURL:sourceURL
targets:targets
webURL:webURL
isBackToReferrer:NO];
}
- (FBSDKAppLink *)initWithIsBackToReferrer:(BOOL)backToReferrer {
if ((self = [super init])) {
_backToReferrer = backToReferrer;
}
return self;
}
@end

View File

@ -1,137 +0,0 @@
// 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 "FBSDKAppLink.h"
#import "FBSDKAppLinkResolving.h"
NS_ASSUME_NONNULL_BEGIN
/*!
The result of calling navigate on a FBSDKAppLinkNavigation
*/
typedef NS_ENUM(NSInteger, FBSDKAppLinkNavigationType) {
/*! Indicates that the navigation failed and no app was opened */
FBSDKAppLinkNavigationTypeFailure,
/*! Indicates that the navigation succeeded by opening the URL in the browser */
FBSDKAppLinkNavigationTypeBrowser,
/*! Indicates that the navigation succeeded by opening the URL in an app on the device */
FBSDKAppLinkNavigationTypeApp
};
/**
Describes the callback for appLinkFromURLInBackground.
@param navType the FBSDKAppLink representing the deferred App Link
@param error the error during the request, if any
*/
typedef void (^FBSDKAppLinkNavigationHandler)(FBSDKAppLinkNavigationType navType, NSError * _Nullable error);
/*!
Represents a pending request to navigate to an App Link. Most developers will
simply use navigateToURLInBackground: to open a URL, but developers can build
custom requests with additional navigation and app data attached to them by
creating FBSDKAppLinkNavigations themselves.
*/
NS_EXTENSION_UNAVAILABLE_IOS("Not available in app extension")
@interface FBSDKAppLinkNavigation : NSObject
/*!
The extras for the AppLinkNavigation. This will generally contain application-specific
data that should be passed along with the request, such as advertiser or affiliate IDs or
other such metadata relevant on this device.
*/
@property (nonatomic, copy, readonly) NSDictionary<NSString *, id> *extras;
/*!
The al_applink_data for the AppLinkNavigation. This will generally contain data common to
navigation attempts such as back-links, user agents, and other information that may be used
in routing and handling an App Link request.
*/
@property (nonatomic, copy, readonly) NSDictionary<NSString *, id> *appLinkData;
/*! The AppLink to navigate to */
@property (nonatomic, strong, readonly) FBSDKAppLink *appLink;
/*!
Return navigation type for current instance.
No-side-effect version of navigate:
*/
@property (nonatomic, readonly) FBSDKAppLinkNavigationType navigationType;
/*! Creates an AppLinkNavigation with the given link, extras, and App Link data */
+ (instancetype)navigationWithAppLink:(FBSDKAppLink *)appLink
extras:(NSDictionary<NSString *, id> *)extras
appLinkData:(NSDictionary<NSString *, id> *)appLinkData;
/*!
Creates an NSDictionary with the correct format for iOS callback URLs,
to be used as 'appLinkData' argument in the call to navigationWithAppLink:extras:appLinkData:
*/
+ (NSDictionary<NSString *, NSDictionary<NSString *, NSString *> *> *)callbackAppLinkDataForAppWithName:(NSString *)appName
url:(NSString *)url;
/*! Performs the navigation */
- (FBSDKAppLinkNavigationType)navigate:(NSError *__autoreleasing *)error;
/*! Returns a FBSDKAppLink for the given URL */
+ (void)resolveAppLink:(NSURL *)destination handler:(FBSDKAppLinkFromURLHandler)handler;
/*! Returns a FBSDKAppLink for the given URL using the given App Link resolution strategy */
+ (void)resolveAppLink:(NSURL *)destination
resolver:(id<FBSDKAppLinkResolving>)resolver
handler:(FBSDKAppLinkFromURLHandler)handler;
/*! Navigates to a FBSDKAppLink and returns whether it opened in-app or in-browser */
+ (FBSDKAppLinkNavigationType)navigateToAppLink:(FBSDKAppLink *)link error:(NSError *__autoreleasing *)error;
/*!
Returns a FBSDKAppLinkNavigationType based on a FBSDKAppLink.
It's essentially a no-side-effect version of navigateToAppLink:error:,
allowing apps to determine flow based on the link type (e.g. open an
internal web view instead of going straight to the browser for regular links.)
*/
+ (FBSDKAppLinkNavigationType)navigationTypeForLink:(FBSDKAppLink *)link;
/*! Navigates to a URL (an asynchronous action) and returns a FBSDKNavigationType */
+ (void)navigateToURL:(NSURL *)destination handler:(FBSDKAppLinkNavigationHandler)handler;
/*!
Navigates to a URL (an asynchronous action) using the given App Link resolution
strategy and returns a FBSDKNavigationType
*/
+ (void)navigateToURL:(NSURL *)destination
resolver:(id<FBSDKAppLinkResolving>)resolver
handler:(FBSDKAppLinkNavigationHandler)handler;
/*!
Gets the default resolver to be used for App Link resolution. If the developer has not set one explicitly,
a basic, built-in resolver will be used.
*/
+ (id<FBSDKAppLinkResolving>)defaultResolver;
/*!
Sets the default resolver to be used for App Link resolution. Setting this to nil will revert the
default resolver to the basic, built-in resolver provided by FBSDK.
*/
+ (void)setDefaultResolver:(id<FBSDKAppLinkResolving>)resolver;
@end
NS_ASSUME_NONNULL_END

View File

@ -1,294 +0,0 @@
// 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 "FBSDKAppLinkNavigation.h"
#import "FBSDKAppLinkTarget.h"
#import "FBSDKAppLink_Internal.h"
#import "FBSDKMeasurementEvent_Internal.h"
#import "FBSDKSettings.h"
#import "FBSDKWebViewAppLinkResolver.h"
FOUNDATION_EXPORT NSString *const FBSDKAppLinkDataParameterName;
FOUNDATION_EXPORT NSString *const FBSDKAppLinkTargetKeyName;
FOUNDATION_EXPORT NSString *const FBSDKAppLinkUserAgentKeyName;
FOUNDATION_EXPORT NSString *const FBSDKAppLinkExtrasKeyName;
FOUNDATION_EXPORT NSString *const FBSDKAppLinkVersionKeyName;
FOUNDATION_EXPORT NSString *const FBSDKAppLinkRefererAppLink;
FOUNDATION_EXPORT NSString *const FBSDKAppLinkRefererAppName;
FOUNDATION_EXPORT NSString *const FBSDKAppLinkRefererUrl;
static id<FBSDKAppLinkResolving> defaultResolver;
@interface FBSDKAppLinkNavigation ()
@property (nonatomic, copy) NSDictionary<NSString *, id> *extras;
@property (nonatomic, copy) NSDictionary<NSString *, id> *appLinkData;
@property (nonatomic, strong) FBSDKAppLink *appLink;
@end
@implementation FBSDKAppLinkNavigation
+ (instancetype)navigationWithAppLink:(FBSDKAppLink *)appLink
extras:(NSDictionary<NSString *, id> *)extras
appLinkData:(NSDictionary<NSString *, id> *)appLinkData {
FBSDKAppLinkNavigation *navigation = [[self alloc] init];
navigation.appLink = appLink;
navigation.extras = extras;
navigation.appLinkData = appLinkData;
return navigation;
}
+ (NSDictionary<NSString *, NSDictionary<NSString *, NSString *> *> *)callbackAppLinkDataForAppWithName:(NSString *)appName
url:(NSString *)url {
return @{FBSDKAppLinkRefererAppLink: @{FBSDKAppLinkRefererAppName: appName, FBSDKAppLinkRefererUrl: url}};
}
- (NSString *)stringByEscapingQueryString:(NSString *)string {
return [string stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];
}
- (NSURL *)appLinkURLWithTargetURL:(NSURL *)targetUrl error:(NSError **)error {
NSMutableDictionary<NSString *, id> *appLinkData =
[NSMutableDictionary dictionaryWithDictionary:self.appLinkData ?: @{}];
// Add applink protocol data
if (!appLinkData[FBSDKAppLinkUserAgentKeyName]) {
appLinkData[FBSDKAppLinkUserAgentKeyName] = [NSString stringWithFormat:@"FBSDK %@", FBSDKSettings.sdkVersion];
}
if (!appLinkData[FBSDKAppLinkVersionKeyName]) {
appLinkData[FBSDKAppLinkVersionKeyName] = FBSDKAppLinkVersion;
}
if (self.appLink.sourceURL.absoluteString) {
appLinkData[FBSDKAppLinkTargetKeyName] = self.appLink.sourceURL.absoluteString;
}
appLinkData[FBSDKAppLinkExtrasKeyName] = self.extras ?: @{};
// JSON-ify the applink data
NSError *jsonError = nil;
NSData *jsonBlob = [NSJSONSerialization dataWithJSONObject:appLinkData options:0 error:&jsonError];
if (!jsonError) {
NSString *jsonString = [[NSString alloc] initWithData:jsonBlob encoding:NSUTF8StringEncoding];
NSString *encoded = [self stringByEscapingQueryString:jsonString];
NSString *endUrlString = [NSString stringWithFormat:@"%@%@%@=%@",
targetUrl.absoluteString,
targetUrl.query ? @"&" : @"?",
FBSDKAppLinkDataParameterName,
encoded];
return [NSURL URLWithString:endUrlString];
} else {
if (error) {
*error = jsonError;
}
// If there was an error encoding the app link data, fail hard.
return nil;
}
}
- (FBSDKAppLinkNavigationType)navigate:(NSError **)error {
NSURL *openedURL = nil;
NSError *encodingError = nil;
FBSDKAppLinkNavigationType retType = FBSDKAppLinkNavigationTypeFailure;
// Find the first eligible/launchable target in the FBSDKAppLink.
for (FBSDKAppLinkTarget *target in self.appLink.targets) {
NSURL *appLinkAppURL = [self appLinkURLWithTargetURL:target.URL error:&encodingError];
if (encodingError || !appLinkAppURL) {
if (error) {
*error = encodingError;
}
} else if ([[UIApplication sharedApplication] openURL:appLinkAppURL]) {
retType = FBSDKAppLinkNavigationTypeApp;
openedURL = appLinkAppURL;
break;
}
}
if (!openedURL && self.appLink.webURL) {
// Fall back to opening the url in the browser if available.
NSURL *appLinkBrowserURL = [self appLinkURLWithTargetURL:self.appLink.webURL error:&encodingError];
if (encodingError || !appLinkBrowserURL) {
// If there was an error encoding the app link data, fail hard.
if (error) {
*error = encodingError;
}
} else if ([[UIApplication sharedApplication] openURL:appLinkBrowserURL]) {
// This was a browser navigation.
retType = FBSDKAppLinkNavigationTypeBrowser;
openedURL = appLinkBrowserURL;
}
}
[self postAppLinkNavigateEventNotificationWithTargetURL:openedURL
error:error ? *error : nil
type:retType];
return retType;
}
- (void)postAppLinkNavigateEventNotificationWithTargetURL:(NSURL *)outputURL error:(NSError *)error type:(FBSDKAppLinkNavigationType)type {
NSString *const EVENT_YES_VAL = @"1";
NSString *const EVENT_NO_VAL = @"0";
NSMutableDictionary<NSString *, id> *logData =
[[NSMutableDictionary alloc] init];
NSString *outputURLScheme = outputURL.scheme;
NSString *outputURLString = outputURL.absoluteString;
if (outputURLScheme) {
logData[@"outputURLScheme"] = outputURLScheme;
}
if (outputURLString) {
logData[@"outputURL"] = outputURLString;
}
NSString *sourceURLString = self.appLink.sourceURL.absoluteString;
NSString *sourceURLHost = self.appLink.sourceURL.host;
NSString *sourceURLScheme = self.appLink.sourceURL.scheme;
if (sourceURLString) {
logData[@"sourceURL"] = sourceURLString;
}
if (sourceURLHost) {
logData[@"sourceHost"] = sourceURLHost;
}
if (sourceURLScheme) {
logData[@"sourceScheme"] = sourceURLScheme;
}
if (error.localizedDescription) {
logData[@"error"] = error.localizedDescription;
}
NSString *success = nil; //no
NSString *linkType = nil; // unknown;
switch (type) {
case FBSDKAppLinkNavigationTypeFailure:
success = EVENT_NO_VAL;
linkType = @"fail";
break;
case FBSDKAppLinkNavigationTypeBrowser:
success = EVENT_YES_VAL;
linkType = @"web";
break;
case FBSDKAppLinkNavigationTypeApp:
success = EVENT_YES_VAL;
linkType = @"app";
break;
default:
break;
}
if (success) {
logData[@"success"] = success;
}
if (linkType) {
logData[@"type"] = linkType;
}
if (self.appLink.backToReferrer) {
[FBSDKMeasurementEvent postNotificationForEventName:FBSDKAppLinkNavigateBackToReferrerEventName args:logData];
} else {
[FBSDKMeasurementEvent postNotificationForEventName:FBSDKAppLinkNavigateOutEventName args:logData];
}
}
+ (void)resolveAppLink:(NSURL *)destination
resolver:(id<FBSDKAppLinkResolving>)resolver
handler:(FBSDKAppLinkFromURLHandler)handler {
[resolver appLinkFromURL:destination handler:handler];
}
+ (void)resolveAppLink:(NSURL *)destination handler:(FBSDKAppLinkFromURLHandler)handler {
[self resolveAppLink:destination resolver:[self defaultResolver] handler:handler];
}
+ (void)navigateToURL:(NSURL *)destination handler:(FBSDKAppLinkNavigationHandler)handler {
[self navigateToURL:destination resolver:[self defaultResolver] handler:handler];
}
+ (void)navigateToURL:(NSURL *)destination
resolver:(id<FBSDKAppLinkResolving>)resolver
handler:(FBSDKAppLinkNavigationHandler)handler {
dispatch_async(dispatch_get_main_queue(), ^{
[self resolveAppLink:destination
resolver:resolver
handler:^(FBSDKAppLink * _Nullable appLink, NSError * _Nullable error) {
if (error) {
handler(FBSDKAppLinkNavigationTypeFailure, error);
return;
}
NSError *navigateError = nil;
FBSDKAppLinkNavigationType result = [self navigateToAppLink:appLink error:&navigateError];
handler(result, navigateError);
}];
});
}
+ (FBSDKAppLinkNavigationType)navigateToAppLink:(FBSDKAppLink *)link error:(NSError **)error {
return [[FBSDKAppLinkNavigation navigationWithAppLink:link
extras:@{}
appLinkData:@{}] navigate:error];
}
+ (FBSDKAppLinkNavigationType)navigationTypeForLink:(FBSDKAppLink *)link {
return [[self navigationWithAppLink:link extras:@{} appLinkData:@{}] navigationType];
}
- (FBSDKAppLinkNavigationType)navigationType {
FBSDKAppLinkTarget *eligibleTarget = nil;
for (FBSDKAppLinkTarget *target in self.appLink.targets) {
if ([[UIApplication sharedApplication] canOpenURL:target.URL]) {
eligibleTarget = target;
break;
}
}
if (eligibleTarget != nil) {
NSURL *appLinkURL = [self appLinkURLWithTargetURL:eligibleTarget.URL error:nil];
if (appLinkURL != nil) {
return FBSDKAppLinkNavigationTypeApp;
} else {
return FBSDKAppLinkNavigationTypeFailure;
}
}
if (self.appLink.webURL != nil) {
NSURL *appLinkURL = [self appLinkURLWithTargetURL:eligibleTarget.URL error:nil];
if (appLinkURL != nil) {
return FBSDKAppLinkNavigationTypeBrowser;
} else {
return FBSDKAppLinkNavigationTypeFailure;
}
}
return FBSDKAppLinkNavigationTypeFailure;
}
+ (id<FBSDKAppLinkResolving>)defaultResolver {
if (defaultResolver) {
return defaultResolver;
}
return [FBSDKWebViewAppLinkResolver sharedInstance];
}
+ (void)setDefaultResolver:(id<FBSDKAppLinkResolving>)resolver {
defaultResolver = resolver;
}
@end

View File

@ -18,15 +18,12 @@
#import <Foundation/Foundation.h>
#import "FBSDKAppLinkResolving.h"
@class BFTask;
// Check if Bolts.framework is available for import
#if __has_include(<Bolts/BFAppLinkResolving.h>)
// Import it if it's available
#import <Bolts/BFAppLinkResolving.h>
# import <Bolts/BFAppLinkResolving.h>
#else
// Otherwise - redeclare BFAppLinkResolving protocol to resolve the problem of missing symbols
// Please note: Bolts.framework is still required for AppLink resolving to work,
@ -37,17 +34,15 @@
App Links that may include pre-fetching, caching, or querying for App Link
data from an index provided by a service provider.
*/
DEPRECATED_MSG_ATTRIBUTE("Use `FBSDKAppLinkResolving`")
@protocol BFAppLinkResolving <NSObject>
/**
Asynchronously resolves App Link data for a given URL.
@param url The URL to resolve into an App Link.
@return A BFTask that will return a BFAppLink for the given URL.
- Parameter url: The URL to resolve into an App Link.
- Returns: A BFTask that will return a BFAppLink for the given URL.
*/
- (BFTask *)appLinkFromURLInBackground:(NSURL *)url
DEPRECATED_MSG_ATTRIBUTE("Use `appLinkFromURL:handler:`");
- (BFTask *)appLinkFromURLInBackground:(NSURL *)url;
@end
@ -64,40 +59,20 @@ DEPRECATED_MSG_ATTRIBUTE("Use `appLinkFromURL:handler:`");
Usage of this type requires a client token. See `[FBSDKSettings setClientToken:]` and linking
Bolts.framework
*/
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
@interface FBSDKAppLinkResolver : NSObject<FBSDKAppLinkResolving, BFAppLinkResolving>
#pragma clang diagnostic pop
@interface FBSDKAppLinkResolver : NSObject<BFAppLinkResolving>
/**
Asynchronously resolves App Link data for multiple URLs.
@param urls An array of NSURLs to resolve into App Links.
@return A BFTask that will return dictionary mapping input NSURLs to their
- Parameter urls: An array of NSURLs to resolve into App Links.
- Returns: A BFTask that will return dictionary mapping input NSURLs to their
corresponding BFAppLink.
You should set the client token before making this call. See `[FBSDKSettings setClientToken:]`
*/
- (BFTask *)appLinksFromURLsInBackground:(NSArray<NSURL *> *)urls
DEPRECATED_MSG_ATTRIBUTE("Use `appLinkFromURLs:handler:`");
/**
Asynchronously resolves App Link data for a given URL.
@param url The URL to resolve into an App Link.
@return A BFTask that will return a BFAppLink for the given URL.
*/
- (BFTask *)appLinkFromURLInBackground:(NSURL *)url
DEPRECATED_MSG_ATTRIBUTE("Use `appLinkFromURL:handler:`");
/**
Asynchronously resolves App Link data for a given array of URLs.
@param urls The URLs to resolve into an App Link.
@param handler The completion block that will return an App Link for the given URL.
*/
- (void)appLinksFromURLs:(NSArray<NSURL *> *)urls handler:(FBSDKAppLinksFromURLArrayHandler)handler
NS_EXTENSION_UNAVAILABLE_IOS("Not available in app extension");
- (BFTask *)appLinksFromURLsInBackground:(NSArray *)urls;
/**
Allocates and initializes a new instance of FBSDKAppLinkResolver.

View File

@ -26,7 +26,6 @@
#import <Bolts/BFTaskCompletionSource.h>
#import "FBSDKAccessToken.h"
#import "FBSDKAppLink.h"
#import "FBSDKGraphRequest+Internal.h"
#import "FBSDKGraphRequestConnection.h"
#import "FBSDKInternalUtility.h"
@ -46,8 +45,7 @@ static NSString *const kAppLinksKey = @"app_links";
@interface FBSDKAppLinkResolver ()
@property (nonatomic, strong) NSMutableDictionary<NSURL *, BFAppLink *> *cachedBFAppLinks;
@property (nonatomic, strong) NSMutableDictionary<NSURL *, FBSDKAppLink *> *cachedFBSDKAppLinks;
@property (nonatomic, strong) NSMutableDictionary *cachedLinks;
@property (nonatomic, assign) UIUserInterfaceIdiom userInterfaceIdiom;
@end
@ -69,135 +67,35 @@ static Class g_BFTaskClass;
}
}
- (instancetype)initWithUserInterfaceIdiom:(UIUserInterfaceIdiom)userInterfaceIdiom
- (id)initWithUserInterfaceIdiom:(UIUserInterfaceIdiom)userInterfaceIdiom
{
if (self = [super init]) {
self.cachedBFAppLinks = [NSMutableDictionary dictionary];
self.cachedFBSDKAppLinks = [NSMutableDictionary dictionary];
self.cachedLinks = [NSMutableDictionary dictionary];
self.userInterfaceIdiom = userInterfaceIdiom;
}
return self;
}
- (void)appLinkFromURL:(NSURL *)url handler:(FBSDKAppLinkFromURLHandler)handler
{
[self appLinksFromURLs:@[url] handler:^(NSDictionary<NSURL *, FBSDKAppLink *> *urls, NSError * _Nullable error) {
handler(urls[url], error);
}];
}
- (void)appLinksFromURLs:(NSArray<NSURL *> *)urls handler:(FBSDKAppLinksFromURLArrayHandler)handler
{
if (![FBSDKSettings clientToken] && ![FBSDKAccessToken currentAccessToken]) {
[FBSDKLogger singleShotLogEntry:FBSDKLoggingBehaviorDeveloperErrors
logEntry:@"A user access token or clientToken is required to use FBAppLinkResolver"];
}
NSMutableDictionary<NSURL *, FBSDKAppLink *> *appLinks = [NSMutableDictionary dictionary];
NSMutableArray<NSURL *> *toFind = [NSMutableArray array];
NSMutableArray<NSString *> *toFindStrings = [NSMutableArray array];
@synchronized (self.cachedFBSDKAppLinks) {
for (NSURL *url in urls) {
if (self.cachedFBSDKAppLinks[url]) {
appLinks[url] = self.cachedFBSDKAppLinks[url];
} else {
[toFind addObject:url];
NSCharacterSet *urlAllowedSet = [NSCharacterSet URLQueryAllowedCharacterSet];
NSString *toFindString = [url.absoluteString stringByAddingPercentEncodingWithAllowedCharacters:urlAllowedSet];
if (toFindString) {
[toFindStrings addObject:toFindString];
}
}
}
}
if (toFind.count == 0) {
// All of the URLs have already been found.
handler(_cachedFBSDKAppLinks, nil);
}
NSMutableArray<NSString *> *fields = [NSMutableArray arrayWithObject:kIOSKey];
NSString *idiomSpecificField = nil;
switch (self.userInterfaceIdiom) {
case UIUserInterfaceIdiomPad:
idiomSpecificField = kIPadKey;
break;
case UIUserInterfaceIdiomPhone:
idiomSpecificField = kIPhoneKey;
break;
default:
break;
}
if (idiomSpecificField) {
[fields addObject:idiomSpecificField];
}
NSString *path = [NSString stringWithFormat:@"?fields=%@.fields(%@)&ids=%@",
kAppLinksKey,
[fields componentsJoinedByString:@","],
[toFindStrings componentsJoinedByString:@","]];
FBSDKGraphRequest *request = [[FBSDKGraphRequest alloc] initWithGraphPath:path
parameters:nil
flags:FBSDKGraphRequestFlagDoNotInvalidateTokenOnError | FBSDKGraphRequestFlagDisableErrorRecovery];
[request startWithCompletionHandler:^(FBSDKGraphRequestConnection *connection, id result, NSError *error) {
if (error) {
handler(@{}, error);
return;
}
for (NSURL *url in toFind) {
id nestedObject = result[url.absoluteString][kAppLinksKey];
NSMutableArray *rawTargets = [NSMutableArray array];
if (idiomSpecificField) {
[rawTargets addObjectsFromArray:nestedObject[idiomSpecificField]];
}
[rawTargets addObjectsFromArray:nestedObject[kIOSKey]];
NSMutableArray<FBSDKAppLinkTarget *> *targets = [NSMutableArray arrayWithCapacity:rawTargets.count];
for (id rawTarget in rawTargets) {
[targets addObject:[FBSDKAppLinkTarget appLinkTargetWithURL:[NSURL URLWithString:rawTarget[kURLKey]]
appStoreId:rawTarget[kIOSAppStoreIdKey]
appName:rawTarget[kIOSAppNameKey]]];
}
id webTarget = nestedObject[kWebKey];
NSString *webFallbackString = webTarget[kURLKey];
NSURL *fallbackUrl = webFallbackString ? [NSURL URLWithString:webFallbackString] : url;
NSNumber *shouldFallback = webTarget[kShouldFallbackKey];
if (shouldFallback && !shouldFallback.boolValue) {
fallbackUrl = nil;
}
FBSDKAppLink *link = [FBSDKAppLink appLinkWithSourceURL:url
targets:targets
webURL:fallbackUrl];
@synchronized (self.cachedFBSDKAppLinks) {
self.cachedFBSDKAppLinks[url] = link;
}
appLinks[url] = link;
}
handler(appLinks, nil);
}];
}
- (BFTask *)appLinksFromURLsInBackground:(NSArray *)urls
{
if (![FBSDKSettings clientToken] && ![FBSDKAccessToken currentAccessToken]) {
[FBSDKLogger singleShotLogEntry:FBSDKLoggingBehaviorDeveloperErrors
logEntry:@"A user access token or clientToken is required to use FBAppLinkResolver"];
}
NSMutableDictionary<NSURL *, BFAppLink *> *appLinks = [NSMutableDictionary dictionary];
NSMutableArray<NSURL *> *toFind = [NSMutableArray array];
NSMutableArray<NSString *> *toFindStrings = [NSMutableArray array];
NSMutableDictionary *appLinks = [NSMutableDictionary dictionary];
NSMutableArray *toFind = [NSMutableArray array];
NSMutableArray *toFindStrings = [NSMutableArray array];
@synchronized (self.cachedBFAppLinks) {
@synchronized (self.cachedLinks) {
for (NSURL *url in urls) {
if (self.cachedBFAppLinks[url]) {
appLinks[url] = self.cachedBFAppLinks[url];
if (self.cachedLinks[url]) {
appLinks[url] = self.cachedLinks[url];
} else {
[toFind addObject:url];
NSCharacterSet *urlAllowedSet = [NSCharacterSet URLQueryAllowedCharacterSet];
[toFindStrings addObject:[url.absoluteString stringByAddingPercentEncodingWithAllowedCharacters:urlAllowedSet]];
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
[toFindStrings addObject:[url.absoluteString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
#pragma clang diagnostic pop
}
}
}
@ -205,7 +103,7 @@ static Class g_BFTaskClass;
// All of the URLs have already been found.
return [g_BFTaskClass taskWithResult:appLinks];
}
NSMutableArray<NSString *> *fields = [NSMutableArray arrayWithObject:kIOSKey];
NSMutableArray *fields = [NSMutableArray arrayWithObject:kIOSKey];
NSString *idiomSpecificField = nil;
@ -236,25 +134,25 @@ static Class g_BFTaskClass;
return;
}
for (NSURL *url in toFind) {
id nestedObject = result[url.absoluteString][kAppLinksKey];
id nestedObject = [[result objectForKey:url.absoluteString] objectForKey:kAppLinksKey];
NSMutableArray *rawTargets = [NSMutableArray array];
if (idiomSpecificField) {
[rawTargets addObjectsFromArray:nestedObject[idiomSpecificField]];
[rawTargets addObjectsFromArray:[nestedObject objectForKey:idiomSpecificField]];
}
[rawTargets addObjectsFromArray:nestedObject[kIOSKey]];
[rawTargets addObjectsFromArray:[nestedObject objectForKey:kIOSKey]];
NSMutableArray<BFAppLinkTarget *> *targets = [NSMutableArray arrayWithCapacity:rawTargets.count];
NSMutableArray *targets = [NSMutableArray arrayWithCapacity:rawTargets.count];
for (id rawTarget in rawTargets) {
[targets addObject:[g_BFAppLinkTargetClass appLinkTargetWithURL:[NSURL URLWithString:rawTarget[kURLKey]]
appStoreId:rawTarget[kIOSAppStoreIdKey]
appName:rawTarget[kIOSAppNameKey]]];
[targets addObject:[g_BFAppLinkTargetClass appLinkTargetWithURL:[NSURL URLWithString:[rawTarget objectForKey:kURLKey]]
appStoreId:[rawTarget objectForKey:kIOSAppStoreIdKey]
appName:[rawTarget objectForKey:kIOSAppNameKey]]];
}
id webTarget = nestedObject[kWebKey];
NSString *webFallbackString = webTarget[kURLKey];
id webTarget = [nestedObject objectForKey:kWebKey];
NSString *webFallbackString = [webTarget objectForKey:kURLKey];
NSURL *fallbackUrl = webFallbackString ? [NSURL URLWithString:webFallbackString] : url;
NSNumber *shouldFallback = webTarget[kShouldFallbackKey];
NSNumber *shouldFallback = [webTarget objectForKey:kShouldFallbackKey];
if (shouldFallback && !shouldFallback.boolValue) {
fallbackUrl = nil;
}
@ -262,8 +160,8 @@ static Class g_BFTaskClass;
BFAppLink *link = [g_BFAppLinkClass appLinkWithSourceURL:url
targets:targets
webURL:fallbackUrl];
@synchronized (self.cachedBFAppLinks) {
self.cachedBFAppLinks[url] = link;
@synchronized (self.cachedLinks) {
self.cachedLinks[url] = link;
}
appLinks[url] = link;
}
@ -272,8 +170,6 @@ static Class g_BFTaskClass;
return tcs.task;
}
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
- (BFTask *)appLinkFromURLInBackground:(NSURL *)url
{
// Implement in terms of appLinksFromURLsInBackground
@ -282,9 +178,8 @@ static Class g_BFTaskClass;
return task.result[url];
}];
}
#pragma clang diagnostic pop
+ (instancetype)resolver
+ (id)resolver
{
return [[self alloc] initWithUserInterfaceIdiom:UI_USER_INTERFACE_IDIOM()];
}

View File

@ -1,60 +0,0 @@
// 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>
NS_ASSUME_NONNULL_BEGIN
@class FBSDKAppLink;
/**
Describes the callback for appLinkFromURLInBackground.
@param appLink the FBSDKAppLink representing the deferred App Link
@param error the error during the request, if any
*/
typedef void (^FBSDKAppLinkFromURLHandler)(FBSDKAppLink * _Nullable appLink, NSError * _Nullable error);
/**
Describes the callback for appLinkFromURLInBackground.
@param appLinks the FBSDKAppLinks representing the deferred App Links
@param error the error during the request, if any
*/
typedef void (^FBSDKAppLinksFromURLArrayHandler)(NSDictionary<NSURL *, FBSDKAppLink *> * appLinks,
NSError * _Nullable error);
/*!
Implement this protocol to provide an alternate strategy for resolving
App Links that may include pre-fetching, caching, or querying for App Link
data from an index provided by a service provider.
*/
@protocol FBSDKAppLinkResolving <NSObject>
/**
Asynchronously resolves App Link data for a given URL.
@param url The URL to resolve into an App Link.
@param handler The completion block that will return an App Link for the given URL.
*/
- (void)appLinkFromURL:(NSURL *)url handler:(FBSDKAppLinkFromURLHandler)handler
NS_EXTENSION_UNAVAILABLE_IOS("Not available in app extension");
@end
NS_ASSUME_NONNULL_END

View File

@ -1,100 +0,0 @@
// Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
//
// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,
// copy, modify, and distribute this software in source code or binary form for use
// in connection with the web services and APIs provided by Facebook.
//
// As with any software that integrates with the Facebook platform, your use of
// this software is subject to the Facebook Developer Principles and Policies
// [http://developers.facebook.com/policy/]. This copyright notice shall be
// included in all copies or substantial portions of the software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#import "FBSDKAppLinkReturnToRefererView.h"
NS_ASSUME_NONNULL_BEGIN
@class FBSDKAppLink;
@class FBSDKAppLinkReturnToRefererController;
/*!
Protocol that a class can implement in order to be notified when the user has navigated back
to the referer of an App Link.
*/
@protocol FBSDKAppLinkReturnToRefererControllerDelegate <NSObject>
@optional
/*! Called when the user has tapped to navigate, but before the navigation has been performed. */
- (void)returnToRefererController:(FBSDKAppLinkReturnToRefererController *)controller
willNavigateToAppLink:(FBSDKAppLink *)appLink;
/*! Called after the navigation has been attempted, with an indication of whether the referer
app link was successfully opened. */
- (void)returnToRefererController:(FBSDKAppLinkReturnToRefererController *)controller
didNavigateToAppLink:(FBSDKAppLink *)url
type:(FBSDKAppLinkNavigationType)type;
@end
/*!
A controller class that implements default behavior for a FBSDKAppLinkReturnToRefererView, including
the ability to display the view above the navigation bar for navigation-based apps.
*/
NS_EXTENSION_UNAVAILABLE_IOS("Not available in app extension")
@interface FBSDKAppLinkReturnToRefererController : NSObject <FBSDKAppLinkReturnToRefererViewDelegate>
/*!
The delegate that will be notified when the user navigates back to the referer.
*/
@property (nonatomic, weak, nullable) id<FBSDKAppLinkReturnToRefererControllerDelegate> delegate;
/*!
The FBSDKAppLinkReturnToRefererView this controller is controlling.
*/
@property (nonatomic, strong) FBSDKAppLinkReturnToRefererView *view;
/*!
Initializes a controller suitable for controlling a FBSDKAppLinkReturnToRefererView that is to be displayed
contained within another UIView (i.e., not displayed above the navigation bar).
*/
- (instancetype)init NS_DESIGNATED_INITIALIZER;
/*!
Initializes a controller suitable for controlling a FBSDKAppLinkReturnToRefererView that is to be displayed
displayed above the navigation bar.
*/
- (instancetype)initForDisplayAboveNavController:(UINavigationController *)navController;
/*!
Removes the view entirely from the navigation controller it is currently displayed in.
*/
- (void)removeFromNavController;
/*!
Shows the FBSDKAppLinkReturnToRefererView with the specified referer information. If nil or missing data,
the view will not be displayed. */
- (void)showViewForRefererAppLink:(FBSDKAppLink *)refererAppLink;
/*!
Shows the FBSDKAppLinkReturnToRefererView with referer information extracted from the specified URL.
If nil or missing referer App Link data, the view will not be displayed. */
- (void)showViewForRefererURL:(NSURL *)url;
/*!
Closes the view, possibly animating it.
*/
- (void)closeViewAnimated:(BOOL)animated;
@end
NS_ASSUME_NONNULL_END

View File

@ -1,238 +0,0 @@
// 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 "FBSDKAppLinkReturnToRefererController.h"
#import "FBSDKAppLink.h"
#import "FBSDKAppLinkReturnToRefererView_Internal.h"
#import "FBSDKURL_Internal.h"
static const CFTimeInterval kFBSDKViewAnimationDuration = 0.25f;
@implementation FBSDKAppLinkReturnToRefererController {
UINavigationController *_navigationController;
FBSDKAppLinkReturnToRefererView *_view;
}
#pragma mark - Object lifecycle
- (instancetype)init {
return [super init];
}
- (instancetype)initForDisplayAboveNavController:(UINavigationController *)navController {
self = [self init];
if (self) {
_navigationController = navController;
if (_navigationController != nil) {
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
[nc addObserver:self
selector:@selector(statusBarFrameWillChange:)
name:UIApplicationWillChangeStatusBarFrameNotification
object:nil];
[nc addObserver:self
selector:@selector(statusBarFrameDidChange:)
name:UIApplicationDidChangeStatusBarFrameNotification
object:nil];
[nc addObserver:self
selector:@selector(orientationDidChange:)
name:UIDeviceOrientationDidChangeNotification
object:nil];
}
}
return self;
}
- (void)dealloc {
_view.delegate = nil;
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
#pragma mark - Public API
- (FBSDKAppLinkReturnToRefererView *)view {
if (!_view) {
self.view = [[FBSDKAppLinkReturnToRefererView alloc] initWithFrame:CGRectZero];
if (_navigationController) {
[_navigationController.view addSubview:_view];
}
}
return _view;
}
- (void)setView:(FBSDKAppLinkReturnToRefererView *)view {
if (_view != view) {
_view.delegate = nil;
}
_view = view;
_view.delegate = self;
if (_navigationController) {
_view.includeStatusBarInSize = FBSDKIncludeStatusBarInSizeAlways;
}
}
- (void)showViewForRefererAppLink:(FBSDKAppLink *)refererAppLink {
self.view.refererAppLink = refererAppLink;
[_view sizeToFit];
if (_navigationController) {
if (!_view.closed) {
dispatch_async(dispatch_get_main_queue(), ^{
[self moveNavigationBar];
});
}
}
}
- (void)showViewForRefererURL:(NSURL *)url {
FBSDKAppLink *appLink = [FBSDKURL URLForRenderBackToReferrerBarURL:url].appLinkReferer;
[self showViewForRefererAppLink:appLink];
}
- (void)removeFromNavController {
if (_navigationController) {
[_view removeFromSuperview];
_navigationController = nil;
}
}
#pragma mark - FBSDKAppLinkReturnToRefererViewDelegate
- (void)returnToRefererViewDidTapInsideCloseButton:(FBSDKAppLinkReturnToRefererView *)view {
[self closeViewAnimated:YES explicitlyClosed:YES];
}
- (void)returnToRefererViewDidTapInsideLink:(FBSDKAppLinkReturnToRefererView *)view
link:(FBSDKAppLink *)link {
[self openRefererAppLink:link];
[self closeViewAnimated:NO explicitlyClosed:NO];
}
#pragma mark - Private
- (void)statusBarFrameWillChange:(NSNotification *)notification {
NSValue *rectValue = [notification.userInfo valueForKey:UIApplicationStatusBarFrameUserInfoKey];
CGRect newFrame;
[rectValue getValue:&newFrame];
if (_navigationController && !_view.closed) {
if (CGRectGetHeight(newFrame) == 40) {
UIViewAnimationOptions options = UIViewAnimationOptionBeginFromCurrentState;
[UIView animateWithDuration:kFBSDKViewAnimationDuration delay:0.0 options:options animations:^{
self->_view.frame = CGRectMake(0.0, 0.0, CGRectGetWidth(self->_view.bounds), 0.0);
} completion:nil];
}
}
}
- (void)statusBarFrameDidChange:(NSNotification *)notification {
NSValue *rectValue = [notification.userInfo valueForKey:UIApplicationStatusBarFrameUserInfoKey];
CGRect newFrame;
[rectValue getValue:&newFrame];
if (_navigationController && !_view.closed) {
if (CGRectGetHeight(newFrame) == 40) {
UIViewAnimationOptions options = UIViewAnimationOptionBeginFromCurrentState;
[UIView animateWithDuration:kFBSDKViewAnimationDuration delay:0.0 options:options animations:^{
[self->_view sizeToFit];
[self moveNavigationBar];
} completion:nil];
}
}
}
- (void)orientationDidChange:(NSNotificationCenter *)notification {
if (_navigationController && !_view.closed && CGRectGetHeight(_view.bounds) > 0) {
dispatch_async(dispatch_get_main_queue(), ^{
[self moveNavigationBar];
});
}
}
- (void)moveNavigationBar {
if (_view.closed || !_view.refererAppLink) {
return;
}
[self updateNavigationBarY:CGRectGetHeight(_view.bounds)];
}
- (void)updateNavigationBarY:(CGFloat)y {
UINavigationBar *navigationBar = _navigationController.navigationBar;
CGRect navigationBarFrame = navigationBar.frame;
CGFloat oldContainerViewY = CGRectGetMaxY(navigationBarFrame);
navigationBarFrame.origin.y = y;
navigationBar.frame = navigationBarFrame;
CGFloat dy = CGRectGetMaxY(navigationBarFrame) - oldContainerViewY;
UIView *containerView = _navigationController.visibleViewController.view.superview;
containerView.frame = UIEdgeInsetsInsetRect(containerView.frame, UIEdgeInsetsMake(dy, 0.0, 0.0, 0.0));
}
- (void)closeViewAnimated:(BOOL)animated {
[self closeViewAnimated:animated explicitlyClosed:YES];
}
- (void)closeViewAnimated:(BOOL)animated explicitlyClosed:(BOOL)explicitlyClosed {
void (^closer)(void) = ^{
if (self->_navigationController) {
[self updateNavigationBarY:self->_view.statusBarHeight];
}
CGRect frame = self->_view.frame;
frame.size.height = 0.0;
self->_view.frame = frame;
};
if (animated) {
[UIView animateWithDuration:kFBSDKViewAnimationDuration animations:^{
closer();
} completion:^(BOOL finished) {
if (explicitlyClosed) {
self->_view.closed = YES;
}
}];
} else {
closer();
if (explicitlyClosed) {
self->_view.closed = YES;
}
}
}
- (void)openRefererAppLink:(FBSDKAppLink *)refererAppLink {
if (refererAppLink) {
id<FBSDKAppLinkReturnToRefererControllerDelegate> delegate = _delegate;
if ([delegate respondsToSelector:@selector(returnToRefererController:willNavigateToAppLink:)]) {
[delegate returnToRefererController:self willNavigateToAppLink:refererAppLink];
}
NSError *error = nil;
FBSDKAppLinkNavigationType type = [FBSDKAppLinkNavigation navigateToAppLink:refererAppLink error:&error];
if ([delegate respondsToSelector:@selector(returnToRefererController:didNavigateToAppLink:type:)]) {
[delegate returnToRefererController:self didNavigateToAppLink:refererAppLink type:type];
}
}
}
@end

View File

@ -1,90 +0,0 @@
// Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
//
// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,
// copy, modify, and distribute this software in source code or binary form for use
// in connection with the web services and APIs provided by Facebook.
//
// As with any software that integrates with the Facebook platform, your use of
// this software is subject to the Facebook Developer Principles and Policies
// [http://developers.facebook.com/policy/]. This copyright notice shall be
// included in all copies or substantial portions of the software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#import "FBSDKAppLinkNavigation.h"
NS_ASSUME_NONNULL_BEGIN
typedef NS_ENUM(NSUInteger, FBSDKIncludeStatusBarInSize) {
FBSDKIncludeStatusBarInSizeNever,
FBSDKIncludeStatusBarInSizeIOS7AndLater,
FBSDKIncludeStatusBarInSizeAlways,
};
@class FBSDKAppLinkReturnToRefererView;
@class FBSDKURL;
/*!
Protocol that a class can implement in order to be notified when the user has navigated back
to the referer of an App Link.
*/
@protocol FBSDKAppLinkReturnToRefererViewDelegate <NSObject>
/*!
Called when the user has tapped inside the close button.
*/
- (void)returnToRefererViewDidTapInsideCloseButton:(FBSDKAppLinkReturnToRefererView *)view;
/*!
Called when the user has tapped inside the App Link portion of the view.
*/
- (void)returnToRefererViewDidTapInsideLink:(FBSDKAppLinkReturnToRefererView *)view
link:(FBSDKAppLink *)link;
@end
/*!
Provides a UIView that displays a button allowing users to navigate back to the
application that launched the App Link currently being handled, if the App Link
contained referer data. The user can also close the view by clicking a close button
rather than navigating away. If the view is provided an App Link that does not contain
referer data, it will have zero size and no UI will be displayed.
*/
NS_EXTENSION_UNAVAILABLE_IOS("Not available in app extension")
@interface FBSDKAppLinkReturnToRefererView : UIView
/*!
The delegate that will be notified when the user navigates back to the referer.
*/
@property (nonatomic, weak, nullable) id<FBSDKAppLinkReturnToRefererViewDelegate> delegate;
/*!
The color of the text label and close button.
*/
@property (nonatomic, strong) UIColor *textColor;
@property (nonatomic, strong) FBSDKAppLink *refererAppLink;
/*!
Indicates whether to extend the size of the view to include the current status bar
size, for use in scenarios where the view might extend under the status bar on iOS 7 and
above; this property has no effect on earlier versions of iOS.
*/
@property (nonatomic, assign) FBSDKIncludeStatusBarInSize includeStatusBarInSize;
/*!
Indicates whether the user has closed the view by clicking the close button.
*/
@property (nonatomic, assign) BOOL closed;
@end
NS_ASSUME_NONNULL_END

View File

@ -1,271 +0,0 @@
// 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 "FBSDKAppLinkReturnToRefererView.h"
#import "FBSDKAppLink.h"
#import "FBSDKAppLinkTarget.h"
static const CGFloat FBSDKMarginX = 8.5f;
static const CGFloat FBSDKMarginY = 8.5f;
static NSString *const FBSDKRefererAppLink = @"referer_app_link";
static NSString *const FBSDKRefererAppName = @"app_name";
static NSString *const FBSDKRefererUrl = @"url";
static const CGFloat FBSDKCloseButtonWidth = 12.0;
static const CGFloat FBSDKCloseButtonHeight = 12.0;
@interface FBSDKAppLinkReturnToRefererView ()
@property (nonatomic, strong) UILabel *labelView;
@property (nonatomic, strong) UIButton *closeButton;
@property (nonatomic, strong) UITapGestureRecognizer *insideTapGestureRecognizer;
@end
@implementation FBSDKAppLinkReturnToRefererView {
BOOL _explicitlyHidden;
}
#pragma mark - Initialization
- (instancetype)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
[self commonInit];
[self sizeToFit];
}
return self;
}
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
self = [super initWithCoder:aDecoder];
if (self) {
[self commonInit];
}
return self;
}
- (void)commonInit {
// Initialization code
_includeStatusBarInSize = FBSDKIncludeStatusBarInSizeIOS7AndLater;
// iOS 7 system blue color
self.backgroundColor = [UIColor colorWithRed:0.0f green:122.0f / 255.0f blue:1.0f alpha:1.0f];
self.textColor = [UIColor whiteColor];
self.clipsToBounds = YES;
[self initViews];
}
- (void)initViews {
if (!_labelView && !_closeButton) {
_closeButton = [UIButton buttonWithType:UIButtonTypeCustom];
_closeButton.backgroundColor = [UIColor clearColor];
_closeButton.userInteractionEnabled = YES;
_closeButton.clipsToBounds = YES;
_closeButton.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleTopMargin;
_closeButton.contentMode = UIViewContentModeCenter;
[_closeButton addTarget:self action:@selector(closeButtonTapped:) forControlEvents:UIControlEventTouchUpInside];
[self addSubview:_closeButton];
_labelView = [[UILabel alloc] initWithFrame:CGRectZero];
_labelView.font = [UIFont systemFontOfSize:[UIFont smallSystemFontSize]];
_labelView.textColor = [UIColor whiteColor];
_labelView.backgroundColor = [UIColor clearColor];
_labelView.textAlignment = NSTextAlignmentCenter;
_labelView.clipsToBounds = YES;
[self updateLabelText];
[self addSubview:_labelView];
_insideTapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(onTapInside:)];
_labelView.userInteractionEnabled = YES;
[_labelView addGestureRecognizer:_insideTapGestureRecognizer];
[self updateColors];
}
}
#pragma mark - Layout
- (CGSize)intrinsicContentSize {
CGSize size = self.bounds.size;
if (_closed || !self.hasRefererData) {
size.height = 0.0;
} else {
CGSize labelSize = [_labelView sizeThatFits:size];
size = CGSizeMake(size.width, labelSize.height + 2 * FBSDKMarginY + self.statusBarHeight);
}
return size;
}
- (void)layoutSubviews {
[super layoutSubviews];
CGRect bounds = self.bounds;
_labelView.preferredMaxLayoutWidth = _labelView.bounds.size.width;
CGSize labelSize = [_labelView sizeThatFits:bounds.size];
_labelView.frame = CGRectMake(FBSDKMarginX,
CGRectGetMaxY(bounds) - labelSize.height - 1.5f * FBSDKMarginY,
CGRectGetMaxX(bounds) - FBSDKCloseButtonWidth - 3 * FBSDKMarginX,
labelSize.height + FBSDKMarginY);
_closeButton.frame = CGRectMake(CGRectGetMaxX(bounds) - FBSDKCloseButtonWidth - 2 * FBSDKMarginX,
_labelView.center.y - FBSDKCloseButtonHeight / 2.0f - FBSDKMarginY,
FBSDKCloseButtonWidth + 2 * FBSDKMarginX,
FBSDKCloseButtonHeight + 2 * FBSDKMarginY);
}
- (CGSize)sizeThatFits:(CGSize)size {
if (_closed || !self.hasRefererData) {
size = CGSizeMake(size.width, 0.0);
} else {
CGSize labelSize = [_labelView sizeThatFits:size];
size = CGSizeMake(size.width, labelSize.height + 2 * FBSDKMarginY + self.statusBarHeight);
}
return size;
}
- (CGFloat)statusBarHeight {
UIApplication *application = [UIApplication sharedApplication];
BOOL include;
switch (_includeStatusBarInSize) {
case FBSDKIncludeStatusBarInSizeAlways:
include = YES;
break;
case FBSDKIncludeStatusBarInSizeIOS7AndLater: {
float systemVersion = [UIDevice currentDevice].systemVersion.floatValue;
include = (systemVersion >= 7.0);
break;
}
case FBSDKIncludeStatusBarInSizeNever:
include = NO;
break;
}
if (include && !application.statusBarHidden) {
BOOL landscape = UIInterfaceOrientationIsLandscape(application.statusBarOrientation);
CGRect statusBarFrame = application.statusBarFrame;
return landscape ? CGRectGetWidth(statusBarFrame) : CGRectGetHeight(statusBarFrame);
}
return 0;
}
#pragma mark - Public API
- (void)setIncludeStatusBarInSize:(FBSDKIncludeStatusBarInSize)includeStatusBarInSize {
_includeStatusBarInSize = includeStatusBarInSize;
[self setNeedsLayout];
[self invalidateIntrinsicContentSize];
}
- (void)setTextColor:(UIColor *)textColor {
_textColor = textColor;
[self updateColors];
}
- (void)setRefererAppLink:(FBSDKAppLink *)refererAppLink {
_refererAppLink = refererAppLink;
[self updateLabelText];
[self updateHidden];
[self invalidateIntrinsicContentSize];
}
- (void)setClosed:(BOOL)closed {
if (_closed != closed) {
_closed = closed;
[self updateHidden];
[self invalidateIntrinsicContentSize];
}
}
- (void)setHidden:(BOOL)hidden {
_explicitlyHidden = hidden;
[self updateHidden];
}
#pragma mark - Private
- (void)updateLabelText {
NSString *appName = (_refererAppLink && _refererAppLink.targets[0]) ? _refererAppLink.targets[0].appName : nil;
_labelView.text = [self localizedLabelForReferer:appName];
}
- (void)updateColors {
UIImage *closeButtonImage = [self drawCloseButtonImageWithColor:_textColor];
_labelView.textColor = _textColor;
[_closeButton setImage:closeButtonImage forState:UIControlStateNormal];
}
- (UIImage *)drawCloseButtonImageWithColor:(UIColor *)color {
UIGraphicsBeginImageContextWithOptions(CGSizeMake(FBSDKCloseButtonWidth, FBSDKCloseButtonHeight), NO, 0.0f);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetStrokeColorWithColor(context, color.CGColor);
CGContextSetFillColorWithColor(context, color.CGColor);
CGContextSetLineWidth(context, 1.25f);
CGFloat inset = 0.5f;
CGContextMoveToPoint(context, inset, inset);
CGContextAddLineToPoint(context, FBSDKCloseButtonWidth - inset, FBSDKCloseButtonHeight - inset);
CGContextStrokePath(context);
CGContextMoveToPoint(context, FBSDKCloseButtonWidth - inset, inset);
CGContextAddLineToPoint(context, inset, FBSDKCloseButtonHeight - inset);
CGContextStrokePath(context);
UIImage *result = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return result;
}
- (NSString *)localizedLabelForReferer:(NSString *)refererName {
if (!refererName) {
return nil;
}
NSString *format = NSLocalizedString(@"Touch to return to %1$@", @"Format for the string to return to a calling app.");
return [NSString stringWithFormat:format, refererName];
}
- (BOOL)hasRefererData {
return _refererAppLink && _refererAppLink.targets[0];
}
- (void)closeButtonTapped:(id)sender {
[_delegate returnToRefererViewDidTapInsideCloseButton:self];
}
- (void)onTapInside:(UIGestureRecognizer *)sender {
[_delegate returnToRefererViewDidTapInsideLink:self link:_refererAppLink];
}
- (void)updateHidden {
super.hidden = _explicitlyHidden || _closed || !self.hasRefererData;
}
@end

View File

@ -1,45 +0,0 @@
// 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>
NS_ASSUME_NONNULL_BEGIN
/*!
Represents a target defined in App Link metadata, consisting of at least
a URL, and optionally an App Store ID and name.
*/
@interface FBSDKAppLinkTarget : NSObject
/*! Creates a FBSDKAppLinkTarget with the given app site and target URL. */
+ (instancetype)appLinkTargetWithURL:(NSURL *)url
appStoreId:(nullable NSString *)appStoreId
appName:(NSString *)appName;
/*! The URL prefix for this app link target */
@property (nonatomic, strong, readonly) NSURL *URL;
/*! The app ID for the app store */
@property (nonatomic, copy, readonly, nullable) NSString *appStoreId;
/*! The name of the app */
@property (nonatomic, copy, readonly) NSString *appName;
@end
NS_ASSUME_NONNULL_END

View File

@ -1,41 +0,0 @@
// 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 "FBSDKAppLinkTarget.h"
@interface FBSDKAppLinkTarget ()
@property (nonatomic, strong) NSURL *URL;
@property (nonatomic, copy) NSString *appStoreId;
@property (nonatomic, copy) NSString *appName;
@end
@implementation FBSDKAppLinkTarget
+ (instancetype)appLinkTargetWithURL:(NSURL *)url
appStoreId:(NSString *)appStoreId
appName:(NSString *)appName {
FBSDKAppLinkTarget *target = [[self alloc] init];
target.URL = url;
target.appStoreId = appStoreId;
target.appName = appName;
return target;
}
@end

View File

@ -20,8 +20,8 @@
/**
Describes the callback for fetchDeferredAppLink.
@param url the url representing the deferred App Link
@param error the error during the request, if any
- Parameter url: the url representing the deferred App Link
- Parameter error: the error during the request, if any
The url may also have a fb_click_time_utc query parameter that
@ -32,7 +32,7 @@ typedef void (^FBSDKDeferredAppLinkHandler)(NSURL *url, NSError *error);
/**
Describes the callback for fetchOrganicDeferredAppLink.
@param url the url representing the deferred App Link
- Parameter url: the url representing the deferred App Link
*/
typedef void (^FBSDKDeferredAppInviteHandler)(NSURL *url);
@ -49,7 +49,7 @@ typedef void (^FBSDKDeferredAppInviteHandler)(NSURL *url);
data (this will only return a valid URL once, and future calls will result in a nil URL
value in the callback).
@param handler the handler to be invoked if there is deferred App Link data
- Parameter handler: the handler to be invoked if there is deferred App Link data
The handler may contain an NSError instance to capture any errors. In the
@ -63,10 +63,10 @@ typedef void (^FBSDKDeferredAppInviteHandler)(NSURL *url);
/**
@warning This method is no longer available and will always return NO.
- Warning:This method is no longer available and will always return NO.
*/
+ (BOOL)fetchDeferredAppInvite:(FBSDKDeferredAppInviteHandler)handler
DEPRECATED_MSG_ATTRIBUTE("This method is no longer available.");
__attribute__((deprecated("This method is no longer available.")));;
/*
Call this method to fetch promotion code from the url, if it's present. This function
@ -75,9 +75,9 @@ DEPRECATED_MSG_ATTRIBUTE("This method is no longer available.");
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.
- Parameter url: App Link url that was passed to the app.
@return Promotion code string.
- Returns: Promotion code string.
Call this method to fetch App Invite Promotion Code from applink if present.

View File

@ -63,10 +63,10 @@ static NSString *const FBSDKDeferredAppLinkEvent = @"DEFERRED_APP_LINK";
NSString *createTimeUtc = result[@"click_time"];
if (createTimeUtc) {
// append/translate the create_time_utc so it can be used by clients
NSString *modifiedURLString = [applinkURL.absoluteString
NSString *modifiedURLString = [[applinkURL absoluteString]
stringByAppendingFormat:@"%@fb_click_time_utc=%@",
(applinkURL.query) ? @"&" : @"?" ,
createTimeUtc];
([applinkURL query]) ? @"&" : @"?" ,
createTimeUtc ];
applinkURL = [NSURL URLWithString:modifiedURLString];
}
}
@ -88,12 +88,12 @@ static NSString *const FBSDKDeferredAppLinkEvent = @"DEFERRED_APP_LINK";
+ (NSString*)appInvitePromotionCodeFromURL:(NSURL*)url;
{
BFURL *parsedUrl = [[FBSDKInternalUtility resolveBoltsClassWithName:@"BFURL"] URLWithURL:url];
NSDictionary *extras = parsedUrl.appLinkExtras;
NSDictionary *extras = [parsedUrl appLinkExtras];
if (extras) {
NSString *deeplinkContextString = extras[@"deeplink_context"];
// Parse deeplinkContext and extract promo code
if (deeplinkContextString.length > 0) {
if ([deeplinkContextString length] > 0) {
NSError *error = nil;
NSDictionary *deeplinkContextData = [FBSDKInternalUtility objectForJSONString:deeplinkContextString error:&error];
if (!error && [deeplinkContextData isKindOfClass:[NSDictionary class]]) {

View File

@ -41,15 +41,15 @@
of the AppDelegate for your app. It should be invoked for the proper processing of responses during interaction
with the native Facebook app or Safari as part of SSO authorization flow or Facebook dialogs.
@param application The application as passed to [UIApplicationDelegate application:openURL:sourceApplication:annotation:].
- Parameter application: The application as passed to [UIApplicationDelegate application:openURL:sourceApplication:annotation:].
@param url The URL as passed to [UIApplicationDelegate application:openURL:sourceApplication:annotation:].
- Parameter url: The URL as passed to [UIApplicationDelegate application:openURL:sourceApplication:annotation:].
@param sourceApplication The sourceApplication as passed to [UIApplicationDelegate application:openURL:sourceApplication:annotation:].
- Parameter sourceApplication: The sourceApplication as passed to [UIApplicationDelegate application:openURL:sourceApplication:annotation:].
@param annotation The annotation as passed to [UIApplicationDelegate application:openURL:sourceApplication:annotation:].
- Parameter annotation: The annotation as passed to [UIApplicationDelegate application:openURL:sourceApplication:annotation:].
@return YES if the url was intended for the Facebook SDK, NO if not.
- Returns: YES if the url was intended for the Facebook SDK, NO if not.
*/
- (BOOL)application:(UIApplication *)application
openURL:(NSURL *)url
@ -62,13 +62,13 @@
of the AppDelegate for your app. It should be invoked for the proper processing of responses during interaction
with the native Facebook app or Safari as part of SSO authorization flow or Facebook dialogs.
@param application The application as passed to [UIApplicationDelegate application:openURL:options:].
- Parameter application: The application as passed to [UIApplicationDelegate application:openURL:options:].
@param url The URL as passed to [UIApplicationDelegate application:openURL:options:].
- Parameter url: The URL as passed to [UIApplicationDelegate application:openURL:options:].
@param options The options dictionary as passed to [UIApplicationDelegate application:openURL:options:].
- Parameter options: The options dictionary as passed to [UIApplicationDelegate application:openURL:options:].
@return YES if the url was intended for the Facebook SDK, NO if not.
- Returns: YES if the url was intended for the Facebook SDK, NO if not.
*/
- (BOOL)application:(UIApplication *)application
openURL:(NSURL *)url
@ -81,11 +81,11 @@
As part of SDK initialization basic auto logging of app events will occur, this can be
controlled via 'FacebookAutoLogAppEventsEnabled' key in the project info plist file.
@param application The application as passed to [UIApplicationDelegate application:didFinishLaunchingWithOptions:].
- Parameter application: The application as passed to [UIApplicationDelegate application:didFinishLaunchingWithOptions:].
@param launchOptions The launchOptions as passed to [UIApplicationDelegate application:didFinishLaunchingWithOptions:].
- Parameter launchOptions: The launchOptions as passed to [UIApplicationDelegate application:didFinishLaunchingWithOptions:].
@return YES if the url was intended for the Facebook SDK, NO if not.
- Returns: YES if the url was intended for the Facebook SDK, NO if not.
*/
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions;

View File

@ -29,7 +29,6 @@
#import "FBSDKConstants.h"
#import "FBSDKDynamicFrameworkLoader.h"
#import "FBSDKError.h"
#import "FBSDKGateKeeperManager.h"
#import "FBSDKInternalUtility.h"
#import "FBSDKLogger.h"
#import "FBSDKServerConfiguration.h"
@ -46,16 +45,8 @@
#import "FBSDKProfile+Internal.h"
#endif
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0
NSNotificationName const FBSDKApplicationDidBecomeActiveNotification = @"com.facebook.sdk.FBSDKApplicationDidBecomeActiveNotification";
#else
NSString *const FBSDKApplicationDidBecomeActiveNotification = @"com.facebook.sdk.FBSDKApplicationDidBecomeActiveNotification";
#endif
static NSString *const FBSDKAppLinkInboundEvent = @"fb_al_inbound";
@implementation FBSDKApplicationDelegate
@ -64,14 +55,13 @@ static NSString *const FBSDKAppLinkInboundEvent = @"fb_al_inbound";
FBSDKBridgeAPIRequest *_pendingRequest;
FBSDKBridgeAPICallbackBlock _pendingRequestCompletionBlock;
id<FBSDKURLOpening> _pendingURLOpen;
#ifdef __IPHONE_11_0
SFAuthenticationSession *_authenticationSession NS_AVAILABLE_IOS(11_0);
SFAuthenticationCompletionHandler _authenticationSessionCompletionHandler NS_AVAILABLE_IOS(11_0);
#endif
#endif
BOOL _expectingBackground;
BOOL _isRequestingSFAuthenticationSession;
UIViewController *_safariViewController;
BOOL _isDismissingSafariViewController;
BOOL _isAppLaunched;
}
#pragma mark - Class Methods
@ -90,9 +80,6 @@ static NSString *const FBSDKAppLinkInboundEvent = @"fb_al_inbound";
+ (void)initializeWithLaunchData:(NSNotification *)note
{
NSDictionary *launchData = note.userInfo;
[[self sharedInstance] application:[UIApplication sharedApplication] didFinishLaunchingWithOptions:launchData];
#if !TARGET_OS_TV
// Register Listener for Bolts measurement events
[FBSDKBoltsMeasurementEventListener defaultListener];
@ -104,6 +91,7 @@ static NSString *const FBSDKAppLinkInboundEvent = @"fb_al_inbound";
[FBSDKTimeSpentData registerAutoResetSourceApplication];
[FBSDKInternalUtility validateFacebookReservedURLSchemes];
// Remove the observer
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
@ -126,8 +114,6 @@ static NSString *const FBSDKAppLinkInboundEvent = @"fb_al_inbound";
NSNotificationCenter *defaultCenter = [NSNotificationCenter defaultCenter];
[defaultCenter addObserver:self selector:@selector(applicationDidEnterBackground:) name:UIApplicationDidEnterBackgroundNotification object:nil];
[defaultCenter addObserver:self selector:@selector(applicationDidBecomeActive:) name:UIApplicationDidBecomeActiveNotification object:nil];
[[FBSDKAppEvents singleton] registerNotifications];
}
return self;
}
@ -149,14 +135,10 @@ static NSString *const FBSDKAppLinkInboundEvent = @"fb_al_inbound";
openURL:(NSURL *)url
options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options
{
if (@available(iOS 9.0, *)) {
return [self application:application
openURL:url
sourceApplication:options[UIApplicationOpenURLOptionsSourceApplicationKey]
annotation:options[UIApplicationOpenURLOptionsAnnotationKey]];
}
return NO;
return [self application:application
openURL:url
sourceApplication:options[UIApplicationOpenURLOptionsSourceApplicationKey]
annotation:options[UIApplicationOpenURLOptionsAnnotationKey]];
}
#endif
@ -176,12 +158,12 @@ static NSString *const FBSDKAppLinkInboundEvent = @"fb_al_inbound";
id<FBSDKURLOpening> pendingURLOpen = _pendingURLOpen;
void (^completePendingOpenURLBlock)(void) = ^{
self->_pendingURLOpen = nil;
_pendingURLOpen = nil;
[pendingURLOpen application:application
openURL:url
sourceApplication:sourceApplication
annotation:annotation];
self->_isDismissingSafariViewController = NO;
_isDismissingSafariViewController = NO;
};
// if they completed a SFVC flow, dismiss it.
if (_safariViewController) {
@ -190,12 +172,12 @@ static NSString *const FBSDKAppLinkInboundEvent = @"fb_al_inbound";
completion:completePendingOpenURLBlock];
_safariViewController = nil;
} else {
if (@available(iOS 11.0, *)) {
if (_authenticationSession != nil) {
[_authenticationSession cancel];
_authenticationSession = nil;
}
#ifdef __IPHONE_11_0
if (_authenticationSession != nil) {
[_authenticationSession cancel];
_authenticationSession = nil;
}
#endif
completePendingOpenURLBlock();
}
if ([pendingURLOpen canOpenURL:url
@ -215,21 +197,12 @@ static NSString *const FBSDKAppLinkInboundEvent = @"fb_al_inbound";
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
if (_isAppLaunched) {
return NO;
}
_isAppLaunched = YES;
FBSDKAccessToken *cachedToken = [FBSDKSettings accessTokenCache].accessToken;
FBSDKAccessToken *cachedToken = [[FBSDKSettings accessTokenCache] fetchAccessToken];
[FBSDKAccessToken setCurrentAccessToken:cachedToken];
// fetch app settings
[FBSDKServerConfigurationManager loadServerConfigurationWithCompletionBlock:NULL];
// fetch gate keepers
[FBSDKGateKeeperManager loadGateKeepers];
if ([FBSDKSettings autoLogAppEventsEnabled].boolValue) {
[self _logSDKInitialize];
}
[self _logSDKInitialize];
#if !TARGET_OS_TV
FBSDKProfile *cachedProfile = [FBSDKProfile fetchCachedProfile];
[FBSDKProfile setCurrentProfile:cachedProfile];
@ -255,7 +228,6 @@ static NSString *const FBSDKAppLinkInboundEvent = @"fb_al_inbound";
- (void)applicationDidEnterBackground:(NSNotification *)notification
{
_isRequestingSFAuthenticationSession = NO;
_active = NO;
_expectingBackground = NO;
}
@ -263,25 +235,22 @@ static NSString *const FBSDKAppLinkInboundEvent = @"fb_al_inbound";
- (void)applicationDidBecomeActive:(NSNotification *)notification
{
// Auto log basic events in case autoLogAppEventsEnabled is set
if ([FBSDKSettings autoLogAppEventsEnabled].boolValue) {
if ([[FBSDKSettings autoLogAppEventsEnabled] boolValue]) {
[FBSDKAppEvents activateApp];
}
// _expectingBackground can be YES if the caller started doing work (like login)
// within the app delegate's lifecycle like openURL, in which case there
// might have been a "didBecomeActive" event pending that we want to ignore.
BOOL notExpectingBackground = !_expectingBackground && !_safariViewController && !_isDismissingSafariViewController && !_isRequestingSFAuthenticationSession;
BOOL notExpectingBackground = !_expectingBackground && !_safariViewController && !_isDismissingSafariViewController;
#if !TARGET_OS_TV
if (@available(iOS 11.0, *)) {
if (notExpectingBackground && _authenticationSessionCompletionHandler != nil) {
_authenticationSessionCompletionHandler(nil, nil);
}
notExpectingBackground = notExpectingBackground && !_authenticationSession;
}
#ifdef __IPHONE_11_0
notExpectingBackground = notExpectingBackground && !_authenticationSession;
#endif
#endif
if (notExpectingBackground) {
_active = YES;
#if !TARGET_OS_TV
[_pendingURLOpen applicationDidBecomeActive:notification.object];
[_pendingURLOpen applicationDidBecomeActive:[notification object]];
[self _cancelBridgeRequest];
#endif
[[NSNotificationCenter defaultCenter] postNotificationName:FBSDKApplicationDidBecomeActiveNotification object:self];
@ -302,11 +271,9 @@ static NSString *const FBSDKAppLinkInboundEvent = @"fb_al_inbound";
// Dispatch openURL calls to prevent hangs if we're inside the current app delegate's openURL flow already
NSOperatingSystemVersion iOS10Version = { .majorVersion = 10, .minorVersion = 0, .patchVersion = 0 };
if ([FBSDKInternalUtility isOSRunTimeVersionAtLeast:iOS10Version]) {
if (@available(iOS 10.0, *)) {
[[UIApplication sharedApplication] openURL:url options:@{} completionHandler:^(BOOL success) {
handler(success, nil);
}];
}
[[UIApplication sharedApplication] openURL:url options:@{} completionHandler:^(BOOL success) {
handler(success, nil);
}];
} else {
BOOL opened = [[UIApplication sharedApplication] openURL:url];
@ -344,14 +311,14 @@ static NSString *const FBSDKAppLinkInboundEvent = @"fb_al_inbound";
_pendingRequestCompletionBlock = [completionBlock copy];
void (^handler)(BOOL, NSError *) = ^(BOOL openedURL, NSError *anError) {
if (!openedURL) {
self->_pendingRequest = nil;
self->_pendingRequestCompletionBlock = nil;
_pendingRequest = nil;
_pendingRequestCompletionBlock = nil;
NSError *openedURLError;
if ([request.scheme hasPrefix:@"http"]) {
openedURLError = [NSError fbErrorWithCode:FBSDKErrorBrowserUnavailable
openedURLError = [FBSDKError errorWithCode:FBSDKBrowserUnavailableErrorCode
message:@"the app switch failed because the browser is unavailable"];
} else {
openedURLError = [NSError fbErrorWithCode:FBSDKErrorAppVersionUnsupported
openedURLError = [FBSDKError errorWithCode:FBSDKAppVersionUnsupportedErrorCode
message:@"the app switch failed because the destination app is out of date"];
}
FBSDKBridgeAPIResponse *response = [FBSDKBridgeAPIResponse bridgeAPIResponseWithRequest:request
@ -380,35 +347,22 @@ static NSString *const FBSDKAppLinkInboundEvent = @"fb_al_inbound";
_expectingBackground = NO;
_pendingURLOpen = sender;
if (@available(iOS 11.0, *)) {
if ([sender isAuthenticationURL:url]) {
Class SFAuthenticationSessionClass = fbsdkdfl_SFAuthenticationSessionClass();
if (SFAuthenticationSessionClass != nil) {
if (_authenticationSession != nil) {
[FBSDKLogger singleShotLogEntry:FBSDKLoggingBehaviorDeveloperErrors
formatString:@"There is already a request for authenticated session. Cancelling active SFAuthenticationSession before starting the new one.", nil];
[_authenticationSession cancel];
#ifdef __IPHONE_11_0
if ([sender isAuthenticationURL:url]) {
Class SFAuthenticationSessionClass = fbsdkdfl_SFAuthenticationSessionClass();
if (SFAuthenticationSessionClass != nil) {
_authenticationSession = [[SFAuthenticationSessionClass alloc] initWithURL:url callbackURLScheme:[FBSDKInternalUtility appURLScheme] completionHandler:^ (NSURL *aURL, NSError *error) {
handler(error == nil, error);
if (error == nil) {
[self application:[UIApplication sharedApplication] openURL:aURL sourceApplication:@"com.apple" annotation:nil];
}
__weak typeof(self) weakSelf = self;
_authenticationSessionCompletionHandler = ^ (NSURL *aURL, NSError *error) {
typeof(self) strongSelf = weakSelf;
strongSelf->_isRequestingSFAuthenticationSession = NO;
handler(error == nil, error);
if (error == nil) {
[strongSelf application:[UIApplication sharedApplication] openURL:aURL sourceApplication:@"com.apple" annotation:nil];
}
strongSelf->_authenticationSession = nil;
strongSelf->_authenticationSessionCompletionHandler = nil;
};
_authenticationSession = [[SFAuthenticationSessionClass alloc] initWithURL:url
callbackURLScheme:[FBSDKInternalUtility appURLScheme]
completionHandler:_authenticationSessionCompletionHandler];
_isRequestingSFAuthenticationSession = YES;
[_authenticationSession start];
return;
}
_authenticationSession = nil;
}];
[_authenticationSession start];
return;
}
}
#endif
// trying to dynamically load SFSafariViewController class
// so for the cases when it is available we can send users through Safari View Controller flow
@ -425,7 +379,7 @@ static NSString *const FBSDKAppLinkInboundEvent = @"fb_al_inbound";
NSURLComponents *components = [NSURLComponents componentsWithURL:url resolvingAgainstBaseURL:NO];
NSURLQueryItem *sfvcQueryItem = [[NSURLQueryItem alloc] initWithName:@"sfvc" value:@"1"];
components.queryItems = [components.queryItems arrayByAddingObject:sfvcQueryItem];
[components setQueryItems:[components.queryItems arrayByAddingObject:sfvcQueryItem]];
url = components.URL;
FBSDKContainerViewController *container = [[FBSDKContainerViewController alloc] init];
container.delegate = self;
@ -433,11 +387,11 @@ static NSString *const FBSDKAppLinkInboundEvent = @"fb_al_inbound";
// Wait until the transition is finished before presenting SafariVC to avoid a blank screen.
[parent.transitionCoordinator animateAlongsideTransition:NULL completion:^(id<UIViewControllerTransitionCoordinatorContext> context) {
// Note SFVC init must occur inside block to avoid blank screen.
self->_safariViewController = [[SFSafariViewControllerClass alloc] initWithURL:url];
_safariViewController = [[SFSafariViewControllerClass alloc] initWithURL:url];
// Disable dismissing with edge pan gesture
self->_safariViewController.modalPresentationStyle = UIModalPresentationOverFullScreen;
[self->_safariViewController performSelector:@selector(setDelegate:) withObject:self];
[container displayChildController:self->_safariViewController];
_safariViewController.modalPresentationStyle = UIModalPresentationOverFullScreen;
[_safariViewController performSelector:@selector(setDelegate:) withObject:self];
[container displayChildController:_safariViewController];
[parent presentViewController:container animated:YES completion:nil];
}];
} else {
@ -515,8 +469,8 @@ static NSString *const FBSDKAppLinkInboundEvent = @"fb_al_inbound";
NSURL *targetURL = [targetURLString isKindOfClass:[NSString class]] ? [NSURL URLWithString:targetURLString] : nil;
NSMutableDictionary *logData = [[NSMutableDictionary alloc] init];
[FBSDKInternalUtility dictionary:logData setObject:targetURL.absoluteString forKey:@"targetURL"];
[FBSDKInternalUtility dictionary:logData setObject:targetURL.host forKey:@"targetURLHost"];
[FBSDKInternalUtility dictionary:logData setObject:[targetURL absoluteString] forKey:@"targetURL"];
[FBSDKInternalUtility dictionary:logData setObject:[targetURL host] forKey:@"targetURLHost"];
NSDictionary *refererData = applinkData[@"referer_data"];
if (refererData) {
@ -524,8 +478,8 @@ static NSString *const FBSDKAppLinkInboundEvent = @"fb_al_inbound";
[FBSDKInternalUtility dictionary:logData setObject:refererData[@"url"] forKey:@"referralURL"];
[FBSDKInternalUtility dictionary:logData setObject:refererData[@"app_name"] forKey:@"referralAppName"];
}
[FBSDKInternalUtility dictionary:logData setObject:url.absoluteString forKey:@"inputURL"];
[FBSDKInternalUtility dictionary:logData setObject:url.scheme forKey:@"inputURLScheme"];
[FBSDKInternalUtility dictionary:logData setObject:[url absoluteString] forKey:@"inputURL"];
[FBSDKInternalUtility dictionary:logData setObject:[url scheme] forKey:@"inputURLScheme"];
[FBSDKAppEvents logImplicitEvent:FBSDKAppLinkInboundEvent
valueToSum:nil
@ -536,27 +490,24 @@ static NSString *const FBSDKAppLinkInboundEvent = @"fb_al_inbound";
- (void)_logSDKInitialize
{
NSMutableDictionary *params = [NSMutableDictionary new];
params[@"core_lib_included"] = @1;
[params setObject:@1 forKey:@"core_lib_included"];
if (objc_lookUpClass("FBSDKShareDialog") != nil) {
params[@"share_lib_included"] = @1;
[params setObject:@1 forKey:@"share_lib_included"];
}
if (objc_lookUpClass("FBSDKLoginManager") != nil) {
params[@"login_lib_included"] = @1;
[params setObject:@1 forKey:@"login_lib_included"];
}
if (objc_lookUpClass("FBSDKPlacesManager") != nil) {
params[@"places_lib_included"] = @1;
[params setObject:@1 forKey:@"places_lib_included"];
}
if (objc_lookUpClass("FBSDKMessengerButton") != nil) {
params[@"messenger_lib_included"] = @1;
[params setObject:@1 forKey:@"messenger_lib_included"];
}
if (objc_lookUpClass("FBSDKMessengerButton") != nil) {
params[@"messenger_lib_included"] = @1;
[params setObject:@1 forKey:@"messenger_lib_included"];
}
if (objc_lookUpClass("FBSDKTVInterfaceFactory.m") != nil) {
params[@"tv_lib_included"] = @1;
}
if (objc_lookUpClass("FBSDKAutoLog") != nil) {
params[@"marketing_lib_included"] = @1;
[params setObject:@1 forKey:@"tv_lib_included"];
}
[FBSDKAppEvents logEvent:@"fb_sdk_initialize" parameters:params];
}

View File

@ -76,7 +76,7 @@
- (CGRect)imageRectForContentRect:(CGRect)contentRect
{
if (self.hidden || CGRectIsEmpty(self.bounds)) {
if ([self isHidden] || CGRectIsEmpty(self.bounds)) {
return CGRectZero;
}
CGRect imageRect = UIEdgeInsetsInsetRect(contentRect, self.imageEdgeInsets);
@ -101,9 +101,9 @@
{
// automatic impression tracking if the button conforms to FBSDKButtonImpressionTracking
if ([self conformsToProtocol:@protocol(FBSDKButtonImpressionTracking)]) {
NSString *eventName = ((id<FBSDKButtonImpressionTracking>)self).impressionTrackingEventName;
NSString *identifier = ((id<FBSDKButtonImpressionTracking>)self).impressionTrackingIdentifier;
NSDictionary<NSString *, id> *parameters = ((id<FBSDKButtonImpressionTracking>)self).analyticsParameters;
NSString *eventName = [(id<FBSDKButtonImpressionTracking>)self impressionTrackingEventName];
NSString *identifier = [(id<FBSDKButtonImpressionTracking>)self impressionTrackingIdentifier];
NSDictionary *parameters = [(id<FBSDKButtonImpressionTracking>)self analyticsParameters];
if (eventName && identifier) {
FBSDKViewImpressionTracker *impressionTracker = [FBSDKViewImpressionTracker impressionTrackerWithEventName:eventName];
[impressionTracker logImpressionWithIdentifier:identifier parameters:parameters];
@ -114,7 +114,7 @@
- (CGSize)sizeThatFits:(CGSize)size
{
if (self.hidden) {
if ([self isHidden]) {
return CGSizeZero;
}
CGSize normalSize = [self sizeThatFits:size title:[self titleForState:UIControlStateNormal]];
@ -131,7 +131,7 @@
- (CGRect)titleRectForContentRect:(CGRect)contentRect
{
if (self.hidden || CGRectIsEmpty(self.bounds)) {
if ([self isHidden] || CGRectIsEmpty(self.bounds)) {
return CGRectZero;
}
CGRect imageRect = [self imageRectForContentRect:contentRect];
@ -174,9 +174,9 @@
- (void)checkImplicitlyDisabled
{
BOOL enabled = !_isExplicitlyDisabled && !self.implicitlyDisabled;
BOOL currentEnabled = self.enabled;
super.enabled = enabled;
BOOL enabled = !_isExplicitlyDisabled && ![self isImplicitlyDisabled];
BOOL currentEnabled = [self isEnabled];
[super setEnabled:enabled];
if (currentEnabled != enabled) {
[self invalidateIntrinsicContentSize];
[self setNeedsLayout];

View File

@ -18,305 +18,200 @@
#import <Foundation/Foundation.h>
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0
#import <FBSDKCoreKit/FBSDKMacros.h>
/**
The error domain for all errors from FBSDKCoreKit.
The error domain for all errors from FBSDKCoreKit.
Error codes from the SDK in the range 0-99 are reserved for this domain.
*/
FOUNDATION_EXPORT NSErrorDomain const FBSDKErrorDomain;
#else
FBSDK_EXTERN NSString *const FBSDKErrorDomain;
/**
The error domain for all errors from FBSDKCoreKit.
Error codes from the SDK in the range 0-99 are reserved for this domain.
NS_ENUM(NSInteger, FBSDKErrorCode)
Error codes for FBSDKErrorDomain.
*/
FOUNDATION_EXPORT NSString *const FBSDKErrorDomain;
#endif
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_11_0
/*
@methodgroup error userInfo keys
*/
/**
The userInfo key for the invalid collection for errors with FBSDKErrorInvalidArgument.
If the invalid argument is a collection, the collection can be found with this key and the individual
invalid item can be found with FBSDKErrorArgumentValueKey.
*/
FOUNDATION_EXPORT NSErrorUserInfoKey const FBSDKErrorArgumentCollectionKey;
/**
The userInfo key for the invalid argument name for errors with FBSDKErrorInvalidArgument.
*/
FOUNDATION_EXPORT NSErrorUserInfoKey const FBSDKErrorArgumentNameKey;
/**
The userInfo key for the invalid argument value for errors with FBSDKErrorInvalidArgument.
*/
FOUNDATION_EXPORT NSErrorUserInfoKey const FBSDKErrorArgumentValueKey;
/**
The userInfo key for the message for developers in NSErrors that originate from the SDK.
The developer message will not be localized and is not intended to be presented within the app.
*/
FOUNDATION_EXPORT NSErrorUserInfoKey const FBSDKErrorDeveloperMessageKey;
/**
The userInfo key describing a localized description that can be presented to the user.
*/
FOUNDATION_EXPORT NSErrorUserInfoKey const FBSDKErrorLocalizedDescriptionKey;
/**
The userInfo key describing a localized title that can be presented to the user, used with `FBSDKLocalizedErrorDescriptionKey`.
*/
FOUNDATION_EXPORT NSErrorUserInfoKey const FBSDKErrorLocalizedTitleKey;
/*
@methodgroup FBSDKGraphRequest error userInfo keys
*/
/**
The userInfo key describing the error category, for error recovery purposes.
See `FBSDKGraphErrorRecoveryProcessor` and `[FBSDKGraphRequest disableErrorRecovery]`.
*/
FOUNDATION_EXPORT NSErrorUserInfoKey const FBSDKGraphRequestErrorKey;
FOUNDATION_EXPORT NSErrorUserInfoKey const FBSDKGraphRequestErrorCategoryKey
DEPRECATED_MSG_ATTRIBUTE("use FBSDKGraphRequestErrorKey instead");
/*
The userInfo key for the Graph API error code.
*/
FOUNDATION_EXPORT NSErrorUserInfoKey const FBSDKGraphRequestErrorGraphErrorCodeKey;
FOUNDATION_EXPORT NSErrorUserInfoKey const FBSDKGraphRequestErrorGraphErrorCode
DEPRECATED_MSG_ATTRIBUTE("use FBSDKGraphRequestErrorGraphErrorCodeKey instead");
/*
The userInfo key for the Graph API error subcode.
*/
FOUNDATION_EXPORT NSErrorUserInfoKey const FBSDKGraphRequestErrorGraphErrorSubcodeKey;
FOUNDATION_EXPORT NSErrorUserInfoKey const FBSDKGraphRequestErrorGraphErrorSubcode
DEPRECATED_MSG_ATTRIBUTE("use FBSDKGraphRequestErrorGraphErrorSubcodeKey instead");
/*
The userInfo key for the HTTP status code.
*/
FOUNDATION_EXPORT NSErrorUserInfoKey const FBSDKGraphRequestErrorHTTPStatusCodeKey;
/*
The userInfo key for the raw JSON response.
*/
FOUNDATION_EXPORT NSErrorUserInfoKey const FBSDKGraphRequestErrorParsedJSONResponseKey;
#else
/*
@methodgroup error userInfo keys
*/
/**
The userInfo key for the invalid collection for errors with FBSDKErrorInvalidArgument.
If the invalid argument is a collection, the collection can be found with this key and the individual
invalid item can be found with FBSDKErrorArgumentValueKey.
*/
FOUNDATION_EXPORT NSString *const FBSDKErrorArgumentCollectionKey;
/**
The userInfo key for the invalid argument name for errors with FBSDKErrorInvalidArgument.
*/
FOUNDATION_EXPORT NSString *const FBSDKErrorArgumentNameKey;
/**
The userInfo key for the invalid argument value for errors with FBSDKErrorInvalidArgument.
*/
FOUNDATION_EXPORT NSString *const FBSDKErrorArgumentValueKey;
/**
The userInfo key for the message for developers in NSErrors that originate from the SDK.
The developer message will not be localized and is not intended to be presented within the app.
*/
FOUNDATION_EXPORT NSString *const FBSDKErrorDeveloperMessageKey;
/**
The userInfo key describing a localized description that can be presented to the user.
*/
FOUNDATION_EXPORT NSString *const FBSDKErrorLocalizedDescriptionKey;
/**
The userInfo key describing a localized title that can be presented to the user, used with `FBSDKLocalizedErrorDescriptionKey`.
*/
FOUNDATION_EXPORT NSString *const FBSDKErrorLocalizedTitleKey;
/*
@methodgroup FBSDKGraphRequest error userInfo keys
*/
/**
The userInfo key describing the error category, for error recovery purposes.
See `FBSDKGraphErrorRecoveryProcessor` and `[FBSDKGraphRequest disableErrorRecovery]`.
*/
FOUNDATION_EXPORT NSString *const FBSDKGraphRequestErrorKey;
FOUNDATION_EXPORT NSString *const FBSDKGraphRequestErrorCategoryKey
DEPRECATED_MSG_ATTRIBUTE("use FBSDKGraphRequestErrorKey instead");
/*
The userInfo key for the Graph API error code.
*/
FOUNDATION_EXPORT NSString *const FBSDKGraphRequestErrorGraphErrorCodeKey;
FOUNDATION_EXPORT NSString *const FBSDKGraphRequestErrorGraphErrorCode
DEPRECATED_MSG_ATTRIBUTE("use FBSDKGraphRequestErrorGraphErrorCodeKey instead");
/*
The userInfo key for the Graph API error subcode.
*/
FOUNDATION_EXPORT NSString *const FBSDKGraphRequestErrorGraphErrorSubcodeKey;
FOUNDATION_EXPORT NSString *const FBSDKGraphRequestErrorGraphErrorSubcode
DEPRECATED_MSG_ATTRIBUTE("use FBSDKGraphRequestErrorGraphErrorSubcodeKey instead");
/*
The userInfo key for the HTTP status code.
*/
FOUNDATION_EXPORT NSString *const FBSDKGraphRequestErrorHTTPStatusCodeKey;
/*
The userInfo key for the raw JSON response.
*/
FOUNDATION_EXPORT NSString *const FBSDKGraphRequestErrorParsedJSONResponseKey;
#endif
#ifndef NS_ERROR_ENUM
#define NS_ERROR_ENUM(_domain, _name) \
enum _name: NSInteger _name; \
enum __attribute__((ns_error_domain(_domain))) _name: NSInteger
#endif
/**
FBSDKError
Error codes for FBSDKErrorDomain.
*/
typedef NS_ERROR_ENUM(FBSDKErrorDomain, FBSDKError)
typedef NS_ENUM(NSInteger, FBSDKErrorCode)
{
/**
Reserved.
Reserved.
*/
FBSDKErrorReserved = 0,
FBSDKReservedErrorCode = 0,
/**
The error code for errors from invalid encryption on incoming encryption URLs.
The error code for errors from invalid encryption on incoming encryption URLs.
*/
FBSDKErrorEncryption,
FBSDKEncryptionErrorCode,
/**
The error code for errors from invalid arguments to SDK methods.
The error code for errors from invalid arguments to SDK methods.
*/
FBSDKErrorInvalidArgument,
FBSDKInvalidArgumentErrorCode,
/**
The error code for unknown errors.
The error code for unknown errors.
*/
FBSDKErrorUnknown,
FBSDKUnknownErrorCode,
/**
A request failed due to a network error. Use NSUnderlyingErrorKey to retrieve
the error object from the NSURLSession for more information.
A request failed due to a network error. Use NSUnderlyingErrorKey to retrieve
the error object from the NSURLConnection for more information.
*/
FBSDKErrorNetwork,
FBSDKNetworkErrorCode,
/**
The error code for errors encountered during an App Events flush.
The error code for errors encountered during an App Events flush.
*/
FBSDKErrorAppEventsFlush,
FBSDKAppEventsFlushErrorCode,
/**
An endpoint that returns a binary response was used with FBSDKGraphRequestConnection.
An endpoint that returns a binary response was used with FBSDKGraphRequestConnection.
Endpoints that return image/jpg, etc. should be accessed using NSURLRequest
Endpoints that return image/jpg, etc. should be accessed using NSURLRequest
*/
FBSDKErrorGraphRequestNonTextMimeTypeReturned,
FBSDKGraphRequestNonTextMimeTypeReturnedErrorCode,
/**
The operation failed because the server returned an unexpected response.
The operation failed because the server returned an unexpected response.
You can get this error if you are not using the most recent SDK, or you are accessing a version of the
You can get this error if you are not using the most recent SDK, or you are accessing a version of the
Graph API incompatible with the current SDK.
*/
FBSDKErrorGraphRequestProtocolMismatch,
FBSDKGraphRequestProtocolMismatchErrorCode,
/**
The Graph API returned an error.
The Graph API returned an error.
See below for useful userInfo keys (beginning with FBSDKGraphRequestError*)
See below for useful userInfo keys (beginning with FBSDKGraphRequestError*)
*/
FBSDKErrorGraphRequestGraphAPI,
FBSDKGraphRequestGraphAPIErrorCode,
/**
The specified dialog configuration is not available.
The specified dialog configuration is not available.
This error may signify that the configuration for the dialogs has not yet been downloaded from the server
This error may signify that the configuration for the dialogs has not yet been downloaded from the server
or that the dialog is unavailable. Subsequent attempts to use the dialog may succeed as the configuration is loaded.
*/
FBSDKErrorDialogUnavailable,
FBSDKDialogUnavailableErrorCode,
/**
Indicates an operation failed because a required access token was not found.
Indicates an operation failed because a required access token was not found.
*/
FBSDKErrorAccessTokenRequired,
FBSDKAccessTokenRequiredErrorCode,
/**
Indicates an app switch (typically for a dialog) failed because the destination app is out of date.
Indicates an app switch (typically for a dialog) failed because the destination app is out of date.
*/
FBSDKErrorAppVersionUnsupported,
FBSDKAppVersionUnsupportedErrorCode,
/**
Indicates an app switch to the browser (typically for a dialog) failed.
Indicates an app switch to the browser (typically for a dialog) failed.
*/
FBSDKErrorBrowserUnavailable,
FBSDKBrowserUnavailableErrorCode,
/**
- Warning:use FBSDKBrowserUnavailableErrorCode instead
*/
FBSDKBrowswerUnavailableErrorCode __attribute__ ((deprecated("use FBSDKBrowserUnavailableErrorCode instead"))) = FBSDKBrowserUnavailableErrorCode,
};
/**
FBSDKGraphRequestError
Describes the category of Facebook error. See `FBSDKGraphRequestErrorKey`.
NS_ENUM(NSUInteger, FBSDKGraphRequestErrorCategory)
Describes the category of Facebook error. See `FBSDKGraphRequestErrorCategoryKey`.
*/
typedef NS_ENUM(NSUInteger, FBSDKGraphRequestError)
typedef NS_ENUM(NSUInteger, FBSDKGraphRequestErrorCategory)
{
/** The default error category that is not known to be recoverable. Check `FBSDKLocalizedErrorDescriptionKey` for a user facing message. */
FBSDKGraphRequestErrorOther = 0,
FBSDKGraphRequestErrorCategoryOther = 0,
/** Indicates the error is temporary (such as server throttling). While a recoveryAttempter will be provided with the error instance, the attempt is guaranteed to succeed so you can simply retry the operation if you do not want to present an alert. */
FBSDKGraphRequestErrorTransient = 1,
FBSDKGraphRequestErrorCategoryTransient = 1,
/** Indicates the error can be recovered (such as requiring a login). A recoveryAttempter will be provided with the error instance that can take UI action. */
FBSDKGraphRequestErrorRecoverable = 2
FBSDKGraphRequestErrorCategoryRecoverable = 2
};
/*
@methodgroup error userInfo keys
*/
/**
a formal protocol very similar to the informal protocol NSErrorRecoveryAttempting
The userInfo key for the invalid collection for errors with FBSDKInvalidArgumentErrorCode.
If the invalid argument is a collection, the collection can be found with this key and the individual
invalid item can be found with FBSDKErrorArgumentValueKey.
*/
FBSDK_EXTERN NSString *const FBSDKErrorArgumentCollectionKey;
/**
The userInfo key for the invalid argument name for errors with FBSDKInvalidArgumentErrorCode.
*/
FBSDK_EXTERN NSString *const FBSDKErrorArgumentNameKey;
/**
The userInfo key for the invalid argument value for errors with FBSDKInvalidArgumentErrorCode.
*/
FBSDK_EXTERN NSString *const FBSDKErrorArgumentValueKey;
/**
The userInfo key for the message for developers in NSErrors that originate from the SDK.
The developer message will not be localized and is not intended to be presented within the app.
*/
FBSDK_EXTERN NSString *const FBSDKErrorDeveloperMessageKey;
/**
The userInfo key describing a localized description that can be presented to the user.
*/
FBSDK_EXTERN NSString *const FBSDKErrorLocalizedDescriptionKey;
/**
The userInfo key describing a localized title that can be presented to the user, used with `FBSDKLocalizedErrorDescriptionKey`.
*/
FBSDK_EXTERN NSString *const FBSDKErrorLocalizedTitleKey;
/*
@methodgroup FBSDKGraphRequest error userInfo keys
*/
/**
The userInfo key describing the error category, for error recovery purposes.
See `FBSDKGraphErrorRecoveryProcessor` and `[FBSDKGraphRequest disableErrorRecovery]`.
*/
FBSDK_EXTERN NSString *const FBSDKGraphRequestErrorCategoryKey;
/*
The userInfo key for the Graph API error code.
*/
FBSDK_EXTERN NSString *const FBSDKGraphRequestErrorGraphErrorCode;
/*
The userInfo key for the Graph API error subcode.
*/
FBSDK_EXTERN NSString *const FBSDKGraphRequestErrorGraphErrorSubcode;
/*
The userInfo key for the HTTP status code.
*/
FBSDK_EXTERN NSString *const FBSDKGraphRequestErrorHTTPStatusCodeKey;
/*
The userInfo key for the raw JSON response.
*/
FBSDK_EXTERN NSString *const FBSDKGraphRequestErrorParsedJSONResponseKey;
/**
a formal protocol very similar to the informal protocol NSErrorRecoveryAttempting
*/
@protocol FBSDKErrorRecoveryAttempting<NSObject>
/**
attempt the recovery
@param error the error
@param recoveryOptionIndex the selected option index
@param delegate the delegate
@param didRecoverSelector the callback selector, see discussion.
@param contextInfo context info to pass back to callback selector, see discussion.
attempt the recovery
- Parameter error: the error
- Parameter recoveryOptionIndex: the selected option index
- Parameter delegate: the delegate
- Parameter didRecoverSelector: the callback selector, see discussion.
- Parameter contextInfo: context info to pass back to callback selector, see discussion.
Given that an error alert has been presented document-modally to the user, and the user has chosen one of the error's recovery options, attempt recovery from the error, and send the selected message to the specified delegate. The option index is an index into the error's array of localized recovery options. The method selected by didRecoverSelector must have the same signature as:
@ -328,34 +223,3 @@ typedef NS_ENUM(NSUInteger, FBSDKGraphRequestError)
- (void)attemptRecoveryFromError:(NSError *)error optionIndex:(NSUInteger)recoveryOptionIndex delegate:(id)delegate didRecoverSelector:(SEL)didRecoverSelector contextInfo:(void *)contextInfo;
@end
/**
Deprecated
*/
typedef NS_ENUM(NSInteger, FBSDKErrorCode)
{
FBSDKReservedErrorCode DEPRECATED_MSG_ATTRIBUTE("use FBSDKErrorReserved instead") = 0,
FBSDKEncryptionErrorCode DEPRECATED_MSG_ATTRIBUTE("use FBSDKErrorEncryption instead"),
FBSDKInvalidArgumentErrorCode DEPRECATED_MSG_ATTRIBUTE("use FBSDKErrorInvalidArgument instead"),
FBSDKUnknownErrorCode DEPRECATED_MSG_ATTRIBUTE("use FBSDKErrorUnknown instead"),
FBSDKNetworkErrorCode DEPRECATED_MSG_ATTRIBUTE("use FBSDKErrorNetwork instead"),
FBSDKAppEventsFlushErrorCode DEPRECATED_MSG_ATTRIBUTE("use FBSDKErrorAppEventsFlush instead"),
FBSDKGraphRequestNonTextMimeTypeReturnedErrorCode DEPRECATED_MSG_ATTRIBUTE("use FBSDKErrorGraphRequestNonTextMimeTypeReturned instead"),
FBSDKGraphRequestProtocolMismatchErrorCode DEPRECATED_MSG_ATTRIBUTE("use FBSDKErrorGraphRequestProtocolMismatch instead"),
FBSDKGraphRequestGraphAPIErrorCode DEPRECATED_MSG_ATTRIBUTE("use FBSDKErrorGraphRequestGraphAPI instead"),
FBSDKDialogUnavailableErrorCode DEPRECATED_MSG_ATTRIBUTE("use FBSDKErrorDialogUnavailable instead"),
FBSDKAccessTokenRequiredErrorCode DEPRECATED_MSG_ATTRIBUTE("use FBSDKErrorAccessTokenRequired instead"),
FBSDKAppVersionUnsupportedErrorCode DEPRECATED_MSG_ATTRIBUTE("use FBSDKErrorAppVersionUnsupported instead"),
FBSDKBrowserUnavailableErrorCode DEPRECATED_MSG_ATTRIBUTE("use FBSDKErrorBrowserUnavailable instead"),
FBSDKBrowswerUnavailableErrorCode DEPRECATED_MSG_ATTRIBUTE("use FBSDKErrorBrowserUnavailable instead") = FBSDKBrowserUnavailableErrorCode,
} DEPRECATED_MSG_ATTRIBUTE("use FBSDKError instead");
/**
Deprecated
*/
typedef NS_ENUM(NSUInteger, FBSDKGraphRequestErrorCategory)
{
FBSDKGraphRequestErrorCategoryOther DEPRECATED_MSG_ATTRIBUTE("use FBSDKGraphRequestErrorOther instead") = 0,
FBSDKGraphRequestErrorCategoryTransient DEPRECATED_MSG_ATTRIBUTE("use FBSDKGraphRequestErrorTransient instead") = 1,
FBSDKGraphRequestErrorCategoryRecoverable DEPRECATED_MSG_ATTRIBUTE("use FBSDKGraphRequestErrorRecoverable instead") = 2
} DEPRECATED_MSG_ATTRIBUTE("use FBSDKGraphRequestError instead");

View File

@ -18,37 +18,8 @@
#import "FBSDKConstants.h"
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0
NSErrorDomain const FBSDKErrorDomain = @"com.facebook.sdk.core";
#else
NSString *const FBSDKErrorDomain = @"com.facebook.sdk.core";
#endif
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0
NSErrorUserInfoKey const FBSDKErrorArgumentCollectionKey = @"com.facebook.sdk:FBSDKErrorArgumentCollectionKey";
NSErrorUserInfoKey const FBSDKErrorArgumentNameKey = @"com.facebook.sdk:FBSDKErrorArgumentNameKey";
NSErrorUserInfoKey const FBSDKErrorArgumentValueKey = @"com.facebook.sdk:FBSDKErrorArgumentValueKey";
NSErrorUserInfoKey const FBSDKErrorDeveloperMessageKey = @"com.facebook.sdk:FBSDKErrorDeveloperMessageKey";
NSErrorUserInfoKey const FBSDKErrorLocalizedDescriptionKey = @"com.facebook.sdk:FBSDKErrorLocalizedDescriptionKey";
NSErrorUserInfoKey const FBSDKErrorLocalizedTitleKey = @"com.facebook.sdk:FBSDKErrorLocalizedErrorTitleKey";
NSErrorUserInfoKey const FBSDKGraphRequestErrorKey = @"com.facebook.sdk:FBSDKGraphRequestErrorCategoryKey";
NSErrorUserInfoKey const FBSDKGraphRequestErrorCategoryKey = @"com.facebook.sdk:FBSDKGraphRequestErrorCategoryKey";
NSErrorUserInfoKey const FBSDKGraphRequestErrorGraphErrorCodeKey = @"com.facebook.sdk:FBSDKGraphRequestErrorGraphErrorCode";
NSErrorUserInfoKey const FBSDKGraphRequestErrorGraphErrorCode = @"com.facebook.sdk:FBSDKGraphRequestErrorGraphErrorCode";
NSErrorUserInfoKey const FBSDKGraphRequestErrorGraphErrorSubcodeKey = @"com.facebook.sdk:FBSDKGraphRequestErrorGraphErrorSubcode";
NSErrorUserInfoKey const FBSDKGraphRequestErrorGraphErrorSubcode = @"com.facebook.sdk:FBSDKGraphRequestErrorGraphErrorSubcode";
NSErrorUserInfoKey const FBSDKGraphRequestErrorHTTPStatusCodeKey = @"com.facebook.sdk:FBSDKGraphRequestErrorHTTPStatusCodeKey";
NSErrorUserInfoKey const FBSDKGraphRequestErrorParsedJSONResponseKey = @"com.facebook.sdk:FBSDKGraphRequestErrorParsedJSONResponseKey";
#else
NSString *const FBSDKErrorArgumentCollectionKey = @"com.facebook.sdk:FBSDKErrorArgumentCollectionKey";
NSString *const FBSDKErrorArgumentNameKey = @"com.facebook.sdk:FBSDKErrorArgumentNameKey";
NSString *const FBSDKErrorArgumentValueKey = @"com.facebook.sdk:FBSDKErrorArgumentValueKey";
@ -56,13 +27,8 @@ NSString *const FBSDKErrorDeveloperMessageKey = @"com.facebook.sdk:FBSDKErrorDev
NSString *const FBSDKErrorLocalizedDescriptionKey = @"com.facebook.sdk:FBSDKErrorLocalizedDescriptionKey";
NSString *const FBSDKErrorLocalizedTitleKey = @"com.facebook.sdk:FBSDKErrorLocalizedErrorTitleKey";
NSString *const FBSDKGraphRequestErrorKey = @"com.facebook.sdk:FBSDKGraphRequestErrorCategoryKey";
NSString *const FBSDKGraphRequestErrorCategoryKey = @"com.facebook.sdk:FBSDKGraphRequestErrorCategoryKey";
NSString *const FBSDKGraphRequestErrorGraphErrorCodeKey = @"com.facebook.sdk:FBSDKGraphRequestErrorGraphErrorCode";
NSString *const FBSDKGraphRequestErrorGraphErrorCode = @"com.facebook.sdk:FBSDKGraphRequestErrorGraphErrorCode";
NSString *const FBSDKGraphRequestErrorGraphErrorSubcodeKey = @"com.facebook.sdk:FBSDKGraphRequestErrorGraphErrorSubcode";
NSString *const FBSDKGraphRequestErrorGraphErrorSubcode = @"com.facebook.sdk:FBSDKGraphRequestErrorGraphErrorSubcode";
NSString *const FBSDKGraphRequestErrorHTTPStatusCodeKey = @"com.facebook.sdk:FBSDKGraphRequestErrorHTTPStatusCodeKey";
NSString *const FBSDKGraphRequestErrorParsedJSONResponseKey = @"com.facebook.sdk:FBSDKGraphRequestErrorParsedJSONResponseKey";
#endif

View File

@ -27,7 +27,7 @@
/**
Implemented by NSObject as a convenience to copyWithZone:.
@return A copy of the receiver.
- Returns: A copy of the receiver.
*/
- (id)copy;

View File

@ -33,25 +33,16 @@
#import <FBSDKCoreKit/FBSDKUtility.h>
#if !TARGET_OS_TV
#import <FBSDKCoreKit/FBSDKAppLink.h>
#import <FBSDKCoreKit/FBSDKAppLinkNavigation.h>
#import <FBSDKCoreKit/FBSDKAppLinkResolver.h>
#import <FBSDKCoreKit/FBSDKAppLinkResolving.h>
#import <FBSDKCoreKit/FBSDKAppLinkReturnToRefererController.h>
#import <FBSDKCoreKit/FBSDKAppLinkReturnToRefererView.h>
#import <FBSDKCoreKit/FBSDKAppLinkTarget.h>
#import <FBSDKCoreKit/FBSDKAppLinkUtility.h>
#import <FBSDKCoreKit/FBSDKGraphErrorRecoveryProcessor.h>
#import <FBSDKCoreKit/FBSDKMeasurementEvent.h>
#import <FBSDKCoreKit/FBSDKMutableCopying.h>
#import <FBSDKCoreKit/FBSDKProfile.h>
#import <FBSDKCoreKit/FBSDKProfilePictureView.h>
#import <FBSDKCoreKit/FBSDKURL.h>
#import <FBSDKCoreKit/FBSDKWebViewAppLinkResolver.h>
#else
#import <FBSDKCoreKit/FBSDKDeviceButton.h>
#import <FBSDKCoreKit/FBSDKDeviceViewControllerBase.h>
#endif
#define FBSDK_VERSION_STRING @"4.39.0"
#define FBSDK_TARGET_PLATFORM_VERSION @"v3.2"
#define FBSDK_VERSION_STRING @"4.29.0"
#define FBSDK_TARGET_PLATFORM_VERSION @"v2.11"

View File

@ -30,21 +30,21 @@
/**
Indicates the error recovery has been attempted.
@param processor the processor instance.
@param didRecover YES if the recovery was successful.
@param error the error that that was attempted to be recovered from.
- Parameter processor: the processor instance.
- Parameter didRecover: YES if the recovery was successful.
- Parameter error: the error that that was attempted to be recovered from.
*/
- (void)processorDidAttemptRecovery:(FBSDKGraphErrorRecoveryProcessor *)processor didRecover:(BOOL)didRecover error:(NSError *)error;
@optional
/**
Indicates the processor is about to process the error.
@param processor the processor instance.
@param error the error is about to be processed.
- Parameter processor: the processor instance.
- Parameter error: the error is about to be processed.
return NO if the processor should not process the error. For example,
if you want to prevent alerts of localized messages but otherwise perform retries and recoveries,
you could return NO for errors where userInfo[FBSDKGraphRequestErrorKey] equal to FBSDKGraphRequestErrorOther
you could return NO for errors where userInfo[FBSDKGraphRequestErrorCategoryKey] equal to FBSDKGraphRequestErrorCategoryOther
*/
- (BOOL)processorWillProcessError:(FBSDKGraphErrorRecoveryProcessor *)processor error:(NSError *)error;
@ -56,7 +56,7 @@
Facebook NSErrors can contain FBSDKErrorRecoveryAttempting instances to recover from errors, or
localized messages to present to the user. This class will process the instances as follows:
1. If the error is temporary as indicated by FBSDKGraphRequestErrorKey, assume the recovery succeeded and
1. If the error is temporary as indicated by FBSDKGraphRequestErrorCategoryKey, assume the recovery succeeded and
notify the delegate.
2. If a FBSDKErrorRecoveryAttempting instance is available, display an alert (dispatched to main thread)
with the recovery options and call the instance's [ attemptRecoveryFromError:optionIndex:...].
@ -83,16 +83,16 @@
/**
Attempts to process the error, return YES if the error can be processed.
@param error the error to process.
@param request the related request that may be reissued.
@param delegate the delegate that will be retained until recovery is complete.
- Parameter error: the error to process.
- Parameter request: the related request that may be reissued.
- Parameter delegate: the delegate that will be retained until recovery is complete.
*/
- (BOOL)processError:(NSError *)error request:(FBSDKGraphRequest *)request delegate:(id<FBSDKGraphErrorRecoveryProcessorDelegate>) delegate;
/**
The callback for FBSDKErrorRecoveryAttempting
@param didRecover if the recovery succeeded
@param contextInfo unused
- Parameter didRecover: if the recovery succeeded
- Parameter contextInfo: unused
*/
- (void)didPresentErrorWithRecovery:(BOOL)didRecover contextInfo:(void *)contextInfo;

View File

@ -20,13 +20,17 @@
#import "FBSDKCoreKit+Internal.h"
#import "FBSDKErrorRecoveryAttempter.h"
@interface FBSDKGraphErrorRecoveryProcessor()
@interface FBSDKGraphErrorRecoveryProcessor()<UIAlertViewDelegate>
{
FBSDKErrorRecoveryAttempter *_recoveryAttempter;
NSError *_error;
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
UIAlertView *_alertView;
#pragma clang diagnostic pop
}
@property (nonatomic, strong) id<FBSDKGraphErrorRecoveryProcessorDelegate>delegate;
@property (nonatomic, strong, readwrite) id<FBSDKGraphErrorRecoveryProcessorDelegate>delegate;
@end
@ -34,7 +38,9 @@
- (void)dealloc
{
if (_alertView) {
_alertView.delegate = nil;
}
}
- (BOOL)processError:(NSError *)error request:(FBSDKGraphRequest *)request delegate:(id<FBSDKGraphErrorRecoveryProcessorDelegate>) delegate
@ -46,13 +52,13 @@
}
}
FBSDKGraphRequestError errorCategory = [error.userInfo[FBSDKGraphRequestErrorKey] unsignedIntegerValue];
FBSDKGraphRequestErrorCategory errorCategory = [error.userInfo[FBSDKGraphRequestErrorCategoryKey] unsignedIntegerValue];
switch (errorCategory) {
case FBSDKGraphRequestErrorTransient :
case FBSDKGraphRequestErrorCategoryTransient :
[self.delegate processorDidAttemptRecovery:self didRecover:YES error:nil];
self.delegate = nil;
return YES;
case FBSDKGraphRequestErrorRecoverable :
case FBSDKGraphRequestErrorCategoryRecoverable :
if ([request.tokenString isEqualToString:[FBSDKAccessToken currentAccessToken].tokenString]) {
_recoveryAttempter = error.recoveryAttempter;
BOOL isLoginRecoveryAttempter = [_recoveryAttempter isKindOfClass:NSClassFromString(@"_FBSDKLoginRecoveryAttempter")];
@ -61,9 +67,9 @@
// the block returns YES if recovery UI is started (meaning we wait for the alertviewdelegate to resume control flow).
BOOL (^standardRecoveryWork)(void) = ^BOOL{
NSArray *recoveryOptionsTitles = error.userInfo[NSLocalizedRecoveryOptionsErrorKey];
if (recoveryOptionsTitles.count > 0 && self->_recoveryAttempter) {
if (recoveryOptionsTitles.count > 0 && _recoveryAttempter) {
NSString *recoverySuggestion = error.userInfo[NSLocalizedRecoverySuggestionErrorKey];
self->_error = error;
_error = error;
dispatch_async(dispatch_get_main_queue(), ^{
[self displayAlertWithRecoverySuggestion:recoverySuggestion recoveryOptionsTitles:recoveryOptionsTitles];
});
@ -72,7 +78,7 @@
return NO;
};
if ([request.tokenString isEqualToString:[FBSDKSystemAccountStoreAdapter sharedInstance].accessTokenString] &&
if ([request.tokenString isEqualToString:[[FBSDKSystemAccountStoreAdapter sharedInstance] accessTokenString]] &&
isLoginRecoveryAttempter) {
// special system auth case: if user has granted permissions we can simply renew. On a successful
// renew, treat this as immediately recovered without the standard alert prompty.
@ -84,7 +90,7 @@
[self.delegate processorDidAttemptRecovery:self didRecover:YES error:nil];
self.delegate = nil;
} else if (!standardRecoveryWork()) {
[self.delegate processorDidAttemptRecovery:self didRecover:NO error:self->_error];
[self.delegate processorDidAttemptRecovery:self didRecover:NO error:_error];
};
});
}];
@ -95,7 +101,7 @@
return standardRecoveryWork();
}
return NO;
case FBSDKGraphRequestErrorOther :
case FBSDKGraphRequestErrorCategoryOther :
if ([request.tokenString isEqualToString:[FBSDKAccessToken currentAccessToken].tokenString]) {
NSString *message = error.userInfo[FBSDKErrorLocalizedDescriptionKey];
NSString *title = error.userInfo[FBSDKErrorLocalizedTitleKey];
@ -114,53 +120,93 @@
return NO;
}
#pragma mark - UIAlertController support
#pragma mark - UIAlertView and UIAlertController support
- (void)displayAlertWithRecoverySuggestion:(NSString *)recoverySuggestion recoveryOptionsTitles:(NSArray<NSString *> *)recoveryOptionsTitles
{
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:nil
message:recoverySuggestion
preferredStyle:UIAlertControllerStyleAlert];
for (NSUInteger i = 0; i < recoveryOptionsTitles.count; i++) {
NSString *title = recoveryOptionsTitles[i];
UIAlertAction *option = [UIAlertAction actionWithTitle:title
style:UIAlertActionStyleDefault
handler:^(UIAlertAction * _Nonnull action) {
[self->_recoveryAttempter attemptRecoveryFromError:self->_error
optionIndex:i
delegate:self
didRecoverSelector:@selector(didPresentErrorWithRecovery:contextInfo:)
contextInfo:nil];
}];
[alertController addAction:option];
if ([UIAlertController class]) {
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:nil
message:recoverySuggestion
preferredStyle:UIAlertControllerStyleAlert];
for (NSUInteger i = 0; i < recoveryOptionsTitles.count; i++) {
NSString *title = recoveryOptionsTitles[i];
UIAlertAction *option = [UIAlertAction actionWithTitle:title
style:UIAlertActionStyleDefault
handler:^(UIAlertAction * _Nonnull action) {
[_recoveryAttempter attemptRecoveryFromError:_error
optionIndex:i
delegate:self
didRecoverSelector:@selector(didPresentErrorWithRecovery:contextInfo:)
contextInfo:nil];
}];
[alertController addAction:option];
}
UIViewController *topMostViewController = [FBSDKInternalUtility topMostViewController];
[topMostViewController presentViewController:alertController
animated:YES
completion:nil];
} else {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
_alertView = [[UIAlertView alloc] initWithTitle:nil
message:recoverySuggestion
delegate:self
cancelButtonTitle:nil
otherButtonTitles:nil];
#pragma clang diagnostic pop
for (NSString *option in recoveryOptionsTitles) {
[_alertView addButtonWithTitle:option];
}
[_alertView show];
}
UIViewController *topMostViewController = [FBSDKInternalUtility topMostViewController];
[topMostViewController presentViewController:alertController
animated:YES
completion:nil];
}
- (void)displayAlertWithTitle:(NSString *)title message:(NSString *)message cancelButtonTitle:(NSString *)localizedOK
{
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:nil
message:message
preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *OKAction = [UIAlertAction actionWithTitle:localizedOK
style:UIAlertActionStyleCancel
handler:^(UIAlertAction * _Nonnull action) {
[self->_recoveryAttempter attemptRecoveryFromError:self->_error
optionIndex:0
delegate:self
didRecoverSelector:@selector(didPresentErrorWithRecovery:contextInfo:)
contextInfo:nil];
}];
[alertController addAction:OKAction];
UIViewController *topMostViewController = [FBSDKInternalUtility topMostViewController];
[topMostViewController presentViewController:alertController
animated:YES
completion:nil];
if ([UIAlertController class]) {
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:nil
message:message
preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *OKAction = [UIAlertAction actionWithTitle:localizedOK
style:UIAlertActionStyleCancel
handler:^(UIAlertAction * _Nonnull action) {
[_recoveryAttempter attemptRecoveryFromError:_error
optionIndex:0
delegate:self
didRecoverSelector:@selector(didPresentErrorWithRecovery:contextInfo:)
contextInfo:nil];
}];
[alertController addAction:OKAction];
UIViewController *topMostViewController = [FBSDKInternalUtility topMostViewController];
[topMostViewController presentViewController:alertController
animated:YES
completion:nil];
} else {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
[[[UIAlertView alloc] initWithTitle:title
message:message
delegate:nil
cancelButtonTitle:localizedOK
otherButtonTitles:nil] show];
#pragma clang diagnostic pop
}
}
#pragma mark - UIAlertViewDelegate
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex
{
[_recoveryAttempter attemptRecoveryFromError:_error optionIndex:buttonIndex delegate:self didRecoverSelector:@selector(didPresentErrorWithRecovery:contextInfo:) contextInfo:nil];
if (_alertView) {
_alertView.delegate = nil;
_alertView = nil;
}
}
#pragma clang diagnostic pop
#pragma mark - FBSDKErrorRecoveryAttempting "delegate"
- (void)didPresentErrorWithRecovery:(BOOL)didRecover contextInfo:(void *)contextInfo

View File

@ -39,26 +39,23 @@
By default, FBSDKGraphRequest will attempt to recover any errors returned from
Facebook. You can disable this via `disableErrorRecovery:`.
@see FBSDKGraphErrorRecoveryProcessor
- See:FBSDKGraphErrorRecoveryProcessor
*/
@interface FBSDKGraphRequest : NSObject
- (instancetype)init NS_UNAVAILABLE;
+ (instancetype)new NS_UNAVAILABLE;
/**
Initializes a new instance that use use `[FBSDKAccessToken currentAccessToken]`.
@param graphPath the graph path (e.g., @"me").
@param parameters the optional parameters dictionary.
- Parameter graphPath: the graph path (e.g., @"me").
- Parameter parameters: the optional parameters dictionary.
*/
- (instancetype)initWithGraphPath:(NSString *)graphPath
parameters:(NSDictionary *)parameters;
/**
Initializes a new instance that use use `[FBSDKAccessToken currentAccessToken]`.
@param graphPath the graph path (e.g., @"me").
@param parameters the optional parameters dictionary.
@param HTTPMethod the optional HTTP method. nil defaults to @"GET".
- Parameter graphPath: the graph path (e.g., @"me").
- Parameter parameters: the optional parameters dictionary.
- Parameter HTTPMethod: the optional HTTP method. nil defaults to @"GET".
*/
- (instancetype)initWithGraphPath:(NSString *)graphPath
parameters:(NSDictionary *)parameters
@ -66,11 +63,11 @@
/**
Initializes a new instance.
@param graphPath the graph path (e.g., @"me").
@param parameters the optional parameters dictionary.
@param tokenString the token string to use. Specifying nil will cause no token to be used.
@param version the optional Graph API version (e.g., @"v2.0"). nil defaults to `[FBSDKSettings graphAPIVersion]`.
@param HTTPMethod the optional HTTP method (e.g., @"POST"). nil defaults to @"GET".
- Parameter graphPath: the graph path (e.g., @"me").
- Parameter parameters: the optional parameters dictionary.
- Parameter tokenString: the token string to use. Specifying nil will cause no token to be used.
- Parameter version: the optional Graph API version (e.g., @"v2.0"). nil defaults to `[FBSDKSettings graphAPIVersion]`.
- Parameter HTTPMethod: the optional HTTP method (e.g., @"POST"). nil defaults to @"GET".
*/
- (instancetype)initWithGraphPath:(NSString *)graphPath
parameters:(NSDictionary *)parameters
@ -106,7 +103,7 @@ NS_DESIGNATED_INITIALIZER;
/**
If set, disables the automatic error recovery mechanism.
@param disable whether to disable the automatic error recovery mechanism
- Parameter disable: whether to disable the automatic error recovery mechanism
By default, non-batched FBSDKGraphRequest instances will automatically try to recover
from errors by constructing a `FBSDKGraphErrorRecoveryProcessor` instance that
@ -119,7 +116,7 @@ NS_DESIGNATED_INITIALIZER;
/**
Starts a connection to the Graph API.
@param handler The handler block to call when the request completes.
- Parameter handler: The handler block to call when the request completes.
*/
- (FBSDKGraphRequestConnection *)startWithCompletionHandler:(FBSDKGraphRequestHandler)handler;

View File

@ -30,7 +30,6 @@
// constants
static NSString *const kGetHTTPMethod = @"GET";
static NSString *const kPostHTTPMethod = @"POST";
@interface FBSDKGraphRequest()
@property (nonatomic, assign) FBSDKGraphRequestFlags flags;
@ -38,6 +37,11 @@ static NSString *const kPostHTTPMethod = @"POST";
@implementation FBSDKGraphRequest
- (instancetype)init NS_UNAVAILABLE
{
assert(0);
}
- (instancetype)initWithGraphPath:(NSString *)graphPath
parameters:(NSDictionary *)parameters {
return [self initWithGraphPath:graphPath
@ -140,22 +144,12 @@ static NSString *const kPostHTTPMethod = @"POST";
+ (NSString *)serializeURL:(NSString *)baseUrl
params:(NSDictionary *)params
httpMethod:(NSString *)httpMethod {
return [self serializeURL:baseUrl params:params httpMethod:httpMethod forBatch:NO];
}
+ (NSString *)serializeURL:(NSString *)baseUrl
params:(NSDictionary *)params
httpMethod:(NSString *)httpMethod
forBatch:(BOOL)forBatch {
params = [self preprocessParams: params];
NSCharacterSet *urlAllowedSet = [NSCharacterSet URLFragmentAllowedCharacterSet];
NSURL *parsedURL = [NSURL URLWithString:[baseUrl stringByAddingPercentEncodingWithAllowedCharacters:urlAllowedSet]];
if ([httpMethod isEqualToString:kPostHTTPMethod] && !forBatch) {
return baseUrl;
}
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
NSURL *parsedURL = [NSURL URLWithString:[baseUrl stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
#pragma clang pop
NSString *queryPrefix = parsedURL.query ? @"&" : @"?";
NSString *query = [FBSDKInternalUtility queryStringWithDictionary:params error:NULL invalidObjectHandler:^id(id object, BOOL *stop) {
@ -175,7 +169,7 @@ static NSString *const kPostHTTPMethod = @"POST";
NSString *debugValue = [FBSDKSettings graphAPIDebugParamValue];
if (debugValue) {
NSMutableDictionary *mutableParams = [NSMutableDictionary dictionaryWithDictionary:params];
mutableParams[@"debug"] = debugValue;
[mutableParams setObject:debugValue forKey:@"debug"];
return mutableParams;
}
@ -203,7 +197,7 @@ static NSString *const kPostHTTPMethod = @"POST";
if (self.HTTPMethod) {
[result appendFormat:@", HTTPMethod: %@", self.HTTPMethod];
}
[result appendFormat:@", parameters: %@>", self.parameters.description];
[result appendFormat:@", parameters: %@>", [self.parameters description]];
return result;
}

View File

@ -18,6 +18,8 @@
#import <Foundation/Foundation.h>
#import <FBSDKCoreKit/FBSDKMacros.h>
@class FBSDKGraphRequest;
@class FBSDKGraphRequestConnection;
@ -32,13 +34,13 @@
Pass a block of this type when calling addRequest. This will be called once
the request completes. The call occurs on the UI thread.
@param connection The `FBSDKGraphRequestConnection` that sent the request.
- Parameter connection: The `FBSDKGraphRequestConnection` that sent the request.
@param result The result of the request. This is a translation of
- Parameter result: The result of the request. This is a translation of
JSON data to `NSDictionary` and `NSArray` objects. This
is nil if there was an error.
@param error The `NSError` representing any error that occurred.
- Parameter error: The `NSError` representing any error that occurred.
*/
typedef void (^FBSDKGraphRequestHandler)(FBSDKGraphRequestConnection *connection,
@ -66,7 +68,7 @@ typedef void (^FBSDKGraphRequestHandler)(FBSDKGraphRequestConnection *connection
start, the object returned from the convenience method has already begun loading and this method
will not be called when the delegate is set.
@param connection The request connection that is starting a network request
- Parameter connection: The request connection that is starting a network request
*/
- (void)requestConnectionWillBeginLoading:(FBSDKGraphRequestConnection *)connection;
@ -84,7 +86,7 @@ typedef void (^FBSDKGraphRequestHandler)(FBSDKGraphRequestConnection *connection
This method is invoked after the completion handler for each <FBSDKGraphRequest>.
@param connection The request connection that successfully completed a network request
- Parameter connection: The request connection that successfully completed a network request
*/
- (void)requestConnectionDidFinishLoading:(FBSDKGraphRequestConnection *)connection;
@ -99,8 +101,8 @@ typedef void (^FBSDKGraphRequestHandler)(FBSDKGraphRequestConnection *connection
argument specifies why the network connection failed. The `NSError` object passed to the
FBSDKGraphRequestHandler block may contain additional information.
@param connection The request connection that successfully completed a network request
@param error The `NSError` representing the network error that occurred, if any. May be nil
- Parameter connection: The request connection that successfully completed a network request
- Parameter error: The `NSError` representing the network error that occurred, if any. May be nil
in some circumstances. Consult the `NSError` for the <FBSDKGraphRequest> for reliable
failure information.
*/
@ -116,12 +118,12 @@ typedef void (^FBSDKGraphRequestHandler)(FBSDKGraphRequestConnection *connection
The byte count arguments refer to the aggregated <FBSDKGraphRequest> objects, not a particular <FBSDKGraphRequest>.
Like `NSURLSession`, the values may change in unexpected ways if data needs to be resent.
Like `NSURLConnection`, the values may change in unexpected ways if data needs to be resent.
@param connection The request connection transmitting data to a remote host
@param bytesWritten The number of bytes sent in the last transmission
@param totalBytesWritten The total number of bytes sent to the remote host
@param totalBytesExpectedToWrite The total number of bytes expected to send to the remote host
- Parameter connection: The request connection transmitting data to a remote host
- Parameter bytesWritten: The number of bytes sent in the last transmission
- Parameter totalBytesWritten: The total number of bytes sent to the remote host
- Parameter totalBytesExpectedToWrite: The total number of bytes expected to send to the remote host
*/
- (void)requestConnection:(FBSDKGraphRequestConnection *)connection
didSendBodyData:(NSInteger)bytesWritten
@ -151,7 +153,7 @@ totalBytesExpectedToWrite:(NSInteger)totalBytesExpectedToWrite;
/**
Gets or sets the timeout interval to wait for a response before giving up.
*/
@property (nonatomic, assign) NSTimeInterval timeout;
@property (nonatomic) NSTimeInterval timeout;
/**
The raw response that was returned from the server. (readonly)
@ -175,7 +177,7 @@ totalBytesExpectedToWrite:(NSInteger)totalBytesExpectedToWrite;
This method sets the default timeout on all FBSDKGraphRequestConnection instances. Defaults to 60 seconds.
@param defaultConnectionTimeout The timeout interval.
- Parameter defaultConnectionTimeout: The timeout interval.
*/
+ (void)setDefaultConnectionTimeout:(NSTimeInterval)defaultConnectionTimeout;
@ -188,8 +190,8 @@ totalBytesExpectedToWrite:(NSInteger)totalBytesExpectedToWrite;
This method adds an <FBSDKGraphRequest> object to this connection.
@param request A request to be included in the round-trip when start is called.
@param handler A handler to call back when the round-trip completes or times out.
- Parameter request: A request to be included in the round-trip when start is called.
- Parameter handler: A handler to call back when the round-trip completes or times out.
@ -204,12 +206,12 @@ totalBytesExpectedToWrite:(NSInteger)totalBytesExpectedToWrite;
This method adds an <FBSDKGraphRequest> object to this connection.
@param request A request to be included in the round-trip when start is called.
- Parameter request: A request to be included in the round-trip when start is called.
@param handler A handler to call back when the round-trip completes or times out.
- Parameter handler: A handler to call back when the round-trip completes or times out.
The handler will be invoked on the main thread.
@param name An optional name for this request. This can be used to feed
- Parameter name: An optional name for this request. This can be used to feed
the results of one request to the input of another <FBSDKGraphRequest> in the same
`FBSDKGraphRequestConnection` as described in
[Graph API Batch Requests]( https://developers.facebook.com/docs/reference/api/batch/ ).
@ -220,25 +222,20 @@ totalBytesExpectedToWrite:(NSInteger)totalBytesExpectedToWrite;
completion or cancellation of the connection. This request can be named
to allow for using the request's response in a subsequent request.
*/
- (void)addRequest:(FBSDKGraphRequest *)request
batchEntryName:(NSString *)name
completionHandler:(FBSDKGraphRequestHandler)handler;
- (void)addRequest:(FBSDKGraphRequest *)request
completionHandler:(FBSDKGraphRequestHandler)handler
batchEntryName:(NSString *)name
DEPRECATED_MSG_ATTRIBUTE("Renamed `addRequest:batchEntryName:completionHandler:`");
batchEntryName:(NSString *)name;
/**
@method
This method adds an <FBSDKGraphRequest> object to this connection.
@param request A request to be included in the round-trip when start is called.
- Parameter request: A request to be included in the round-trip when start is called.
@param handler A handler to call back when the round-trip completes or times out.
- Parameter handler: A handler to call back when the round-trip completes or times out.
@param batchParameters The optional dictionary of parameters to include for this request
- Parameter batchParameters: The optional dictionary of parameters to include for this request
as described in [Graph API Batch Requests]( https://developers.facebook.com/docs/reference/api/batch/ ).
Examples include "depends_on", "name", or "omit_response_on_success".
@ -248,14 +245,9 @@ DEPRECATED_MSG_ATTRIBUTE("Renamed `addRequest:batchEntryName:completionHandler:`
completion or cancellation of the connection. This request can be named
to allow for using the request's response in a subsequent request.
*/
- (void)addRequest:(FBSDKGraphRequest *)request
batchParameters:(NSDictionary<NSString *, id> *)batchParameters
completionHandler:(FBSDKGraphRequestHandler)handler;
- (void)addRequest:(FBSDKGraphRequest *)request
completionHandler:(FBSDKGraphRequestHandler)handler
batchParameters:(NSDictionary *)batchParameters
DEPRECATED_MSG_ATTRIBUTE("Renamed `addRequest:batchParameters:completionHandler:`");
batchParameters:(NSDictionary *)batchParameters;
/**
@methodgroup Instance methods
@ -293,10 +285,12 @@ DEPRECATED_MSG_ATTRIBUTE("Renamed `addRequest:batchParameters:completionHandler:
/**
Determines the operation queue that is used to call methods on the connection's delegate.
@param queue The operation queue to use when calling delegate methods.
- Parameter queue: The operation queue to use when calling delegate methods.
By default, a connection is scheduled on the current thread in the default mode when it is created.
You cannot reschedule a connection after it has started.
This is very similar to `[NSURLConnection setDelegateQueue:]`.
*/
- (void)setDelegateQueue:(NSOperationQueue *)queue;
@ -311,12 +305,9 @@ DEPRECATED_MSG_ATTRIBUTE("Renamed `addRequest:batchParameters:completionHandler:
for applications. If you want to override the version part while using batch requests on the connection, call
this method to set the version for the batch request.
@param version This is a string in the form @"v2.0" which will be used for the version part of an API path
- Parameter version: This is a string in the form @"v2.0" which will be used for the version part of an API path
*/
- (void)overrideGraphAPIVersion:(NSString *)version;
- (void)overrideVersionPartWith:(NSString *)version
DEPRECATED_MSG_ATTRIBUTE("Renamed `overrideGraphAPIVersion`");
- (void)overrideVersionPartWith:(NSString *)version;
@end
@ -329,4 +320,4 @@ DEPRECATED_MSG_ATTRIBUTE("Renamed `overrideGraphAPIVersion`");
will be wrapped into a dictionary using this const as the key. This only applies for very few Graph API
prior to v2.1.
*/
FOUNDATION_EXPORT NSString *const FBSDKNonJSONResponseProperty;
FBSDK_EXTERN NSString *const FBSDKNonJSONResponseProperty;

View File

@ -60,27 +60,6 @@ static NSTimeInterval g_defaultTimeout = 60.0;
static FBSDKErrorConfiguration *g_errorConfiguration;
#if !TARGET_OS_TV
static FBSDKAccessToken *_CreateExpiredAccessToken(FBSDKAccessToken *accessToken)
{
if (accessToken == nil) {
return nil;
}
if (accessToken.isExpired) {
return accessToken;
}
NSDate *expirationDate = [NSDate dateWithTimeIntervalSinceNow:-1];
return [[FBSDKAccessToken alloc] initWithTokenString:accessToken.tokenString
permissions:accessToken.permissions.allObjects
declinedPermissions:accessToken.declinedPermissions.allObjects
appID:accessToken.appID
userID:accessToken.userID
expirationDate:expirationDate
refreshDate:expirationDate
dataAccessExpirationDate:expirationDate];
}
#endif
// ----------------------------------------------------------------------------
// FBSDKGraphRequestConnectionState
@ -154,20 +133,20 @@ NSURLSessionDataDelegate
- (void)addRequest:(FBSDKGraphRequest *)request
completionHandler:(FBSDKGraphRequestHandler)handler
{
[self addRequest:request batchEntryName:nil completionHandler:handler];
[self addRequest:request completionHandler:handler batchEntryName:nil];
}
- (void)addRequest:(FBSDKGraphRequest *)request
batchEntryName:(NSString *)name
completionHandler:(FBSDKGraphRequestHandler)handler
batchEntryName:(NSString *)name
{
NSDictionary *batchParams = (name)? @{kBatchEntryName : name } : nil;
[self addRequest:request batchParameters:batchParams completionHandler:handler];
[self addRequest:request completionHandler:handler batchParameters:batchParams];
}
- (void)addRequest:(FBSDKGraphRequest *)request
batchParameters:(NSDictionary<NSString *, id> *)batchParameters
completionHandler:(FBSDKGraphRequestHandler)handler
batchParameters:(NSDictionary *)batchParameters
{
if (self.state != kStateCreated) {
@throw [NSException exceptionWithName:NSInternalInconsistencyException
@ -181,20 +160,6 @@ NSURLSessionDataDelegate
[self.requests addObject:metadata];
}
- (void)addRequest:(FBSDKGraphRequest *)request
completionHandler:(FBSDKGraphRequestHandler)handler
batchEntryName:(NSString *)name
{
[self addRequest:request batchEntryName:name completionHandler:handler];
}
- (void)addRequest:(FBSDKGraphRequest *)request
completionHandler:(FBSDKGraphRequestHandler)handler
batchParameters:(NSDictionary *)batchParameters
{
[self addRequest:request batchParameters:batchParameters completionHandler:handler];
}
- (void)cancel
{
self.state = kStateCancelled;
@ -202,18 +167,13 @@ NSURLSessionDataDelegate
[self cleanUpSession];
}
- (void)overrideGraphAPIVersion:(NSString *)version
- (void)overrideVersionPartWith:(NSString *)version
{
if (![_overrideVersionPart isEqualToString:version]) {
_overrideVersionPart = [version copy];
}
}
- (void)overrideVersionPartWith:(NSString *)version
{
[self overrideGraphAPIVersion:version];
}
- (void)start
{
static dispatch_once_t onceToken;
@ -303,13 +263,13 @@ NSURLSessionDataDelegate
if ([FBSDKGraphRequest isAttachment:value]) {
NSString *name = [NSString stringWithFormat:@"%@%lu",
kBatchFileNamePrefix,
(unsigned long)attachments.count];
(unsigned long)[attachments count]];
[attachmentNames addObject:name];
attachments[name] = value;
}
}];
if (attachmentNames.count) {
if ([attachmentNames count]) {
requestElement[kBatchAttachmentKey] = [attachmentNames componentsJoinedByString:@","];
}
@ -431,16 +391,16 @@ NSURLSessionDataDelegate
[self _validateFieldsParamForGetRequests:requests];
if (requests.count == 1) {
FBSDKGraphRequestMetadata *metadata = requests[0];
if ([requests count] == 1) {
FBSDKGraphRequestMetadata *metadata = [requests objectAtIndex:0];
NSURL *url = [NSURL URLWithString:[self urlStringForSingleRequest:metadata.request forBatch:NO]];
request = [NSMutableURLRequest requestWithURL:url
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:timeout];
// HTTP methods are case-sensitive; be helpful in case someone provided a mixed case one.
NSString *httpMethod = metadata.request.HTTPMethod.uppercaseString;
request.HTTPMethod = httpMethod;
NSString *httpMethod = [metadata.request.HTTPMethod uppercaseString];
[request setHTTPMethod:httpMethod];
[self appendAttachments:metadata.request.parameters
toBody:body
addFormData:[httpMethod isEqualToString:@"POST"]
@ -476,14 +436,14 @@ NSURLSessionDataDelegate
request = [NSMutableURLRequest requestWithURL:url
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:timeout];
request.HTTPMethod = @"POST";
[request setHTTPMethod:@"POST"];
}
request.HTTPBody = body.data;
NSUInteger bodyLength = body.data.length / 1024;
[request setHTTPBody:[body data]];
NSUInteger bodyLength = [[body data] length] / 1024;
[request setValue:[FBSDKGraphRequestConnection userAgent] forHTTPHeaderField:@"User-Agent"];
[request setValue:[body mimeContentType] forHTTPHeaderField:@"Content-Type"];
[request setValue:[FBSDKGraphRequestBody mimeContentType] forHTTPHeaderField:@"Content-Type"];
[request setHTTPShouldHandleCookies:NO];
[self logRequest:request bodyLength:bodyLength bodyLogger:bodyLogger attachmentLogger:attachmentLogger];
@ -520,23 +480,22 @@ NSURLSessionDataDelegate
NSString *prefix = kGraphURLPrefix;
// We special case a graph post to <id>/videos and send it to graph-video.facebook.com
// We only do this for non batch post requests
NSString *graphPath = request.graphPath.lowercaseString;
if ([request.HTTPMethod.uppercaseString isEqualToString:@"POST"] &&
NSString *graphPath = [request.graphPath lowercaseString];
if ([[request.HTTPMethod uppercaseString] isEqualToString:@"POST"] &&
[graphPath hasSuffix:@"/videos"]) {
graphPath = [graphPath stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@"/"]];
NSArray *components = [graphPath componentsSeparatedByString:@"/"];
if (components.count == 2) {
if ([components count] == 2) {
prefix = kGraphVideoURLPrefix;
}
}
baseURL = [FBSDKInternalUtility facebookURLWithHostPrefix:prefix path:request.graphPath queryParameters:nil defaultVersion:request.version error:NULL].absoluteString;
baseURL = [[FBSDKInternalUtility facebookURLWithHostPrefix:prefix path:request.graphPath queryParameters:nil defaultVersion:request.version error:NULL] absoluteString];
}
NSString *url = [FBSDKGraphRequest serializeURL:baseURL
params:request.parameters
httpMethod:request.HTTPMethod
forBatch:forBatch];
httpMethod:request.HTTPMethod];
return url;
}
@ -563,7 +522,7 @@ NSURLSessionDataDelegate
NSInteger statusCode = _URLResponse.statusCode;
if (!error && [response.MIMEType hasPrefix:@"image"]) {
error = [NSError fbErrorWithCode:FBSDKErrorGraphRequestNonTextMimeTypeReturned
error = [FBSDKError errorWithCode:FBSDKGraphRequestNonTextMimeTypeReturnedErrorCode
message:@"Response is a non-text MIME type; endpoints that return images and other "
@"binary data should be fetched using NSURLRequest and NSURLSession"];
} else {
@ -572,28 +531,28 @@ NSURLSessionDataDelegate
statusCode:statusCode];
}
} else if (!error) {
error = [NSError fbErrorWithCode:FBSDKErrorUnknown
error = [FBSDKError errorWithCode:FBSDKUnknownErrorCode
message:@"Missing NSURLResponse"];
}
if (!error) {
if (self.requests.count != results.count) {
error = [NSError fbErrorWithCode:FBSDKErrorGraphRequestProtocolMismatch
if ([self.requests count] != [results count]) {
error = [FBSDKError errorWithCode:FBSDKGraphRequestProtocolMismatchErrorCode
message:@"Unexpected number of results returned from server."];
} else {
[_logger appendFormat:@"Response <#%lu>\nDuration: %llu msec\nSize: %lu kB\nResponse Body:\n%@\n\n",
(unsigned long)_logger.loggerSerialNumber,
(unsigned long)[_logger loggerSerialNumber],
[FBSDKInternalUtility currentTimeInMilliseconds] - _requestStartTime,
(unsigned long)data.length,
(unsigned long)[data length],
results];
}
}
if (error) {
[_logger appendFormat:@"Response <#%lu> <Error>:\n%@\n%@\n",
(unsigned long)_logger.loggerSerialNumber,
error.localizedDescription,
error.userInfo];
(unsigned long)[_logger loggerSerialNumber],
[error localizedDescription],
[error userInfo]];
}
[_logger emitToNSLog];
@ -626,7 +585,7 @@ NSURLSessionDataDelegate
id response = [self parseJSONOrOtherwise:responseUTF8 error:error];
if (responseUTF8 == nil) {
NSString *base64Data = data.length != 0 ? [data base64EncodedStringWithOptions:0] : @"";
NSString *base64Data = [data length] != 0 ? [data base64EncodedStringWithOptions:0] : @"";
if (base64Data != nil) {
[FBSDKAppEvents logImplicitEvent:@"fb_response_invalid_utf8"
valueToSum:nil
@ -638,13 +597,13 @@ NSURLSessionDataDelegate
NSDictionary *responseError = nil;
if (!response) {
if ((error != NULL) && (*error == nil)) {
*error = [self errorWithCode:FBSDKErrorUnknown
*error = [self errorWithCode:FBSDKUnknownErrorCode
statusCode:statusCode
parsedJSONResponse:nil
innerError:nil
message:@"The server returned an unexpected response."];
}
} else if (self.requests.count == 1) {
} else if ([self.requests count] == 1) {
// response is the entry, so put it in a dictionary under "body" and add
// that to array of responses.
[results addObject:@{
@ -685,7 +644,7 @@ NSURLSessionDataDelegate
[results addObject:result];
}
} else if (error != NULL) {
*error = [self errorWithCode:FBSDKErrorGraphRequestProtocolMismatch
*error = [self errorWithCode:FBSDKGraphRequestProtocolMismatchErrorCode
statusCode:statusCode
parsedJSONResponse:results
innerError:nil
@ -699,7 +658,7 @@ NSURLSessionDataDelegate
error:(NSError **)error
{
id parsed = nil;
if (!(*error) && [utf8 isKindOfClass:[NSString class]]) {
if (!(*error)) {
parsed = [FBSDKInternalUtility objectForJSONString:utf8 error:error];
// if we fail parse we attempt a re-parse of a modified input to support results in the form "foo=bar", "true", etc.
// which is shouldn't be necessary since Graph API v2.1.
@ -722,11 +681,11 @@ NSURLSessionDataDelegate
- (void)completeWithResults:(NSArray *)results
networkError:(NSError *)networkError
{
NSUInteger count = self.requests.count;
NSUInteger count = [self.requests count];
_expectingResults = count;
NSUInteger disabledRecoveryCount = 0;
for (FBSDKGraphRequestMetadata *metadata in self.requests) {
if (metadata.request.graphErrorRecoveryDisabled) {
if ([metadata.request isGraphErrorRecoveryDisabled]) {
disabledRecoveryCount++;
}
}
@ -735,7 +694,7 @@ NSURLSessionDataDelegate
#endif
[self.requests enumerateObjectsUsingBlock:^(FBSDKGraphRequestMetadata *metadata, NSUInteger i, BOOL *stop) {
id result = networkError ? nil : results[i];
id result = networkError ? nil : [results objectAtIndex:i];
NSError *resultError = networkError ?: [self errorFromResult:result request:metadata.request];
id body = nil;
@ -745,10 +704,10 @@ NSURLSessionDataDelegate
}
#if !TARGET_OS_TV
if (resultError && !metadata.request.graphErrorRecoveryDisabled && isSingleRequestToRecover) {
self->_recoveringRequestMetadata = metadata;
self->_errorRecoveryProcessor = [[FBSDKGraphErrorRecoveryProcessor alloc] init];
if ([self->_errorRecoveryProcessor processError:resultError request:metadata.request delegate:self]) {
if (resultError && ![metadata.request isGraphErrorRecoveryDisabled] && isSingleRequestToRecover) {
_recoveringRequestMetadata = metadata;
_errorRecoveryProcessor = [[FBSDKGraphErrorRecoveryProcessor alloc] init];
if ([_errorRecoveryProcessor processError:resultError request:metadata.request delegate:self]) {
return;
}
}
@ -767,30 +726,24 @@ NSURLSessionDataDelegate
- (void)processResultBody:(NSDictionary *)body error:(NSError *)error metadata:(FBSDKGraphRequestMetadata *)metadata canNotifyDelegate:(BOOL)canNotifyDelegate
{
void (^finishAndInvokeCompletionHandler)(void) = ^{
NSDictionary<NSString *, id> *graphDebugDict = body[@"__debug__"];
NSDictionary *graphDebugDict = [body objectForKey:@"__debug__"];
if ([graphDebugDict isKindOfClass:[NSDictionary class]]) {
[self processResultDebugDictionary: graphDebugDict];
}
[metadata invokeCompletionHandlerForConnection:self withResults:body error:error];
if (--self->_expectingResults == 0) {
if (canNotifyDelegate && [self->_delegate respondsToSelector:@selector(requestConnectionDidFinishLoading:)]) {
[self->_delegate requestConnectionDidFinishLoading:self];
if (--_expectingResults == 0) {
if (canNotifyDelegate && [_delegate respondsToSelector:@selector(requestConnectionDidFinishLoading:)]) {
[_delegate requestConnectionDidFinishLoading:self];
}
}
};
#if !TARGET_OS_TV
void (^clearToken)(NSInteger) = ^(NSInteger errorSubcode){
if (metadata.request.flags & FBSDKGraphRequestFlagDoNotInvalidateTokenOnError) {
return;
}
if (errorSubcode == 493) {
[FBSDKAccessToken setCurrentAccessToken:_CreateExpiredAccessToken([FBSDKAccessToken currentAccessToken])];
} else {
void (^clearToken)(void) = ^{
if (!(metadata.request.flags & FBSDKGraphRequestFlagDoNotInvalidateTokenOnError)) {
[FBSDKAccessToken setCurrentAccessToken:nil];
}
};
FBSDKSystemAccountStoreAdapter *adapter = [FBSDKSystemAccountStoreAdapter sharedInstance];
@ -800,8 +753,8 @@ NSURLSessionDataDelegate
BOOL isAccountStoreLogin = [metadataTokenString isEqualToString:accountStoreTokenString];
if ([metadataTokenString isEqualToString:currentTokenString] || isAccountStoreLogin) {
NSInteger errorCode = [error.userInfo[FBSDKGraphRequestErrorGraphErrorCodeKey] integerValue];
NSInteger errorSubcode = [error.userInfo[FBSDKGraphRequestErrorGraphErrorSubcodeKey] integerValue];
NSInteger errorCode = [error.userInfo[FBSDKGraphRequestErrorGraphErrorCode] integerValue];
NSInteger errorSubcode = [error.userInfo[FBSDKGraphRequestErrorGraphErrorSubcode] integerValue];
if (errorCode == 190 || errorCode == 102) {
if (isAccountStoreLogin) {
if (errorSubcode == 460) {
@ -813,20 +766,20 @@ NSURLSessionDataDelegate
adapter.forceBlockingRenew = YES;
} else {
[adapter renewSystemAuthorization:^(ACAccountCredentialRenewResult result, NSError *renewError) {
NSOperationQueue *queue = self->_delegateQueue ?: [NSOperationQueue mainQueue];
NSOperationQueue *queue = _delegateQueue ?: [NSOperationQueue mainQueue];
[queue addOperationWithBlock:^{
clearToken(errorSubcode);
clearToken();
finishAndInvokeCompletionHandler();
}];
}];
return;
}
}
clearToken(errorSubcode);
clearToken();
} else if (errorCode >= 200 && errorCode < 300) {
// permission error
[adapter renewSystemAuthorization:^(ACAccountCredentialRenewResult result, NSError *renewError) {
NSOperationQueue *queue = self->_delegateQueue ?: [NSOperationQueue mainQueue];
NSOperationQueue *queue = _delegateQueue ?: [NSOperationQueue mainQueue];
[queue addOperationWithBlock:finishAndInvokeCompletionHandler];
}];
return;
@ -840,7 +793,7 @@ NSURLSessionDataDelegate
- (void)processResultDebugDictionary:(NSDictionary *)dict
{
NSArray *messages = [FBSDKTypeUtility arrayValue:dict[@"messages"]];
if (!messages.count) {
if (![messages count]) {
return;
}
@ -873,8 +826,8 @@ NSURLSessionDataDelegate
if ([errorDictionary isKindOfClass:[NSDictionary class]]) {
NSMutableDictionary *userInfo = [NSMutableDictionary dictionary];
[FBSDKInternalUtility dictionary:userInfo setObject:errorDictionary[@"code"] forKey:FBSDKGraphRequestErrorGraphErrorCodeKey];
[FBSDKInternalUtility dictionary:userInfo setObject:errorDictionary[@"error_subcode"] forKey:FBSDKGraphRequestErrorGraphErrorSubcodeKey];
[FBSDKInternalUtility dictionary:userInfo setObject:errorDictionary[@"code"] forKey:FBSDKGraphRequestErrorGraphErrorCode];
[FBSDKInternalUtility dictionary:userInfo setObject:errorDictionary[@"error_subcode"] forKey:FBSDKGraphRequestErrorGraphErrorSubcode];
//"message" is preferred over error_msg or error_reason.
[FBSDKInternalUtility dictionary:userInfo setObject:errorDictionary[@"error_msg"] forKey:FBSDKErrorDeveloperMessageKey];
[FBSDKInternalUtility dictionary:userInfo setObject:errorDictionary[@"error_reason"] forKey:FBSDKErrorDeveloperMessageKey];
@ -886,20 +839,20 @@ NSURLSessionDataDelegate
[FBSDKInternalUtility dictionary:userInfo setObject:result forKey:FBSDKGraphRequestErrorParsedJSONResponseKey];
FBSDKErrorRecoveryConfiguration *recoveryConfiguration = [g_errorConfiguration
recoveryConfigurationForCode:[userInfo[FBSDKGraphRequestErrorGraphErrorCodeKey] stringValue]
subcode:[userInfo[FBSDKGraphRequestErrorGraphErrorSubcodeKey] stringValue]
recoveryConfigurationForCode:[userInfo[FBSDKGraphRequestErrorGraphErrorCode] stringValue]
subcode:[userInfo[FBSDKGraphRequestErrorGraphErrorSubcode] stringValue]
request:request];
if ([errorDictionary[@"is_transient"] boolValue]) {
userInfo[FBSDKGraphRequestErrorKey] = @(FBSDKGraphRequestErrorTransient);
userInfo[FBSDKGraphRequestErrorCategoryKey] = @(FBSDKGraphRequestErrorCategoryTransient);
} else {
[FBSDKInternalUtility dictionary:userInfo setObject:@(recoveryConfiguration.errorCategory) forKey:FBSDKGraphRequestErrorKey];
[FBSDKInternalUtility dictionary:userInfo setObject:@(recoveryConfiguration.errorCategory) forKey:FBSDKGraphRequestErrorCategoryKey];
}
[FBSDKInternalUtility dictionary:userInfo setObject:recoveryConfiguration.localizedRecoveryDescription forKey:NSLocalizedRecoverySuggestionErrorKey];
[FBSDKInternalUtility dictionary:userInfo setObject:recoveryConfiguration.localizedRecoveryOptionDescriptions forKey:NSLocalizedRecoveryOptionsErrorKey];
FBSDKErrorRecoveryAttempter *attempter = [FBSDKErrorRecoveryAttempter recoveryAttempterFromConfiguration:recoveryConfiguration];
[FBSDKInternalUtility dictionary:userInfo setObject:attempter forKey:NSRecoveryAttempterErrorKey];
return [NSError fbErrorWithCode:FBSDKErrorGraphRequestGraphAPI
return [FBSDKError errorWithCode:FBSDKGraphRequestGraphAPIErrorCode
userInfo:userInfo
message:nil
underlyingError:nil];
@ -909,7 +862,7 @@ NSURLSessionDataDelegate
return nil;
}
- (NSError *)errorWithCode:(FBSDKError)code
- (NSError *)errorWithCode:(FBSDKErrorCode)code
statusCode:(NSInteger)statusCode
parsedJSONResponse:(id)response
innerError:(NSError *)innerError
@ -946,8 +899,8 @@ NSURLSessionDataDelegate
{
if (_logger.isActive) {
[_logger appendFormat:@"Request <#%lu>:\n", (unsigned long)_logger.loggerSerialNumber];
[_logger appendKey:@"URL" value:request.URL.absoluteString];
[_logger appendKey:@"Method" value:request.HTTPMethod];
[_logger appendKey:@"URL" value:[[request URL] absoluteString]];
[_logger appendKey:@"Method" value:[request HTTPMethod]];
[_logger appendKey:@"UserAgent" value:[request valueForHTTPHeaderField:@"User-Agent"]];
[_logger appendKey:@"MIME" value:[request valueForHTTPHeaderField:@"Content-Type"]];
@ -1048,8 +1001,8 @@ totalBytesExpectedToSend:(int64_t)totalBytesExpectedToSend
FBSDKGraphRequestMetadata *retryMetadata = [[FBSDKGraphRequestMetadata alloc] initWithRequest:retryRequest completionHandler:_recoveringRequestMetadata.completionHandler batchParameters:_recoveringRequestMetadata.batchParameters];
[retryRequest startWithCompletionHandler:^(FBSDKGraphRequestConnection *connection, id result, NSError *retriedError) {
[self processResultBody:result error:retriedError metadata:retryMetadata canNotifyDelegate:YES];
self->_errorRecoveryProcessor = nil;
self->_recoveringRequestMetadata = nil;
_errorRecoveryProcessor = nil;
_recoveringRequestMetadata = nil;
}];
} else {
[self processResultBody:nil error:error metadata:_recoveringRequestMetadata canNotifyDelegate:YES];
@ -1073,7 +1026,7 @@ totalBytesExpectedToSend:(int64_t)totalBytesExpectedToSend
if (comma) {
[result appendString:@",\n"];
}
[result appendString:request.description];
[result appendString:[request description]];
comma = YES;
}
[result appendString:@"\n)>"];

View File

@ -23,14 +23,11 @@
*/
@interface FBSDKGraphRequestDataAttachment : NSObject
- (instancetype)init NS_UNAVAILABLE;
+ (instancetype)new NS_UNAVAILABLE;
/**
Initializes the receiver with the attachment data and metadata.
@param data The attachment data (retained, not copied)
@param filename The filename for the attachment
@param contentType The content type for the attachment
- Parameter data: The attachment data (retained, not copied)
- Parameter filename: The filename for the attachment
- Parameter contentType: The content type for the attachment
*/
- (instancetype)initWithData:(NSData *)data
filename:(NSString *)filename

View File

@ -18,6 +18,8 @@
#import "FBSDKGraphRequestDataAttachment.h"
#import "FBSDKMacros.h"
@implementation FBSDKGraphRequestDataAttachment
- (instancetype)initWithData:(NSData *)data filename:(NSString *)filename contentType:(NSString *)contentType
@ -30,4 +32,10 @@
return self;
}
- (instancetype)init
{
FBSDK_NOT_DESIGNATED_INITIALIZER(initWithData:filename:contentType:);
return [self initWithData:nil filename:nil contentType:nil];
}
@end

View File

@ -17,3 +17,23 @@
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#import <Foundation/Foundation.h>
#ifdef __cplusplus
#define FBSDK_EXTERN extern "C" __attribute__((visibility ("default")))
#else
#define FBSDK_EXTERN extern __attribute__((visibility ("default")))
#endif
#define FBSDK_STATIC_INLINE static inline
#define FBSDK_NO_DESIGNATED_INITIALIZER() \
@throw [NSException exceptionWithName:NSInvalidArgumentException \
reason:[NSString stringWithFormat:@"unrecognized selector sent to instance %p", self] \
userInfo:nil]
#define FBSDK_NOT_DESIGNATED_INITIALIZER(DESIGNATED_INITIALIZER) \
@throw [NSException exceptionWithName:NSInvalidArgumentException \
reason:[NSString stringWithFormat:@"Please use the designated initializer [%p %@]", \
self, \
NSStringFromSelector(@selector(DESIGNATED_INITIALIZER))] \
userInfo:nil]

View File

@ -1,69 +0,0 @@
// 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>
NS_ASSUME_NONNULL_BEGIN
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0
/*! The name of the notification posted by FBSDKMeasurementEvent */
FOUNDATION_EXPORT NSNotificationName const FBSDKMeasurementEventNotification;
#else
/*! The name of the notification posted by FBSDKMeasurementEvent */
FOUNDATION_EXPORT NSString *const FBSDKMeasurementEventNotification;
#endif
FOUNDATION_EXPORT NSString *const FBSDKMeasurementEventNotificationName
DEPRECATED_MSG_ATTRIBUTE("Use `FBSDKMeasurementEventNotification` instead");
/*! Defines keys in the userInfo object for the notification named FBSDKMeasurementEventNotificationName */
/*! The string field for the name of the event */
FOUNDATION_EXPORT NSString *const FBSDKMeasurementEventNameKey;
/*! The dictionary field for the arguments of the event */
FOUNDATION_EXPORT NSString *const FBSDKMeasurementEventArgsKey;
/*! Events raised by FBSDKMeasurementEvent for Applink */
/*!
The name of the event posted when [FBSDKURL URLWithURL:] is called successfully. This represents the successful parsing of an app link URL.
*/
FOUNDATION_EXPORT NSString *const FBSDKAppLinkParseEventName;
/*!
The name of the event posted when [FBSDKURL URLWithInboundURL:] is called successfully.
This represents parsing an inbound app link URL from a different application
*/
FOUNDATION_EXPORT NSString *const FBSDKAppLinkNavigateInEventName;
/*! The event raised when the user navigates from your app to other apps */
FOUNDATION_EXPORT NSString *const FBSDKAppLinkNavigateOutEventName;
/*!
The event raised when the user navigates out from your app and back to the referrer app.
e.g when the user leaves your app after tapping the back-to-referrer navigation bar
*/
FOUNDATION_EXPORT NSString *const FBSDKAppLinkNavigateBackToReferrerEventName;
@interface FBSDKMeasurementEvent : NSObject
@end
NS_ASSUME_NONNULL_END

View File

@ -1,78 +0,0 @@
// 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 "FBSDKMeasurementEvent_Internal.h"
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0
NSNotificationName const FBSDKMeasurementEventNotification = @"com.facebook.facebook-objc-sdk.measurement_event";
#else
NSString *const FBSDKMeasurementEventNotification = @"com.facebook.facebook-objc-sdk.measurement_event";
#endif
NSString *const FBSDKMeasurementEventNotificationName = @"com.facebook.facebook-objc-sdk.measurement_event";
NSString *const FBSDKMeasurementEventNameKey = @"event_name";
NSString *const FBSDKMeasurementEventArgsKey = @"event_args";
/* app Link Event raised by this FBSDKURL */
NSString *const FBSDKAppLinkParseEventName = @"al_link_parse";
NSString *const FBSDKAppLinkNavigateInEventName = @"al_nav_in";
/*! AppLink events raised in this class */
NSString *const FBSDKAppLinkNavigateOutEventName = @"al_nav_out";
NSString *const FBSDKAppLinkNavigateBackToReferrerEventName = @"al_ref_back_out";
@implementation FBSDKMeasurementEvent {
NSString *_name;
NSDictionary<NSString *, id> *_args;
}
- (void)postNotification {
if (!_name) {
NSLog(@"Warning: Missing event name when logging FBSDK measurement event. \n"
" Ignoring this event in logging.");
return;
}
NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
NSDictionary<NSString *, id> *userInfo = @{FBSDKMeasurementEventNameKey : _name,
FBSDKMeasurementEventArgsKey : _args};
[center postNotificationName:FBSDKMeasurementEventNotification
object:self
userInfo:userInfo];
}
- (instancetype)initEventWithName:(NSString *)name
args:(NSDictionary<NSString *, id> *)args {
if ((self = [super init])) {
_name = name;
_args = args ? args : @{};
}
return self;
}
+ (void)postNotificationForEventName:(NSString *)name
args:(NSDictionary<NSString *, id> *)args {
[[[self alloc] initEventWithName:name args:args] postNotification];
}
@end

View File

@ -29,7 +29,7 @@
/**
Implemented by NSObject as a convenience to mutableCopyWithZone:.
@return A mutable copy of the receiver.
- Returns: A mutable copy of the receiver.
*/
- (id)mutableCopy;

View File

@ -14,12 +14,11 @@
// 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."
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#import "FBSDKMacros.h"
#import "FBSDKProfilePictureView.h"
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0
/**
Notification indicating that the `currentProfile` has changed.
@ -27,32 +26,19 @@
`FBSDKProfileChangeOldKey` and
`FBSDKProfileChangeNewKey`.
*/
FOUNDATION_EXPORT NSNotificationName const FBSDKProfileDidChangeNotification;
#else
/**
Notification indicating that the `currentProfile` has changed.
the userInfo dictionary of the notification will contain keys
`FBSDKProfileChangeOldKey` and
`FBSDKProfileChangeNewKey`.
*/
FOUNDATION_EXPORT NSString *const FBSDKProfileDidChangeNotification;
#endif
FBSDK_EXTERN NSString *const FBSDKProfileDidChangeNotification;
/* key in notification's userInfo object for getting the old profile.
If there was no old profile, the key will not be present.
*/
FOUNDATION_EXPORT NSString *const FBSDKProfileChangeOldKey;
FBSDK_EXTERN NSString *const FBSDKProfileChangeOldKey;
/* key in notification's userInfo object for getting the new profile.
If there is no new profile, the key will not be present.
*/
FOUNDATION_EXPORT NSString *const FBSDKProfileChangeNewKey;
FBSDK_EXTERN NSString *const FBSDKProfileChangeNewKey;
/**
Represents an immutable Facebook profile
@ -68,18 +54,15 @@ FOUNDATION_EXPORT NSString *const FBSDKProfileChangeNewKey;
*/
@interface FBSDKProfile : NSObject<NSCopying, NSSecureCoding>
- (instancetype)init NS_UNAVAILABLE;
+ (instancetype)new NS_UNAVAILABLE;
/**
initializes a new instance.
@param userID the user ID
@param firstName the user's first name
@param middleName the user's middle name
@param lastName the user's last name
@param name the user's complete name
@param linkURL the link for this profile
@param refreshDate the optional date this profile was fetched. Defaults to [NSDate date].
- Parameter userID: the user ID
- Parameter firstName: the user's first name
- Parameter middleName: the user's middle name
- Parameter lastName: the user's last name
- Parameter name: the user's complete name
- Parameter linkURL: the link for this profile
- Parameter refreshDate: the optional date this profile was fetched. Defaults to [NSDate date].
*/
- (instancetype)initWithUserID:(NSString *)userID
firstName:(NSString *)firstName
@ -129,7 +112,7 @@ FOUNDATION_EXPORT NSString *const FBSDKProfileChangeNewKey;
/**
Sets the current instance and posts the appropriate notification if the profile parameter is different
than the receiver.
@param profile the profile to set
- Parameter profile: the profile to set
This persists the profile to NSUserDefaults.
*/
@ -137,7 +120,7 @@ FOUNDATION_EXPORT NSString *const FBSDKProfileChangeNewKey;
/**
Indicates if `currentProfile` will automatically observe `FBSDKAccessTokenDidChangeNotification` notifications
@param enable YES is observing
- Parameter enable: YES is observing
If observing, this class will issue a graph request for public profile data when the current token's userID
differs from the current profile. You can observe `FBSDKProfileDidChangeNotification` for when the profile is updated.
@ -149,7 +132,7 @@ FOUNDATION_EXPORT NSString *const FBSDKProfileChangeNewKey;
/**
Loads the current profile and passes it to the completion block.
@param completion The block to be executed once the profile is loaded
- Parameter completion: The block to be executed once the profile is loaded
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.
@ -158,26 +141,26 @@ FOUNDATION_EXPORT NSString *const FBSDKProfileChangeNewKey;
/**
A convenience method for returning a complete `NSURL` for retrieving the user's profile image.
@param mode The picture mode
@param size The height and width. This will be rounded to integer precision.
- Parameter mode: The picture mode
- Parameter size: The height and width. This will be rounded to integer precision.
*/
- (NSURL *)imageURLForPictureMode:(FBSDKProfilePictureMode)mode size:(CGSize)size;
/**
A convenience method for returning a Graph API path for retrieving the user's profile image.
@warning use `imageURLForPictureMode:size:` instead
- Warning:use `imageURLForPictureMode:size:` instead
You can pass this to a `FBSDKGraphRequest` instance to download the image.
@param mode The picture mode
@param size The height and width. This will be rounded to integer precision.
- Parameter mode: The picture mode
- Parameter size: The height and width. This will be rounded to integer precision.
*/
- (NSString *)imagePathForPictureMode:(FBSDKProfilePictureMode)mode size:(CGSize)size
DEPRECATED_MSG_ATTRIBUTE("use imageURLForPictureMode:size: instead");
__attribute__ ((deprecated("use imageURLForPictureMode:size: instead")));
/**
Returns YES if the profile is equivalent to the receiver.
@param profile the profile to compare to.
- Parameter profile: the profile to compare to.
*/
- (BOOL)isEqualToProfile:(FBSDKProfile *)profile;
@end

View File

@ -20,16 +20,7 @@
#import "FBSDKCoreKit+Internal.h"
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0
NSNotificationName const FBSDKProfileDidChangeNotification = @"com.facebook.sdk.FBSDKProfile.FBSDKProfileDidChangeNotification";;
#else
NSString *const FBSDKProfileDidChangeNotification = @"com.facebook.sdk.FBSDKProfile.FBSDKProfileDidChangeNotification";;
#endif
NSString *const FBSDKProfileChangeOldKey = @"FBSDKProfileOld";
NSString *const FBSDKProfileChangeNewKey = @"FBSDKProfileNew";
static NSString *const FBSDKProfileUserDefaultsKey = @"com.facebook.sdk.FBSDKProfile.currentProfile";
@ -48,6 +39,11 @@ static FBSDKProfile *g_currentProfile;
@implementation FBSDKProfile
- (instancetype)init NS_UNAVAILABLE
{
assert(0);
}
- (instancetype)initWithUserID:(NSString *)userID
firstName:(NSString *)firstName
middleName:(NSString *)middleName
@ -144,13 +140,13 @@ static FBSDKProfile *g_currentProfile;
- (NSUInteger)hash
{
NSUInteger subhashes[] = {
self.userID.hash,
self.firstName.hash,
self.middleName.hash,
self.lastName.hash,
self.name.hash,
self.linkURL.hash,
self.refreshDate.hash
[self.userID hash],
[self.firstName hash],
[self.middleName hash],
[self.lastName hash],
[self.name hash],
[self.linkURL hash],
[self.refreshDate hash]
};
return [FBSDKMath hashWithIntegerArray:subhashes count:sizeof(subhashes) / sizeof(subhashes[0])];
}
@ -183,7 +179,7 @@ static FBSDKProfile *g_currentProfile;
return YES;
}
- (instancetype)initWithCoder:(NSCoder *)decoder
- (id)initWithCoder:(NSCoder *)decoder
{
NSString *userID = [decoder decodeObjectOfClass:[NSString class] forKey:FBSDKPROFILE_USERID_KEY];
NSString *firstName = [decoder decodeObjectOfClass:[NSString class] forKey:FBSDKPROFILE_FIRSTNAME_KEY];

View File

@ -22,6 +22,7 @@
#import "FBSDKInternalUtility.h"
#import "FBSDKMaleSilhouetteIcon.h"
#import "FBSDKMath.h"
#import "FBSDKURLConnection.h"
#import "FBSDKUtility.h"
@interface FBSDKProfilePictureViewState : NSObject
@ -69,7 +70,7 @@
(NSUInteger)_size.height,
(NSUInteger)_scale,
(NSUInteger)_pictureMode,
_profileID.hash,
[_profileID hash],
};
return [FBSDKMath hashWithIntegerArray:subhashes count:sizeof(subhashes) / sizeof(subhashes[0])];
}
@ -119,7 +120,7 @@
return self;
}
- (instancetype)initWithCoder:(NSCoder *)decoder
- (id)initWithCoder:(NSCoder *)decoder
{
if ((self = [super initWithCoder:decoder])) {
[self _configureProfilePictureView];
@ -138,7 +139,7 @@
{
CGRect currentBounds = self.bounds;
if (!CGRectEqualToRect(currentBounds, bounds)) {
super.bounds = bounds;
[super setBounds:bounds];
if (!CGSizeEqualToSize(currentBounds.size, bounds.size)) {
_placeholderImageIsValid = NO;
[self setNeedsImageUpdate];
@ -155,7 +156,7 @@
{
if (_imageView.contentMode != contentMode) {
_imageView.contentMode = contentMode;
super.contentMode = contentMode;
[super setContentMode:contentMode];
[self setNeedsImageUpdate];
}
}
@ -211,16 +212,16 @@
if (!imageURL) {
return;
}
FBSDKURLConnectionHandler completionHandler = ^(FBSDKURLConnection *connection,
NSError *error,
NSURLResponse *response,
NSData *responseData) {
if (!error && [responseData length]) {
completionBlock(responseData);
}
};
NSURLRequest *request = [[NSURLRequest alloc] initWithURL:imageURL];
NSURLSession *session = [NSURLSession sharedSession];
[[session
dataTaskWithRequest:request
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
if (!error && data.length) {
completionBlock(data);
}
}] resume];
[[[FBSDKURLConnection alloc] initWithRequest:request completionHandler:completionHandler] start];
}
+ (NSURL *)_imageURLWithState:(FBSDKProfilePictureViewState *)state
@ -240,7 +241,7 @@
- (void)_accessTokenDidChangeNotification:(NSNotification *)notification
{
if (![_profileID isEqualToString:@"me"] || !notification.userInfo[FBSDKAccessTokenDidChangeUserIDKey]) {
if (![_profileID isEqualToString:@"me"] || !notification.userInfo[FBSDKAccessTokenDidChangeUserID]) {
return;
}
_lastState = nil;
@ -327,7 +328,7 @@
// leave the current value until the new resolution image is downloaded
BOOL imageShouldFit = [self _imageShouldFit];
UIScreen *screen = self.window.screen ?: [UIScreen mainScreen];
CGFloat scale = screen.scale;
CGFloat scale = [screen scale];
CGSize imageSize = [self _imageSize:imageShouldFit scale:scale];
FBSDKProfilePictureViewState *state = [[FBSDKProfilePictureViewState alloc] initWithProfileID:_profileID
size:imageSize

View File

@ -18,47 +18,46 @@
#import <UIKit/UIKit.h>
#import <FBSDKCoreKit/FBSDKMacros.h>
/*
* Constants defining logging behavior. Use with <[FBSDKSettings setLoggingBehavior]>.
*/
/** Include access token in logging. */
FOUNDATION_EXPORT NSString *const FBSDKLoggingBehaviorAccessTokens;
FBSDK_EXTERN NSString *const FBSDKLoggingBehaviorAccessTokens;
/** Log performance characteristics */
FOUNDATION_EXPORT NSString *const FBSDKLoggingBehaviorPerformanceCharacteristics;
FBSDK_EXTERN NSString *const FBSDKLoggingBehaviorPerformanceCharacteristics;
/** Log FBSDKAppEvents interactions */
FOUNDATION_EXPORT NSString *const FBSDKLoggingBehaviorAppEvents;
FBSDK_EXTERN NSString *const FBSDKLoggingBehaviorAppEvents;
/** Log Informational occurrences */
FOUNDATION_EXPORT NSString *const FBSDKLoggingBehaviorInformational;
FBSDK_EXTERN NSString *const FBSDKLoggingBehaviorInformational;
/** Log cache errors. */
FOUNDATION_EXPORT NSString *const FBSDKLoggingBehaviorCacheErrors;
FBSDK_EXTERN NSString *const FBSDKLoggingBehaviorCacheErrors;
/** Log errors from SDK UI controls */
FOUNDATION_EXPORT NSString *const FBSDKLoggingBehaviorUIControlErrors;
FBSDK_EXTERN NSString *const FBSDKLoggingBehaviorUIControlErrors;
/** Log debug warnings from API response, i.e. when friends fields requested, but user_friends permission isn't granted. */
FOUNDATION_EXPORT NSString *const FBSDKLoggingBehaviorGraphAPIDebugWarning;
FBSDK_EXTERN NSString *const FBSDKLoggingBehaviorGraphAPIDebugWarning;
/** Log warnings from API response, i.e. when requested feature will be deprecated in next version of API.
Info is the lowest level of severity, using it will result in logging all previously mentioned levels.
*/
FOUNDATION_EXPORT NSString *const FBSDKLoggingBehaviorGraphAPIDebugInfo;
FBSDK_EXTERN NSString *const FBSDKLoggingBehaviorGraphAPIDebugInfo;
/** Log errors from SDK network requests */
FOUNDATION_EXPORT NSString *const FBSDKLoggingBehaviorNetworkRequests;
FBSDK_EXTERN NSString *const FBSDKLoggingBehaviorNetworkRequests;
/** Log errors likely to be preventable by the developer. This is in the default set of enabled logging behaviors. */
FOUNDATION_EXPORT NSString *const FBSDKLoggingBehaviorDeveloperErrors;
FBSDK_EXTERN NSString *const FBSDKLoggingBehaviorDeveloperErrors;
@interface FBSDKSettings : NSObject
- (instancetype)init NS_UNAVAILABLE;
+ (instancetype)new NS_UNAVAILABLE;
/**
Get the Facebook App ID used by the SDK.
@ -68,7 +67,7 @@ FOUNDATION_EXPORT NSString *const FBSDKLoggingBehaviorDeveloperErrors;
/**
Set the Facebook App ID to be used by the SDK.
@param appID The Facebook App ID to be used by the SDK.
- Parameter appID: The Facebook App ID to be used by the SDK.
*/
+ (void)setAppID:(NSString *)appID;
@ -81,7 +80,7 @@ FOUNDATION_EXPORT NSString *const FBSDKLoggingBehaviorDeveloperErrors;
/**
Set the app url scheme suffix used by the SDK.
@param appURLSchemeSuffix The url scheme suffix to be used by the SDK.
- Parameter appURLSchemeSuffix: The url scheme suffix to be used by the SDK.
*/
+ (void)setAppURLSchemeSuffix:(NSString *)appURLSchemeSuffix;
@ -96,14 +95,14 @@ FOUNDATION_EXPORT NSString *const FBSDKLoggingBehaviorDeveloperErrors;
Sets the Client Token for the Facebook App.
This is needed for certain API calls when made anonymously, without a user-based access token.
@param clientToken The Facebook App's "client token", which, for a given appid can be found in the Security
- Parameter clientToken: The Facebook App's "client token", which, for a given appid can be found in the Security
section of the Advanced tab of the Facebook App settings found at <https://developers.facebook.com/apps/[your-app-id]>
*/
+ (void)setClientToken:(NSString *)clientToken;
/**
A convenient way to toggle error recovery for all FBSDKGraphRequest instances created after this is set.
@param disableGraphErrorRecovery YES or NO.
- Parameter disableGraphErrorRecovery: YES or NO.
*/
+ (void)setGraphErrorRecoveryDisabled:(BOOL)disableGraphErrorRecovery;
@ -119,7 +118,7 @@ FOUNDATION_EXPORT NSString *const FBSDKLoggingBehaviorDeveloperErrors;
This should match the Display Name that has been set for the app with the corresponding Facebook App ID,
in the Facebook App Dashboard.
@param displayName The Facebook Display Name to be used by the SDK.
- Parameter displayName: The Facebook Display Name to be used by the SDK.
*/
+ (void)setDisplayName:(NSString *)displayName;
@ -135,7 +134,7 @@ FOUNDATION_EXPORT NSString *const FBSDKLoggingBehaviorDeveloperErrors;
This can be used to change the Facebook domain (e.g. @"beta") so that requests will be sent to
graph.beta.facebook.com
@param facebookDomainPart The domain part to be inserted into facebook.com.
- Parameter facebookDomainPart: The domain part to be inserted into facebook.com.
*/
+ (void)setFacebookDomainPart:(NSString *)facebookDomainPart;
@ -144,14 +143,14 @@ FOUNDATION_EXPORT NSString *const FBSDKLoggingBehaviorDeveloperErrors;
If not explicitly set, the default is 0.9.
@see [UIImageJPEGRepresentation](https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIKitFunctionReference/#//apple_ref/c/func/UIImageJPEGRepresentation) */
- See:[UIImageJPEGRepresentation](https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIKitFunctionReference/#//apple_ref/c/func/UIImageJPEGRepresentation) */
+ (CGFloat)JPEGCompressionQuality;
/**
Set the quality of JPEG images sent to Facebook from the SDK.
@param JPEGCompressionQuality The quality for JPEG images, expressed as a value from 0.0 to 1.0.
- Parameter JPEGCompressionQuality: The quality for JPEG images, expressed as a value from 0.0 to 1.0.
@see [UIImageJPEGRepresentation](https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIKitFunctionReference/#//apple_ref/c/func/UIImageJPEGRepresentation) */
- See:[UIImageJPEGRepresentation](https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIKitFunctionReference/#//apple_ref/c/func/UIImageJPEGRepresentation) */
+ (void)setJPEGCompressionQuality:(CGFloat)JPEGCompressionQuality;
/**
@ -162,34 +161,10 @@ FOUNDATION_EXPORT NSString *const FBSDKLoggingBehaviorDeveloperErrors;
/**
Set the flag which controls the auto logging of basic app events, such as activateApp and deactivateApp.
@param AutoLogAppEventsEnabled Flag value, expressed as a value from 0 - false or 1 - true.
- Parameter AutoLogAppEventsEnabled: Flag value, expressed as a value from 0 - false or 1 - true.
*/
+ (void)setAutoLogAppEventsEnabled:(NSNumber *)AutoLogAppEventsEnabled;
/**
Flag which controls the fb_codeless_debug logging event
If not explicitly set, the default is 1 - true
*/
+ (NSNumber *)codelessDebugLogEnabled;
/**
Set the flag which controls the fb_codeless_debug logging event
@param CodelessDebugLogEnabled Flag value, expressed as a value from 0 - false or 1 - true.
*/
+ (void)setCodelessDebugLogEnabled:(NSNumber *)CodelessDebugLogEnabled;
/**
Flag which controls whether advertiserID could be collected.
If not explicitly set, the default is 1 - true
*/
+ (NSNumber *)advertiserIDCollectionEnabled;
/**
Set the flag which controls ontrols whether advertiserID could be collected.
@param AdvertiserIDCollectionEnabled Flag value, expressed as a value from 0 - false or 1 - true.
*/
+ (void)setAdvertiserIDCollectionEnabled:(NSNumber *)AdvertiserIDCollectionEnabled;
/**
Gets whether data such as that generated through FBSDKAppEvents and sent to Facebook should be restricted from being used for other than analytics and conversions. Defaults to NO. This value is stored on the device and persists across app launches.
*/
@ -198,7 +173,7 @@ FOUNDATION_EXPORT NSString *const FBSDKLoggingBehaviorDeveloperErrors;
/**
Sets whether data such as that generated through FBSDKAppEvents and sent to Facebook should be restricted from being used for other than analytics and conversions. Defaults to NO. This value is stored on the device and persists across app launches.
@param limitEventAndDataUsage The desired value.
- Parameter limitEventAndDataUsage: The desired value.
*/
+ (void)setLimitEventAndDataUsage:(BOOL)limitEventAndDataUsage;
@ -216,7 +191,7 @@ FOUNDATION_EXPORT NSString *const FBSDKLoggingBehaviorDeveloperErrors;
Set the current Facebook SDK logging behavior. This should consist of strings defined as
constants with FBSDKLoggingBehavior*.
@param loggingBehavior A set of strings indicating what information should be logged. If nil is provided, the logging
- Parameter loggingBehavior: A set of strings indicating what information should be logged. If nil is provided, the logging
behavior is reset to the default set of enabled behaviors. Set to an empty set in order to disable all logging.
@ -227,21 +202,21 @@ FOUNDATION_EXPORT NSString *const FBSDKLoggingBehaviorDeveloperErrors;
/**
Enable a particular Facebook SDK logging behavior.
@param loggingBehavior The LoggingBehavior to enable. This should be a string defined as a constant with FBSDKLoggingBehavior*.
- Parameter loggingBehavior: The LoggingBehavior to enable. This should be a string defined as a constant with FBSDKLoggingBehavior*.
*/
+ (void)enableLoggingBehavior:(NSString *)loggingBehavior;
/**
Disable a particular Facebook SDK logging behavior.
@param loggingBehavior The LoggingBehavior to disable. This should be a string defined as a constant with FBSDKLoggingBehavior*.
- Parameter loggingBehavior: The LoggingBehavior to disable. This should be a string defined as a constant with FBSDKLoggingBehavior*.
*/
+ (void)disableLoggingBehavior:(NSString *)loggingBehavior;
/**
Set the user defaults key used by legacy token caches.
@param tokenInformationKeyName the key used by legacy token caches.
- Parameter tokenInformationKeyName: the key used by legacy token caches.
Use this only if you customized FBSessionTokenCachingStrategy in v3.x of

View File

@ -19,7 +19,6 @@
#import "FBSDKSettings+Internal.h"
#import "FBSDKAccessTokenCache.h"
#import "FBSDKAccessTokenExpirer.h"
#import "FBSDKCoreKit.h"
#define FBSDKSETTINGS_PLIST_CONFIGURATION_SETTING_IMPL(TYPE, PLIST_KEY, GETTER, SETTER, DEFAULT_VALUE) \
@ -53,7 +52,6 @@ static NSString *const FBSDKSettingsLimitEventAndDataUsage = @"com.facebook.sdk:
static BOOL g_disableErrorRecovery;
static NSString *g_userAgentSuffix;
static NSString *g_defaultGraphAPIVersion;
static FBSDKAccessTokenExpirer *g_accessTokenExpirer;
@implementation FBSDKSettings
@ -61,7 +59,6 @@ static FBSDKAccessTokenExpirer *g_accessTokenExpirer;
{
if (self == [FBSDKSettings class]) {
g_tokenCache = [[FBSDKAccessTokenCache alloc] init];
g_accessTokenExpirer = [[FBSDKAccessTokenExpirer alloc] init];
}
}
@ -75,10 +72,6 @@ FBSDKSETTINGS_PLIST_CONFIGURATION_SETTING_IMPL(NSString, FacebookDomainPart, fac
FBSDKSETTINGS_PLIST_CONFIGURATION_SETTING_IMPL(NSNumber, FacebookJpegCompressionQuality, _JPEGCompressionQualityNumber, _setJPEGCompressionQualityNumber, @0.9);
FBSDKSETTINGS_PLIST_CONFIGURATION_SETTING_IMPL(NSNumber, FacebookAutoLogAppEventsEnabled, autoLogAppEventsEnabled,
setAutoLogAppEventsEnabled, @1);
FBSDKSETTINGS_PLIST_CONFIGURATION_SETTING_IMPL(NSNumber, FacebookCodelessDebugLogEnabled, codelessDebugLogEnabled,
setCodelessDebugLogEnabled, @0);
FBSDKSETTINGS_PLIST_CONFIGURATION_SETTING_IMPL(NSNumber, FacebookAdvertiserIDCollectionEnabled, advertiserIDCollectionEnabled,
setAdvertiserIDCollectionEnabled, @1);
+ (void)setGraphErrorRecoveryDisabled:(BOOL)disableGraphErrorRecovery {
g_disableErrorRecovery = disableGraphErrorRecovery;
@ -90,7 +83,7 @@ FBSDKSETTINGS_PLIST_CONFIGURATION_SETTING_IMPL(NSNumber, FacebookAdvertiserIDCol
+ (CGFloat)JPEGCompressionQuality
{
return [self _JPEGCompressionQualityNumber].floatValue;
return [[self _JPEGCompressionQualityNumber] floatValue];
}
+ (void)setJPEGCompressionQuality:(CGFloat)JPEGCompressionQuality
@ -175,6 +168,14 @@ FBSDKSETTINGS_PLIST_CONFIGURATION_SETTING_IMPL(NSNumber, FacebookAdvertiserIDCol
return FBSDK_VERSION_STRING;
}
#pragma mark - Object Lifecycle
- (instancetype)init
{
FBSDK_NO_DESIGNATED_INITIALIZER();
return nil;
}
#pragma mark - Internal
+ (NSObject<FBSDKAccessTokenCaching> *)accessTokenCache

View File

@ -48,25 +48,22 @@ typedef void (^FBSDKTestUsersManagerRemoveTestAccountHandler)(NSError *error) ;
*/
@interface FBSDKTestUsersManager : NSObject
- (instancetype)init NS_UNAVAILABLE;
+ (instancetype)new NS_UNAVAILABLE;
/**
construct or return the shared instance
@param appID the Facebook app id
@param appSecret the Facebook app secret
- Parameter appID: the Facebook app id
- Parameter appSecret: the Facebook app secret
*/
+ (instancetype)sharedInstanceForAppID:(NSString *)appID appSecret:(NSString *)appSecret;
/**
retrieve FBSDKAccessToken instances for test accounts with the specific permissions.
@param arraysOfPermissions an array of permissions sets, such as @[ [NSSet setWithObject:@"email"], [NSSet setWithObject:@"user_birthday"]]
- Parameter arraysOfPermissions: an array of permissions sets, such as @[ [NSSet setWithObject:@"email"], [NSSet setWithObject:@"user_birthday"]]
if you needed two test accounts with email and birthday permissions, respectively. You can pass in empty nested sets
if you need two arbitrary test accounts. For convenience, passing nil is treated as @[ [NSSet set] ]
for fetching a single test user.
@param createIfNotFound if YES, new test accounts are created if no test accounts existed that fit the permissions
- Parameter createIfNotFound: if YES, new test accounts are created if no test accounts existed that fit the permissions
requirement
@param handler the callback to invoke which will return an array of `FBAccessTokenData` instances or an `NSError`.
- Parameter handler: the callback to invoke which will return an array of `FBAccessTokenData` instances or an `NSError`.
If param `createIfNotFound` is NO, the array may contain `[NSNull null]` instances.
@ -80,24 +77,24 @@ typedef void (^FBSDKTestUsersManagerRemoveTestAccountHandler)(NSError *error) ;
/**
add a test account with the specified permissions
@param permissions the set of permissions, e.g., [NSSet setWithObjects:@"email", @"user_friends"]
@param handler the callback handler
- Parameter permissions: the set of permissions, e.g., [NSSet setWithObjects:@"email", @"user_friends"]
- Parameter handler: the callback handler
*/
- (void)addTestAccountWithPermissions:(NSSet *)permissions
completionHandler:(FBSDKTestUsersManagerRetrieveTestAccountTokensHandler)handler;
/**
remove a test account for the given user id
@param userId the user id
@param handler the callback handler
- Parameter userId: the user id
- Parameter handler: the callback handler
*/
- (void)removeTestAccount:(NSString *)userId completionHandler:(FBSDKTestUsersManagerRemoveTestAccountHandler)handler;
/**
Make two test users friends with each other.
@param first the token of the first user
@param second the token of the second user
@param callback the callback handler
- Parameter first: the token of the first user
- Parameter second: the token of the second user
- Parameter callback: the callback handler
*/
- (void)makeFriendsWithFirst:(FBSDKAccessToken *)first second:(FBSDKAccessToken *)second callback:(void (^)(NSError *))callback;

View File

@ -48,6 +48,12 @@ static NSMutableDictionary *gInstancesDictionary;
return self;
}
- (instancetype)init
{
FBSDK_NOT_DESIGNATED_INITIALIZER(initWithAppID:appSecret:);
return [self initWithAppID:nil appSecret:nil];
}
+ (instancetype)sharedInstanceForAppID:(NSString *)appID appSecret:(NSString *)appSecret {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
@ -126,7 +132,7 @@ static NSMutableDictionary *gInstancesDictionary;
completionHandler:(FBSDKTestUsersManagerRetrieveTestAccountTokensHandler)handler {
NSDictionary *params = @{
@"installed" : @"true",
@"permissions" : [permissions.allObjects componentsJoinedByString:@","],
@"permissions" : [[permissions allObjects] componentsJoinedByString:@","],
@"access_token" : self.appAccessToken
};
FBSDKGraphRequest *request = [[FBSDKGraphRequest alloc] initWithGraphPath:[NSString stringWithFormat:kFBGraphAPITestUsersPathFormat, _appID]
@ -143,7 +149,7 @@ static NSMutableDictionary *gInstancesDictionary;
NSMutableDictionary *accountData = [NSMutableDictionary dictionaryWithCapacity:2];
accountData[kAccountsDictionaryPermissionsKey] = [NSSet setWithSet:permissions];
accountData[kAccountsDictionaryTokenKey] = result[@"access_token"];
self->_accounts[result[@"id"]] = accountData;
_accounts[result[@"id"]] = accountData;
if (handler) {
FBSDKAccessToken *token = [self tokenDataForTokenString:accountData[kAccountsDictionaryTokenKey]
@ -160,8 +166,8 @@ static NSMutableDictionary *gInstancesDictionary;
__block int expectedCount = 2;
void (^complete)(NSError *) = ^(NSError *error) {
// ignore if they're already friends or pending request
if ([error.userInfo[FBSDKGraphRequestErrorGraphErrorCodeKey] integerValue] == 522 ||
[error.userInfo[FBSDKGraphRequestErrorGraphErrorCodeKey] integerValue] == 520) {
if ([error.userInfo[FBSDKGraphRequestErrorGraphErrorCode] integerValue] == 522 ||
[error.userInfo[FBSDKGraphRequestErrorGraphErrorCode] integerValue] == 520) {
error = nil;
}
if (--expectedCount == 0 || error) {
@ -179,16 +185,12 @@ static NSMutableDictionary *gInstancesDictionary;
version:nil
HTTPMethod:@"POST"];
FBSDKGraphRequestConnection *conn = [[FBSDKGraphRequestConnection alloc] init];
[conn addRequest:one
batchEntryName:@"first"
completionHandler:^(FBSDKGraphRequestConnection *connection, id result, NSError *error) {
[conn addRequest:one completionHandler:^(FBSDKGraphRequestConnection *connection, id result, NSError *error) {
complete(error);
}];
[conn addRequest:two
batchParameters:@{ @"depends_on" : @"first"}
completionHandler:^(FBSDKGraphRequestConnection *connection, id result, NSError *error) {
} batchEntryName:@"first"];
[conn addRequest:two completionHandler:^(FBSDKGraphRequestConnection *connection, id result, NSError *error) {
complete(error);
}];
} batchParameters:@{ @"depends_on" : @"first"} ];
[conn start];
}
@ -209,13 +211,12 @@ static NSMutableDictionary *gInstancesDictionary;
#pragma mark - private methods
- (FBSDKAccessToken *)tokenDataForTokenString:(NSString *)tokenString permissions:(NSSet *)permissions userId:(NSString *)userId{
return [[FBSDKAccessToken alloc] initWithTokenString:tokenString
permissions:permissions.allObjects
permissions:[permissions allObjects]
declinedPermissions:nil
appID:_appID
userID:userId
expirationDate:nil
refreshDate:nil
dataAccessExpirationDate:nil];
refreshDate:nil];
}
- (NSArray *)userIdAndTokenOfExistingAccountWithPermissions:(NSSet *)permissions skip:(NSSet *)setToSkip {
@ -263,15 +264,15 @@ static NSMutableDictionary *gInstancesDictionary;
handler(error);
}
// on errors, clear out accounts since it may be in a bad state
[self->_accounts removeAllObjects];
[_accounts removeAllObjects];
return;
} else {
for (NSDictionary *account in result[@"data"]) {
NSString *userId = account[@"id"];
NSString *token = account[@"access_token"];
if (userId && token) {
self->_accounts[userId] = [NSMutableDictionary dictionaryWithCapacity:2];
self->_accounts[userId][kAccountsDictionaryTokenKey] = token;
_accounts[userId] = [NSMutableDictionary dictionaryWithCapacity:2];
_accounts[userId][kAccountsDictionaryTokenKey] = token;
expectedTestAccounts++;
[permissionConnection addRequest:[[FBSDKGraphRequest alloc] initWithGraphPath:[NSString stringWithFormat:@"%@?fields=permissions", userId]
parameters:nil
@ -279,7 +280,7 @@ static NSMutableDictionary *gInstancesDictionary;
version:nil
HTTPMethod:nil]
completionHandler:^(FBSDKGraphRequestConnection *innerConnection2, id innerResult, NSError *innerError) {
if (self->_accounts.count == 0) {
if (_accounts.count == 0) {
// indicates an earlier error that was already passed to handler, so just short circuit.
return;
}
@ -287,7 +288,7 @@ static NSMutableDictionary *gInstancesDictionary;
if (handler) {
handler(innerError);
}
[self->_accounts removeAllObjects];
[_accounts removeAllObjects];
return;
} else {
NSMutableSet *grantedPermissions = [NSMutableSet set];
@ -297,7 +298,7 @@ static NSMutableDictionary *gInstancesDictionary;
[grantedPermissions addObject:obj[@"permission"]];
}
}];
self->_accounts[userId][kAccountsDictionaryPermissionsKey] = grantedPermissions;
_accounts[userId][kAccountsDictionaryPermissionsKey] = grantedPermissions;
}
expectedTestAccounts--;
if (!expectedTestAccounts) {

View File

@ -1,87 +0,0 @@
// 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>
NS_ASSUME_NONNULL_BEGIN
@class FBSDKAppLink;
/*!
Provides a set of utilities for working with NSURLs, such as parsing of query parameters
and handling for App Link requests.
*/
@interface FBSDKURL : NSObject
/*!
Creates a link target from a raw URL.
On success, this posts the FBSDKAppLinkParseEventName measurement event. If you are constructing the FBSDKURL within your application delegate's
application:openURL:sourceApplication:annotation:, you should instead use URLWithInboundURL:sourceApplication:
to support better FBSDKMeasurementEvent notifications
@param url The instance of `NSURL` to create FBSDKURL from.
*/
+ (FBSDKURL *)URLWithURL:(NSURL *)url;
/*!
Creates a link target from a raw URL received from an external application. This is typically called from the app delegate's
application:openURL:sourceApplication:annotation: and will post the FBSDKAppLinkNavigateInEventName measurement event.
@param url The instance of `NSURL` to create FBSDKURL from.
@param sourceApplication the bundle ID of the app that is requesting your app to open the URL. The same sourceApplication in application:openURL:sourceApplication:annotation:
*/
+ (FBSDKURL *)URLWithInboundURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication;
/*!
Gets the target URL. If the link is an App Link, this is the target of the App Link.
Otherwise, it is the url that created the target.
*/
@property (nonatomic, strong, readonly) NSURL *targetURL;
/*!
Gets the query parameters for the target, parsed into an NSDictionary.
*/
@property (nonatomic, strong, readonly) NSDictionary<NSString *, id> *targetQueryParameters;
/*!
If this link target is an App Link, this is the data found in al_applink_data.
Otherwise, it is nil.
*/
@property (nonatomic, strong, readonly) NSDictionary<NSString *, id> *appLinkData;
/*!
If this link target is an App Link, this is the data found in extras.
*/
@property (nonatomic, strong, readonly) NSDictionary<NSString *, id> *appLinkExtras;
/*!
The App Link indicating how to navigate back to the referer app, if any.
*/
@property (nonatomic, strong, readonly) FBSDKAppLink *appLinkReferer;
/*!
The URL that was used to create this FBSDKURL.
*/
@property (nonatomic, strong, readonly) NSURL *inputURL;
/*!
The query parameters of the inputURL, parsed into an NSDictionary.
*/
@property (nonatomic, strong, readonly) NSDictionary<NSString *, id> *inputQueryParameters;
@end
NS_ASSUME_NONNULL_END

View File

@ -1,152 +0,0 @@
// 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 "FBSDKURL_Internal.h"
#import "FBSDKAppLinkTarget.h"
#import "FBSDKAppLink_Internal.h"
#import "FBSDKMeasurementEvent_Internal.h"
@implementation FBSDKURL
- (instancetype)initWithURL:(NSURL *)url forOpenInboundURL:(BOOL)forOpenURLEvent sourceApplication:(NSString *)sourceApplication forRenderBackToReferrerBar:(BOOL)forRenderBackToReferrerBar {
self = [super init];
if (!self) return nil;
_inputURL = url;
_targetURL = url;
// Parse the query string parameters for the base URL
NSDictionary<NSString *, id> *baseQuery = [FBSDKURL queryParametersForURL:url];
_inputQueryParameters = baseQuery;
_targetQueryParameters = baseQuery;
// Check for applink_data
NSString *appLinkDataString = baseQuery[FBSDKAppLinkDataParameterName];
if (appLinkDataString) {
// Try to parse the JSON
NSError *error = nil;
NSDictionary<NSString *, id> *applinkData =
[NSJSONSerialization JSONObjectWithData:[appLinkDataString dataUsingEncoding:NSUTF8StringEncoding]
options:0
error:&error];
if (!error && [applinkData isKindOfClass:[NSDictionary class]]) {
// If the version is not specified, assume it is 1.
NSString *version = applinkData[FBSDKAppLinkVersionKeyName] ?: @"1.0";
NSString *target = applinkData[FBSDKAppLinkTargetKeyName];
if ([version isKindOfClass:[NSString class]] &&
[version isEqual:FBSDKAppLinkVersion]) {
// There's applink data! The target should actually be the applink target.
_appLinkData = applinkData;
id applinkExtras = applinkData[FBSDKAppLinkExtrasKeyName];
if (applinkExtras && [applinkExtras isKindOfClass:[NSDictionary class]]) {
_appLinkExtras = applinkExtras;
}
_targetURL = ([target isKindOfClass:[NSString class]] ? [NSURL URLWithString:target] : url);
_targetQueryParameters = [FBSDKURL queryParametersForURL:_targetURL];
NSDictionary<NSString *, id> *refererAppLink = _appLinkData[FBSDKAppLinkRefererAppLink];
NSString *refererURLString = refererAppLink[FBSDKAppLinkRefererUrl];
NSString *refererAppName = refererAppLink[FBSDKAppLinkRefererAppName];
if (refererURLString && refererAppName) {
FBSDKAppLinkTarget *appLinkTarget = [FBSDKAppLinkTarget appLinkTargetWithURL:[NSURL URLWithString:refererURLString]
appStoreId:nil
appName:refererAppName];
_appLinkReferer = [FBSDKAppLink appLinkWithSourceURL:[NSURL URLWithString:refererURLString]
targets:@[ appLinkTarget ]
webURL:nil
isBackToReferrer:YES];
}
// Raise Measurement Event
NSString *const EVENT_YES_VAL = @"1";
NSString *const EVENT_NO_VAL = @"0";
NSMutableDictionary<NSString *, id> *logData = [[NSMutableDictionary alloc] init];
logData[@"version"] = version;
if (refererURLString) {
logData[@"refererURL"] = refererURLString;
}
if (refererAppName) {
logData[@"refererAppName"] = refererAppName;
}
if (sourceApplication) {
logData[@"sourceApplication"] = sourceApplication;
}
if (_targetURL.absoluteString) {
logData[@"targetURL"] = _targetURL.absoluteString;
}
if (_inputURL.absoluteString) {
logData[@"inputURL"] = _inputURL.absoluteString;
}
if (_inputURL.scheme) {
logData[@"inputURLScheme"] = _inputURL.scheme;
}
logData[@"forRenderBackToReferrerBar"] = forRenderBackToReferrerBar ? EVENT_YES_VAL : EVENT_NO_VAL;
logData[@"forOpenUrl"] = forOpenURLEvent ? EVENT_YES_VAL : EVENT_NO_VAL;
[FBSDKMeasurementEvent postNotificationForEventName:FBSDKAppLinkParseEventName args:logData];
if (forOpenURLEvent) {
[FBSDKMeasurementEvent postNotificationForEventName:FBSDKAppLinkNavigateInEventName args:logData];
}
}
}
}
return self;
}
+ (FBSDKURL *)URLWithURL:(NSURL *)url {
return [[FBSDKURL alloc] initWithURL:url forOpenInboundURL:NO sourceApplication:nil forRenderBackToReferrerBar:NO];
}
+ (FBSDKURL *)URLWithInboundURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication {
return [[FBSDKURL alloc] initWithURL:url forOpenInboundURL:YES sourceApplication:sourceApplication forRenderBackToReferrerBar:NO];
}
+ (FBSDKURL *)URLForRenderBackToReferrerBarURL:(NSURL *)url {
return [[FBSDKURL alloc] initWithURL:url forOpenInboundURL:NO sourceApplication:nil forRenderBackToReferrerBar:YES];
}
+ (NSString *)decodeURLString:(NSString *)string {
return (NSString *)CFBridgingRelease(CFURLCreateStringByReplacingPercentEscapes(NULL,
(CFStringRef)string,
CFSTR("")));
}
+ (NSDictionary<NSString *, id> *)queryParametersForURL:(NSURL *)url {
NSMutableDictionary<NSString *, id> *parameters = [NSMutableDictionary dictionary];
NSString *query = url.query;
if ([query isEqualToString:@""]) {
return @{};
}
NSArray<NSString *> *queryComponents = [query componentsSeparatedByString:@"&"];
for (NSString *component in queryComponents) {
NSRange equalsLocation = [component rangeOfString:@"="];
if (equalsLocation.location == NSNotFound) {
// There's no equals, so associate the key with NSNull
parameters[[self decodeURLString:component]] = [NSNull null];
} else {
NSString *key = [self decodeURLString:[component substringToIndex:equalsLocation.location]];
NSString *value = [self decodeURLString:[component substringFromIndex:equalsLocation.location + 1]];
parameters[key] = value;
}
}
return [NSDictionary dictionaryWithDictionary:parameters];
}
@end

View File

@ -23,57 +23,33 @@
*/
@interface FBSDKUtility : NSObject
- (instancetype)init NS_UNAVAILABLE;
+ (instancetype)new NS_UNAVAILABLE;
/**
Parses a query string into a dictionary.
@param queryString The query string value.
@return A dictionary with the key/value pairs.
- Parameter queryString: The query string value.
- Returns: A dictionary with the key/value pairs.
*/
+ (NSDictionary *)dictionaryWithQueryString:(NSString *)queryString;
/**
Constructs a query string from a dictionary.
@param dictionary The dictionary with key/value pairs for the query string.
@param errorRef If an error occurs, upon return contains an NSError object that describes the problem.
@return Query string representation of the parameters.
- Parameter dictionary: The dictionary with key/value pairs for the query string.
- Parameter errorRef: If an error occurs, upon return contains an NSError object that describes the problem.
- Returns: Query string representation of the parameters.
*/
+ (NSString *)queryStringWithDictionary:(NSDictionary *)dictionary error:(NSError *__autoreleasing *)errorRef;
/**
Decodes a value from an URL.
@param value The value to decode.
@return The decoded value.
- Parameter value: The value to decode.
- Returns: The decoded value.
*/
+ (NSString *)URLDecode:(NSString *)value;
/**
Encodes a value for an URL.
@param value The value to encode.
@return The encoded value.
- Parameter value: The value to encode.
- Returns: The encoded value.
*/
+ (NSString *)URLEncode:(NSString *)value;
/**
Creates a timer using Grand Central Dispatch.
@param interval The interval to fire the timer, in seconds.
@param block The code block to execute when timer is fired.
@return The dispatch handle.
*/
+ (dispatch_source_t)startGCDTimerWithInterval:(double)interval block:(dispatch_block_t)block;
/**
Stop a timer that was started by startGCDTimerWithInterval.
@param timer The dispatch handle received from startGCDTimerWithInterval.
*/
+ (void)stopGCDTimer:(dispatch_source_t)timer;
/**
Get SHA256 hased string of NSString/NSData
@param input The data that needs to be hashed, it could be NSString or NSData.
*/
+ (NSString *)SHA256Hash:(NSObject *)input;
@end

View File

@ -18,9 +18,8 @@
#import "FBSDKUtility.h"
#import <CommonCrypto/CommonDigest.h>
#import "FBSDKInternalUtility.h"
#import "FBSDKMacros.h"
@implementation FBSDKUtility
@ -30,7 +29,7 @@
NSArray *parts = [queryString componentsSeparatedByString:@"&"];
for (NSString *part in parts) {
if (part.length == 0) {
if ([part length] == 0) {
continue;
}
@ -62,69 +61,30 @@
+ (NSString *)URLDecode:(NSString *)value
{
return [value
stringByReplacingOccurrencesOfString:@"+"
withString:@" "].stringByRemovingPercentEncoding;
value = [value stringByReplacingOccurrencesOfString:@"+" withString:@" "];
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
value = [value stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
#pragma clang diagnostic pop
return value;
}
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+ (NSString *)URLEncode:(NSString *)value
{
NSCharacterSet *urlAllowedSet = [NSCharacterSet
characterSetWithCharactersInString:@" !*();:'@&=+$,/?%#[]\""].invertedSet;
return [value stringByAddingPercentEncodingWithAllowedCharacters:urlAllowedSet];
return (__bridge_transfer NSString *)CFURLCreateStringByAddingPercentEscapes(NULL,
(CFStringRef)value,
NULL, // characters to leave unescaped
CFSTR(":!*();@/&?+$,='"),
kCFStringEncodingUTF8);
}
#pragma clang diagnostic pop
+ (dispatch_source_t)startGCDTimerWithInterval:(double)interval block:(dispatch_block_t)block
- (instancetype)init
{
dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, // source type
0, // handle
0, // mask
dispatch_get_main_queue()); // queue
dispatch_source_set_timer(timer, // dispatch source
dispatch_time(DISPATCH_TIME_NOW, interval * NSEC_PER_SEC), // start
interval * NSEC_PER_SEC, // interval
0 * NSEC_PER_SEC); // leeway
dispatch_source_set_event_handler(timer, block);
dispatch_resume(timer);
return timer;
}
+ (void)stopGCDTimer:(dispatch_source_t)timer
{
if (timer) {
dispatch_source_cancel(timer);
}
}
+ (NSString *)SHA256Hash:(NSObject *)input
{
NSData *data = nil;
if ([input isKindOfClass:[NSString class]]) {
data = [(NSString *)input dataUsingEncoding:NSUTF8StringEncoding];
} else if ([input isKindOfClass:[NSData class]]) {
data = (NSData *)input;
}
if (!data) {
return nil;
}
uint8_t digest[CC_SHA256_DIGEST_LENGTH];
CC_SHA256(data.bytes, (CC_LONG)data.length, digest);
NSMutableString *encryptedStuff = [NSMutableString stringWithCapacity:CC_SHA256_DIGEST_LENGTH * 2];
for (int i = 0; i < CC_SHA256_DIGEST_LENGTH; i++) {
[encryptedStuff appendFormat:@"%02x", digest[i]];
}
return encryptedStuff;
FBSDK_NO_DESIGNATED_INITIALIZER();
return nil;
}
@end

View File

@ -1,38 +0,0 @@
// 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 "FBSDKAppLinkResolving.h"
NS_ASSUME_NONNULL_BEGIN
/*!
A reference implementation for an App Link resolver that uses a hidden UIWebView
to parse the HTML containing App Link metadata.
*/
@interface FBSDKWebViewAppLinkResolver : NSObject <FBSDKAppLinkResolving>
/*!
Gets the instance of a FBSDKWebViewAppLinkResolver.
*/
+ (instancetype)sharedInstance;
@end
NS_ASSUME_NONNULL_END

View File

@ -1,304 +0,0 @@
// 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 "FBSDKWebViewAppLinkResolver.h"
#import <UIKit/UIKit.h>
#import "FBSDKAppLink.h"
#import "FBSDKAppLinkTarget.h"
/**
Describes the callback for appLinkFromURLInBackground.
@param result the results from following redirects
@param error the error during the request, if any
*/
typedef void (^FBSDKURLFollowRedirectsHandler)(NSDictionary<NSString *, id> *result, NSError * _Nullable error);
// Defines JavaScript to extract app link tags from HTML content
static NSString *const FBSDKWebViewAppLinkResolverTagExtractionJavaScript = @""
"(function() {"
" var metaTags = document.getElementsByTagName('meta');"
" var results = [];"
" for (var i = 0; i < metaTags.length; i++) {"
" var property = metaTags[i].getAttribute('property');"
" if (property && property.substring(0, 'al:'.length) === 'al:') {"
" var tag = { \"property\": metaTags[i].getAttribute('property') };"
" if (metaTags[i].hasAttribute('content')) {"
" tag['content'] = metaTags[i].getAttribute('content');"
" }"
" results.push(tag);"
" }"
" }"
" return JSON.stringify(results);"
"})()";
static NSString *const FBSDKWebViewAppLinkResolverIOSURLKey = @"url";
static NSString *const FBSDKWebViewAppLinkResolverIOSAppStoreIdKey = @"app_store_id";
static NSString *const FBSDKWebViewAppLinkResolverIOSAppNameKey = @"app_name";
static NSString *const FBSDKWebViewAppLinkResolverDictionaryValueKey = @"_value";
static NSString *const FBSDKWebViewAppLinkResolverPreferHeader = @"Prefer-Html-Meta-Tags";
static NSString *const FBSDKWebViewAppLinkResolverMetaTagPrefix = @"al";
static NSString *const FBSDKWebViewAppLinkResolverWebKey = @"web";
static NSString *const FBSDKWebViewAppLinkResolverIOSKey = @"ios";
static NSString *const FBSDKWebViewAppLinkResolverIPhoneKey = @"iphone";
static NSString *const FBSDKWebViewAppLinkResolverIPadKey = @"ipad";
static NSString *const FBSDKWebViewAppLinkResolverWebURLKey = @"url";
static NSString *const FBSDKWebViewAppLinkResolverShouldFallbackKey = @"should_fallback";
@interface FBSDKWebViewAppLinkResolverWebViewDelegate : NSObject <UIWebViewDelegate>
@property (nonatomic, copy) void (^didFinishLoad)(UIWebView *webView);
@property (nonatomic, copy) void (^didFailLoadWithError)(UIWebView *webView, NSError *error);
@property (nonatomic, assign) BOOL hasLoaded;
@end
@implementation FBSDKWebViewAppLinkResolverWebViewDelegate
- (void)webViewDidFinishLoad:(UIWebView *)webView {
if (self.didFinishLoad) {
self.didFinishLoad(webView);
}
}
- (void)webViewDidStartLoad:(UIWebView *)webView {
}
- (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error {
if (self.didFailLoadWithError) {
self.didFailLoadWithError(webView, error);
}
}
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
if (self.hasLoaded) {
// Consider loading a second resource to be "success", since it indicates an inner frame
// or redirect is happening. We can run the tag extraction script at this point.
self.didFinishLoad(webView);
return NO;
}
self.hasLoaded = YES;
return YES;
}
@end
@implementation FBSDKWebViewAppLinkResolver
+ (instancetype)sharedInstance {
static id instance;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
instance = [[self alloc] init];
});
return instance;
}
- (void)followRedirects:(NSURL *)url handler:(FBSDKURLFollowRedirectsHandler)handler
{
// This task will be resolved with either the redirect NSURL
// or a dictionary with the response data to be returned.
void (^completion)(NSURLResponse *response, NSData *data, NSError *error) = ^(NSURLResponse *response, NSData *data, NSError *error) {
if (error) {
handler(nil, error);
return;
}
if ([response isKindOfClass:[NSHTTPURLResponse class]]) {
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
// NSURLConnection usually follows redirects automatically, but the
// documentation is unclear what the default is. This helps it along.
if (httpResponse.statusCode >= 300 && httpResponse.statusCode < 400) {
NSString *redirectString = httpResponse.allHeaderFields[@"Location"];
NSURL *redirectURL = [NSURL URLWithString:redirectString];
[self followRedirects:redirectURL handler:handler];
return;
}
}
handler(@{ @"response" : response, @"data" : data }, nil);
};
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
[request setValue:FBSDKWebViewAppLinkResolverMetaTagPrefix forHTTPHeaderField:FBSDKWebViewAppLinkResolverPreferHeader];
NSURLSession *session = [NSURLSession sharedSession];
[[session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
completion(response, data, error);
}] resume];
}
- (void)appLinkFromURL:(NSURL *)url handler:(FBSDKAppLinkFromURLHandler)handler
{
dispatch_async(dispatch_get_main_queue(), ^{
[self followRedirects:url handler:^(NSDictionary<NSString *,id> *result, NSError * _Nullable error) {
if (error) {
handler(nil, error);
return;
}
NSData *responseData = result[@"data"];
NSHTTPURLResponse *response = result[@"response"];
UIWebView *webView = [[UIWebView alloc] init];
FBSDKWebViewAppLinkResolverWebViewDelegate *listener = [[FBSDKWebViewAppLinkResolverWebViewDelegate alloc] init];
__block FBSDKWebViewAppLinkResolverWebViewDelegate *retainedListener = listener;
listener.didFinishLoad = ^(UIWebView *view) {
if (retainedListener) {
NSDictionary<NSString *, id> *ogData = [self getALDataFromLoadedPage:view];
[view removeFromSuperview];
view.delegate = nil;
retainedListener = nil;
handler([self appLinkFromALData:ogData destination:url], nil);
}
};
listener.didFailLoadWithError = ^(UIWebView* view, NSError *loadError) {
if (retainedListener) {
[view removeFromSuperview];
view.delegate = nil;
retainedListener = nil;
handler(nil, loadError);
}
};
webView.delegate = listener;
webView.hidden = YES;
[webView loadData:responseData
MIMEType:response.MIMEType
textEncodingName:response.textEncodingName
baseURL:response.URL];
UIWindow *window = [UIApplication sharedApplication].windows.firstObject;
[window addSubview:webView];
}];
});
}
/*
Builds up a data structure filled with the app link data from the meta tags on a page.
The structure of this object is a dictionary where each key holds an array of app link
data dictionaries. Values are stored in a key called "_value".
*/
- (NSDictionary<NSString *, id> *)parseALData:(NSArray<NSDictionary<NSString *, id> *> *)dataArray {
NSMutableDictionary<NSString *, id> *al = [NSMutableDictionary dictionary];
for (NSDictionary<NSString *, id> *tag in dataArray) {
NSString *name = tag[@"property"];
if (![name isKindOfClass:[NSString class]]) {
continue;
}
NSArray<NSString *> *nameComponents = [name componentsSeparatedByString:@":"];
if (![nameComponents[0] isEqualToString:FBSDKWebViewAppLinkResolverMetaTagPrefix]) {
continue;
}
NSMutableDictionary<NSString *, id> *root = al;
for (NSUInteger i = 1; i < nameComponents.count; i++) {
NSMutableArray<NSMutableDictionary<NSString *, id> *> *children = root[nameComponents[i]];
if (!children) {
children = [NSMutableArray array];
root[nameComponents[i]] = children;
}
NSMutableDictionary<NSString *, id> *child = children.lastObject;
if (!child || i == nameComponents.count - 1) {
child = [NSMutableDictionary dictionary];
[children addObject:child];
}
root = child;
}
if (tag[@"content"]) {
root[FBSDKWebViewAppLinkResolverDictionaryValueKey] = tag[@"content"];
}
}
return al;
}
- (NSDictionary<NSString *, id> *)getALDataFromLoadedPage:(UIWebView *)webView {
// Run some JavaScript in the webview to fetch the meta tags.
NSString *jsonString = [webView stringByEvaluatingJavaScriptFromString:FBSDKWebViewAppLinkResolverTagExtractionJavaScript];
NSError *error = nil;
NSArray<NSDictionary<NSString *, id> *> *arr =
[NSJSONSerialization JSONObjectWithData:[jsonString dataUsingEncoding:NSUTF8StringEncoding]
options:0
error:&error];
return [self parseALData:arr];
}
/*
Converts app link data into a FBSDKAppLink containing the targets relevant for this platform.
*/
- (FBSDKAppLink *)appLinkFromALData:(NSDictionary<NSString *, id> *)appLinkDict destination:(NSURL *)destination {
NSMutableArray<FBSDKAppLinkTarget *> *linkTargets = [NSMutableArray array];
NSArray *platformData = nil;
const UIUserInterfaceIdiom idiom = UI_USER_INTERFACE_IDIOM();
if (idiom == UIUserInterfaceIdiomPad) {
platformData = @[ appLinkDict[FBSDKWebViewAppLinkResolverIPadKey] ?: @{},
appLinkDict[FBSDKWebViewAppLinkResolverIOSKey] ?: @{} ];
} else if (idiom == UIUserInterfaceIdiomPhone) {
platformData = @[ appLinkDict[FBSDKWebViewAppLinkResolverIPhoneKey] ?: @{},
appLinkDict[FBSDKWebViewAppLinkResolverIOSKey] ?: @{} ];
} else {
// Future-proofing. Other User Interface idioms should only hit ios.
platformData = @[ appLinkDict[FBSDKWebViewAppLinkResolverIOSKey] ?: @{} ];
}
for (NSArray<NSDictionary *> *platformObjects in platformData) {
for (NSDictionary<NSString *, NSArray *> *platformDict in platformObjects) {
// The schema requires a single url/app store id/app name,
// but we could find multiple of them. We'll make a best effort
// to interpret this data.
NSArray<NSDictionary<NSString *, id> *> *urls = platformDict[FBSDKWebViewAppLinkResolverIOSURLKey];
NSArray<NSDictionary<NSString *, id> *> *appStoreIds = platformDict[FBSDKWebViewAppLinkResolverIOSAppStoreIdKey];
NSArray<NSDictionary<NSString *, id> *> *appNames = platformDict[FBSDKWebViewAppLinkResolverIOSAppNameKey];
NSUInteger maxCount = MAX(urls.count, MAX(appStoreIds.count, appNames.count));
for (NSUInteger i = 0; i < maxCount; i++) {
NSString *urlString = urls[i][FBSDKWebViewAppLinkResolverDictionaryValueKey];
NSURL *url = urlString ? [NSURL URLWithString:urlString] : nil;
NSString *appStoreId = appStoreIds[i][FBSDKWebViewAppLinkResolverDictionaryValueKey];
NSString *appName = appNames[i][FBSDKWebViewAppLinkResolverDictionaryValueKey];
FBSDKAppLinkTarget *target = [FBSDKAppLinkTarget appLinkTargetWithURL:url
appStoreId:appStoreId
appName:appName];
[linkTargets addObject:target];
}
}
}
NSDictionary<NSString *, id> *webDict = appLinkDict[FBSDKWebViewAppLinkResolverWebKey][0];
NSString *webUrlString = webDict[FBSDKWebViewAppLinkResolverWebURLKey][0][FBSDKWebViewAppLinkResolverDictionaryValueKey];
NSString *shouldFallbackString = webDict[FBSDKWebViewAppLinkResolverShouldFallbackKey][0][FBSDKWebViewAppLinkResolverDictionaryValueKey];
NSURL *webUrl = destination;
if (shouldFallbackString &&
[@[ @"no", @"false", @"0" ] containsObject:shouldFallbackString.lowercaseString]) {
webUrl = nil;
}
if (webUrl && webUrlString) {
webUrl = [NSURL URLWithString:webUrlString];
}
return [FBSDKAppLink appLinkWithSourceURL:destination
targets:linkTargets
webURL:webUrl];
}
@end

View File

@ -1,322 +0,0 @@
// 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 "FBSDKCodelessIndexer.h"
#import <objc/runtime.h>
#import <sys/sysctl.h>
#import <sys/utsname.h>
#import <UIKit/UIKit.h>
#import <FBSDKCoreKit/FBSDKGraphRequest.h>
#import <FBSDKCoreKit/FBSDKSettings.h>
#import "FBSDKCoreKit+Internal.h"
@implementation FBSDKCodelessIndexer
static BOOL _isCodelessIndexing;
static BOOL _isCheckingSession;
static BOOL _isCodelessIndexingEnabled;
static NSString *_deviceSessionID;
static NSTimer *_appIndexingTimer;
static NSString *_lastTreeHash;
+ (void)load
{
#if TARGET_OS_SIMULATOR
[self setupGesture];
#else
[FBSDKServerConfigurationManager loadServerConfigurationWithCompletionBlock:^(FBSDKServerConfiguration *serverConfiguration, NSError *error) {
if (serverConfiguration.codelessSetupEnabled) {
[self setupGesture];
}
}];
#endif
}
+ (void)setupGesture
{
[UIApplication sharedApplication].applicationSupportsShakeToEdit = YES;
Class class = [UIApplication class];
[FBSDKSwizzler swizzleSelector:@selector(motionBegan:withEvent:) onClass:class withBlock:^{
if ([FBSDKServerConfigurationManager cachedServerConfiguration].isCodelessEventsEnabled) {
[self checkCodelessIndexingSession];
}
} named:@"motionBegan"];
}
+ (void)checkCodelessIndexingSession
{
if (_isCheckingSession) return;
_isCheckingSession = YES;
NSDictionary *parameters = @{
CODELESS_INDEXING_SESSION_ID_KEY: [self currentSessionDeviceID],
CODELESS_INDEXING_EXT_INFO_KEY: [self extInfo]
};
FBSDKGraphRequest *request = [[FBSDKGraphRequest alloc]
initWithGraphPath:[NSString stringWithFormat:@"%@/%@",
[FBSDKSettings appID], CODELESS_INDEXING_SESSION_ENDPOINT]
parameters: parameters
HTTPMethod:@"POST"];
[request startWithCompletionHandler:^(FBSDKGraphRequestConnection *connection, id result, NSError *error) {
_isCheckingSession = NO;
if ([result isKindOfClass:[NSDictionary class]]) {
_isCodelessIndexingEnabled = [((NSDictionary *)result)[CODELESS_INDEXING_STATUS_KEY] boolValue];
if (_isCodelessIndexingEnabled) {
_lastTreeHash = nil;
if (!_appIndexingTimer) {
_appIndexingTimer = [NSTimer timerWithTimeInterval:CODELESS_INDEXING_UPLOAD_INTERVAL_IN_SECONDS
target:self
selector:@selector(startIndexing)
userInfo:nil
repeats:YES];
[[NSRunLoop mainRunLoop] addTimer:_appIndexingTimer forMode:NSDefaultRunLoopMode];
}
} else {
_deviceSessionID = nil;
}
}
}];
}
+ (NSString *)currentSessionDeviceID
{
if (!_deviceSessionID) {
_deviceSessionID = [NSUUID UUID].UUIDString;
}
return _deviceSessionID;
}
+ (NSString *)extInfo
{
struct utsname systemInfo;
uname(&systemInfo);
NSString *machine = @(systemInfo.machine);
NSString *advertiserID = [FBSDKAppEventsUtility advertiserID] ?: @"";
machine = machine ?: @"";
NSString *debugStatus = [FBSDKAppEventsUtility isDebugBuild] ? @"1" : @"0";
#if TARGET_IPHONE_SIMULATOR
NSString *isSimulator = @"1";
#else
NSString *isSimulator = @"0";
#endif
NSLocale *locale = [NSLocale currentLocale];
NSString *languageCode = [locale objectForKey:NSLocaleLanguageCode];
NSString *countryCode = [locale objectForKey:NSLocaleCountryCode];
NSString *localeString = locale.localeIdentifier;
if (languageCode && countryCode) {
localeString = [NSString stringWithFormat:@"%@_%@", languageCode, countryCode];
}
NSString *extinfo = [FBSDKInternalUtility JSONStringForObject:@[machine,
advertiserID,
debugStatus,
isSimulator,
localeString]
error:NULL
invalidObjectHandler:NULL];
return extinfo ?: @"";
}
+ (void)startIndexing {
if (!_isCodelessIndexingEnabled) {
return;
}
if (UIApplicationStateActive != [UIApplication sharedApplication].applicationState) {
return;
}
// If userAgentSuffix begins with Unity, trigger unity code to upload view hierarchy
NSString *userAgentSuffix = [FBSDKSettings userAgentSuffix];
if (userAgentSuffix != nil && [userAgentSuffix hasPrefix:@"Unity"]) {
Class FBUnityUtility = objc_lookUpClass("FBUnityUtility");
SEL selector = NSSelectorFromString(@"triggerUploadViewHierarchy");
if (FBUnityUtility && selector && [FBUnityUtility respondsToSelector:selector]) {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
[FBUnityUtility performSelector:selector];
#pragma clang diagnostic pop
}
} else {
[self uploadIndexing];
}
}
+ (void)uploadIndexing
{
if (_isCodelessIndexing) {
return;
}
NSString *tree = [FBSDKCodelessIndexer currentViewTree];
[self uploadIndexing:tree];
}
+ (void)uploadIndexing:(NSString *)tree
{
if (_isCodelessIndexing) {
return;
}
if (!tree) {
return;
}
NSString *currentTreeHash = [FBSDKUtility SHA256Hash:tree];
if (_lastTreeHash && [_lastTreeHash isEqualToString:currentTreeHash]) {
return;
}
_lastTreeHash = currentTreeHash;
NSBundle *mainBundle = [NSBundle mainBundle];
NSString *version = [mainBundle objectForInfoDictionaryKey:@"CFBundleShortVersionString"];
FBSDKGraphRequest *request = [[FBSDKGraphRequest alloc]
initWithGraphPath:[NSString stringWithFormat:@"%@/%@",
[FBSDKSettings appID], CODELESS_INDEXING_ENDPOINT]
parameters:@{
CODELESS_INDEXING_TREE_KEY: tree,
CODELESS_INDEXING_APP_VERSION_KEY: version ?: @"",
CODELESS_INDEXING_PLATFORM_KEY: @"iOS",
CODELESS_INDEXING_SESSION_ID_KEY: [self currentSessionDeviceID]
}
HTTPMethod:@"POST"];
_isCodelessIndexing = YES;
[request startWithCompletionHandler:^(FBSDKGraphRequestConnection *connection, id result, NSError *error) {
_isCodelessIndexing = NO;
if ([result isKindOfClass:[NSDictionary class]]) {
_isCodelessIndexingEnabled = [result[CODELESS_INDEXING_STATUS_KEY] boolValue];
if (!_isCodelessIndexingEnabled) {
_deviceSessionID = nil;
}
}
}];
}
+ (NSString *)currentViewTree
{
NSMutableArray *trees = [NSMutableArray array];
NSArray *windows = [UIApplication sharedApplication].windows;
for (UIWindow *window in windows) {
NSDictionary *tree = [FBSDKCodelessIndexer recursiveCaptureTree:window];
if (tree) {
if (window.isKeyWindow) {
[trees insertObject:tree atIndex:0];
} else {
[trees addObject:tree];
}
}
}
if (0 == trees.count) {
return nil;
}
NSArray *viewTrees = [trees reverseObjectEnumerator].allObjects;
NSData *data = UIImageJPEGRepresentation([FBSDKCodelessIndexer screenshot], 0.5);
NSString *screenshot = [data base64EncodedStringWithOptions:0];
NSMutableDictionary *treeInfo = [NSMutableDictionary dictionary];
treeInfo[@"view"] = viewTrees;
treeInfo[@"screenshot"] = screenshot ?: @"";
NSString *tree = nil;
data = [NSJSONSerialization dataWithJSONObject:treeInfo options:0 error:nil];
if (data) {
tree = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
}
return tree;
}
+ (NSDictionary<NSString *, id> *)recursiveCaptureTree:(NSObject *)obj
{
if (!obj) {
return nil;
}
NSMutableDictionary *result = [FBSDKViewHierarchy getDetailAttributesOf:obj];
NSArray *children = [FBSDKViewHierarchy getChildren:obj];
NSMutableArray *childrenTrees = [NSMutableArray array];
for (NSObject *child in children) {
NSDictionary *objTree = [self recursiveCaptureTree:child];
[childrenTrees addObject:objTree];
}
if (childrenTrees.count > 0) {
[result setValue:[childrenTrees copy] forKey:CODELESS_VIEW_TREE_CHILDREN_KEY];
}
return [result copy];
}
+ (UIImage *)screenshot {
UIWindow *window = [UIApplication sharedApplication].delegate.window;
UIGraphicsBeginImageContext(window.bounds.size);
[window drawViewHierarchyInRect:window.bounds afterScreenUpdates:YES];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image;
}
+ (NSDictionary<NSString *, NSNumber *> *)dimensionOf:(NSObject *)obj
{
UIView *view = nil;
if ([obj isKindOfClass:[UIView class]]) {
view = (UIView *)obj;
} else if ([obj isKindOfClass:[UIViewController class]]) {
view = ((UIViewController *)obj).view;
}
CGRect frame = view.frame;
CGPoint offset = CGPointZero;
if ([view isKindOfClass:[UIScrollView class]])
offset = ((UIScrollView *)view).contentOffset;
return @{
CODELESS_VIEW_TREE_TOP_KEY: @((int)frame.origin.y),
CODELESS_VIEW_TREE_LEFT_KEY: @((int)frame.origin.x),
CODELESS_VIEW_TREE_WIDTH_KEY: @((int)frame.size.width),
CODELESS_VIEW_TREE_HEIGHT_KEY: @((int)frame.size.height),
CODELESS_VIEW_TREE_OFFSET_X_KEY: @((int)offset.x),
CODELESS_VIEW_TREE_OFFSET_Y_KEY: @((int)offset.y),
CODELESS_VIEW_TREE_VISIBILITY_KEY: view.isHidden ? @4 : @0
};
}
@end

View File

@ -1,85 +0,0 @@
// 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.
#ifndef FBSDKCodelessMacros_h
#define FBSDKCodelessMacros_h
// keys for event binding path compoenent
#define CODELESS_MAPPING_METHOD_KEY @"method"
#define CODELESS_MAPPING_EVENT_NAME_KEY @"event_name"
#define CODELESS_MAPPING_EVENT_TYPE_KEY @"event_type"
#define CODELESS_MAPPING_APP_VERSION_KEY @"app_version"
#define CODELESS_MAPPING_PATH_KEY @"path"
#define CODELESS_MAPPING_PATH_TYPE_KEY @"path_type"
#define CODELESS_MAPPING_CLASS_NAME_KEY @"class_name"
#define CODELESS_MAPPING_MATCH_BITMASK_KEY @"match_bitmask"
#define CODELESS_MAPPING_ID_KEY @"id"
#define CODELESS_MAPPING_INDEX_KEY @"index"
#define CODELESS_MAPPING_SECTION_KEY @"section"
#define CODELESS_MAPPING_ROW_KEY @"row"
#define CODELESS_MAPPING_TEXT_KEY @"text"
#define CODELESS_MAPPING_TAG_KEY @"tag"
#define CODELESS_MAPPING_DESC_KEY @"description"
#define CODELESS_MAPPING_HINT_KEY @"hint"
#define CODELESS_MAPPING_PARAMETERS_KEY @"parameters"
#define CODELESS_MAPPING_PARAMETER_NAME_KEY @"name"
#define CODELESS_MAPPING_PARAMETER_VALUE_KEY @"value"
#define CODELESS_MAPPING_PARENT_CLASS_NAME @".."
#define CODELESS_MAPPING_CURRENT_CLASS_NAME @"."
#define ReactNativeClassRCTView "RCTView"
#define ReactNativeClassRCTRootView "RCTRootView"
#define CODELESS_INDEXING_UPLOAD_INTERVAL_IN_SECONDS 1
#define CODELESS_INDEXING_STATUS_KEY @"is_app_indexing_enabled"
#define CODELESS_INDEXING_SESSION_ID_KEY @"device_session_id"
#define CODELESS_INDEXING_APP_VERSION_KEY @"app_version"
#define CODELESS_INDEXING_SDK_VERSION_KEY @"sdk_version"
#define CODELESS_INDEXING_PLATFORM_KEY @"platform"
#define CODELESS_INDEXING_TREE_KEY @"tree"
#define CODELESS_INDEXING_SCREENSHOT_KEY @"screenshot"
#define CODELESS_INDEXING_EXT_INFO_KEY @"extinfo"
#define CODELESS_INDEXING_ENDPOINT @"app_indexing"
#define CODELESS_INDEXING_SESSION_ENDPOINT @"app_indexing_session"
// keys for view tree
#define CODELESS_VIEW_TREE_CLASS_NAME_KEY @"classname"
#define CODELESS_VIEW_TREE_CLASS_TYPE_BIT_MASK_KEY @"classtypebitmask"
#define CODELESS_VIEW_TREE_TEXT_KEY @"text"
#define CODELESS_VIEW_TREE_DESC_KEY @"description"
#define CODELESS_VIEW_TREE_DIMENSION_KEY @"dimension"
#define CODELESS_VIEW_TREE_TAG_KEY @"tag"
#define CODELESS_VIEW_TREE_CHILDREN_KEY @"childviews"
#define CODELESS_VIEW_TREE_HINT_KEY @"hint"
#define CODELESS_VIEW_TREE_ACTIONS_KEY @"actions"
#define CODELESS_VIEW_TREE_TOP_KEY @"top"
#define CODELESS_VIEW_TREE_LEFT_KEY @"left"
#define CODELESS_VIEW_TREE_WIDTH_KEY @"width"
#define CODELESS_VIEW_TREE_HEIGHT_KEY @"height"
#define CODELESS_VIEW_TREE_OFFSET_X_KEY @"scrollx"
#define CODELESS_VIEW_TREE_OFFSET_Y_KEY @"scrolly"
#define CODELESS_VIEW_TREE_VISIBILITY_KEY @"visibility"
#define CODELESS_VIEW_TREE_TEXT_STYLE_KEY @"text_style"
#define CODELESS_VIEW_TREE_TEXT_IS_BOLD_KEY @"is_bold"
#define CODELESS_VIEW_TREE_TEXT_IS_ITALIC_KEY @"is_italic"
#define CODELESS_VIEW_TREE_TEXT_SIZE_KEY @"font_size"
#endif /* FBSDKCodelessMacros_h */

View File

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

View File

@ -1,44 +0,0 @@
// 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 "FBSDKCodelessParameterComponent.h"
#import "FBSDKCodelessMacros.h"
#import "FBSDKCodelessPathComponent.h"
@implementation FBSDKCodelessParameterComponent
- (instancetype)initWithJSON:(NSDictionary *)dict {
if (self = [super init]) {
_name = [dict[CODELESS_MAPPING_PARAMETER_NAME_KEY] copy];
_value = [dict[CODELESS_MAPPING_PARAMETER_VALUE_KEY] copy];
_pathType = [dict[CODELESS_MAPPING_PATH_TYPE_KEY] copy];
NSArray *ary = dict[CODELESS_MAPPING_PATH_KEY];
NSMutableArray *mut = [NSMutableArray array];
for (NSDictionary *info in ary) {
FBSDKCodelessPathComponent *component = [[FBSDKCodelessPathComponent alloc] initWithJSON:info];
[mut addObject:component];
}
_path = [mut copy];
}
return self;
}
@end

View File

@ -1,44 +0,0 @@
// Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
//
// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,
// copy, modify, and distribute this software in source code or binary form for use
// in connection with the web services and APIs provided by Facebook.
//
// As with any software that integrates with the Facebook platform, your use of
// this software is subject to the Facebook Developer Principles and Policies
// [http://developers.facebook.com/policy/]. This copyright notice shall be
// included in all copies or substantial portions of the software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#import <Foundation/Foundation.h>
typedef NS_OPTIONS(int, FBSDKCodelessMatchBitmaskField)
{
FBSDKCodelessMatchBitmaskFieldID = 1,
FBSDKCodelessMatchBitmaskFieldText = 1 << 1,
FBSDKCodelessMatchBitmaskFieldTag = 1 << 2,
FBSDKCodelessMatchBitmaskFieldDescription = 1 << 3,
FBSDKCodelessMatchBitmaskFieldHint = 1 << 4
};
@interface FBSDKCodelessPathComponent : NSObject
@property (nonatomic, copy, readonly) NSString *className;
@property (nonatomic, copy, readonly) NSString *text;
@property (nonatomic, copy, readonly) NSString *hint;
@property (nonatomic, copy, readonly) NSString *desc; // description
@property (nonatomic, readonly) int index;
@property (nonatomic, readonly) int tag;
@property (nonatomic, readonly) int section;
@property (nonatomic, readonly) int row;
@property (nonatomic, readonly) int matchBitmask;
- (instancetype)initWithJSON:(NSDictionary*)dict;
@end

View File

@ -1,58 +0,0 @@
// 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 "FBSDKCodelessPathComponent.h"
#import "FBSDKCodelessMacros.h"
@implementation FBSDKCodelessPathComponent
- (instancetype)initWithJSON:(NSDictionary *)dict {
if (self = [super init]) {
_className = [dict[CODELESS_MAPPING_CLASS_NAME_KEY] copy];
_text = [dict[CODELESS_MAPPING_TEXT_KEY] copy];
_hint = [dict[CODELESS_MAPPING_HINT_KEY] copy];
_desc = [dict[CODELESS_MAPPING_DESC_KEY] copy];
if (dict[CODELESS_MAPPING_INDEX_KEY]) {
_index = [dict[CODELESS_MAPPING_INDEX_KEY] intValue];
} else {
_index = -1;
}
if (dict[CODELESS_MAPPING_SECTION_KEY]) {
_section = [dict[CODELESS_MAPPING_SECTION_KEY] intValue];
} else {
_section = -1;
}
if (dict[CODELESS_MAPPING_ROW_KEY]) {
_row = [dict[CODELESS_MAPPING_ROW_KEY] intValue];
} else {
_row = -1;
}
_tag = [dict[CODELESS_MAPPING_TAG_KEY] intValue];
_matchBitmask = [dict[CODELESS_MAPPING_MATCH_BITMASK_KEY] intValue];
}
return self;
}
@end

View File

@ -1,37 +0,0 @@
// Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
//
// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,
// copy, modify, and distribute this software in source code or binary form for use
// in connection with the web services and APIs provided by Facebook.
//
// As with any software that integrates with the Facebook platform, your use of
// this software is subject to the Facebook Developer Principles and Policies
// [http://developers.facebook.com/policy/]. This copyright notice shall be
// included in all copies or substantial portions of the software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
@interface FBSDKEventBinding : NSObject
@property (nonatomic, copy, readonly) NSString *eventName;
@property (nonatomic, copy, readonly) NSString *eventType;
@property (nonatomic, copy, readonly) NSString *appVersion;
@property (nonatomic, readonly) NSArray *path;
@property (nonatomic, copy, readonly) NSString *pathType;
@property (nonatomic, readonly) NSArray *parameters;
+ (BOOL)isViewMatchPath:(UIView *)view path:(NSArray *)path;
+ (BOOL)isPath:(NSArray *)path matchViewPath:(NSArray *)viewPath;
- (FBSDKEventBinding *)initWithJSON:(NSDictionary *)dict;
- (void)trackEvent:(id)sender;
@end

View File

@ -1,274 +0,0 @@
// 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 "FBSDKEventBinding.h"
#import <FBSDKCoreKit/FBSDKAppEvents.h>
#import "FBSDKAppEventsUtility.h"
#import "FBSDKCodelessMacros.h"
#import "FBSDKCodelessParameterComponent.h"
#import "FBSDKCodelessPathComponent.h"
#import "FBSDKSwizzler.h"
#import "FBSDKViewHierarchy.h"
#define CODELESS_PATH_TYPE_ABSOLUTE @"absolute"
#define CODELESS_PATH_TYPE_RELATIVE @"relative"
#define CODELESS_CODELESS_EVENT_KEY @"_is_fb_codeless"
#define PARAMETER_NAME_PRICE @"_valueToSum"
@implementation FBSDKEventBinding
- (FBSDKEventBinding *)initWithJSON:(NSDictionary *)dict
{
if ((self = [super init])) {
_eventName = [dict[CODELESS_MAPPING_EVENT_NAME_KEY] copy];
_eventType = [dict[CODELESS_MAPPING_EVENT_TYPE_KEY] copy];
_appVersion = [dict[CODELESS_MAPPING_APP_VERSION_KEY] copy];
_pathType = [dict[CODELESS_MAPPING_PATH_TYPE_KEY] copy];
NSArray *pathComponents = dict[CODELESS_MAPPING_PATH_KEY];
NSMutableArray *mut = [NSMutableArray array];
for (NSDictionary *info in pathComponents) {
FBSDKCodelessPathComponent *component = [[FBSDKCodelessPathComponent alloc] initWithJSON:info];
[mut addObject:component];
}
_path = [mut copy];
NSArray *parameters = dict[CODELESS_MAPPING_PARAMETERS_KEY];
mut = [NSMutableArray array];
for (NSDictionary *info in parameters) {
FBSDKCodelessParameterComponent *component = [[FBSDKCodelessParameterComponent alloc] initWithJSON:info];
[mut addObject:component];
}
_parameters = [mut copy];
}
return self;
}
- (void)trackEvent:(id)sender
{
UIView *sourceView = [sender isKindOfClass:[UIView class]] ? (UIView *)sender : nil;
NSMutableDictionary *params = [NSMutableDictionary dictionary];
params[CODELESS_CODELESS_EVENT_KEY] = @"1";
for (FBSDKCodelessParameterComponent *component in self.parameters) {
NSString *text = component.value;
if (!text || text.length == 0) {
text = [FBSDKEventBinding findParameterOfPath:component.path
pathType:component.pathType
sourceView:sourceView];
}
if (text) {
if ([component.name isEqualToString:PARAMETER_NAME_PRICE]) {
NSNumber *value = [FBSDKAppEventsUtility getNumberValue:text];
params[component.name] = value;
} else {
params[component.name] = text;
}
}
}
[FBSDKAppEvents logEvent:_eventName parameters:[params copy]];
}
+ (BOOL)matchAnyView:(NSArray *)views
pathComponent:(FBSDKCodelessPathComponent *)component
{
for (NSObject *view in views) {
if ([self match:view pathComponent:component]) {
return YES;
}
}
return NO;
}
+ (BOOL)match:(NSObject *)view
pathComponent:(FBSDKCodelessPathComponent *)component
{
NSString *className = NSStringFromClass([view class]);
if (![className isEqualToString:component.className]) {
return NO;
}
if (component.index >= 0) {
NSObject *parent = [FBSDKViewHierarchy getParent:view];
if (parent) {
NSArray *children = [FBSDKViewHierarchy getChildren:[FBSDKViewHierarchy getParent:view]];
NSUInteger index = [children indexOfObject:view];
if (index == NSNotFound || index != component.index) {
return NO;
}
} else {
if (0 != component.index) {
return NO;
}
}
}
if ((component.matchBitmask & FBSDKCodelessMatchBitmaskFieldText) > 0) {
NSString *text = [FBSDKViewHierarchy getText:view];
BOOL match = ((text.length == 0 && component.text.length == 0)
|| [text isEqualToString:component.text]);
if (!match) {
return NO;
}
}
if ((component.matchBitmask & FBSDKCodelessMatchBitmaskFieldTag) > 0
&& [view isKindOfClass:[UIView class]]
&& component.tag != ((UIView *)view).tag) {
return NO;
}
if ((component.matchBitmask & FBSDKCodelessMatchBitmaskFieldHint) > 0) {
NSString *hint = [FBSDKViewHierarchy getHint:view];
BOOL match = ((hint.length == 0 && component.hint.length == 0)
|| [hint isEqualToString:component.hint]);
if (!match) {
return NO;
}
}
return YES;
}
+ (BOOL)isViewMatchPath:(UIView *)view path:(NSArray *)path
{
NSArray *viewPath = [FBSDKViewHierarchy getPath:view];
BOOL isMatch = [self isPath:path matchViewPath:viewPath];
return isMatch;
}
+ (BOOL)isPath:(NSArray *)path matchViewPath:(NSArray *)viewPath {
for (NSInteger i = 0; i < MIN(path.count, viewPath.count); i++) {
NSInteger idxPath = path.count - i - 1;
NSInteger idxViewPath = viewPath.count - i - 1;
FBSDKCodelessPathComponent *pathComponent = path[idxPath];
FBSDKCodelessPathComponent *viewPathComponent = viewPath[idxViewPath];
if (![pathComponent.className isEqualToString:viewPathComponent.className]) {
return NO;
}
if (pathComponent.index >= 0
&& pathComponent.index != viewPathComponent.index) {
return NO;
}
if ((pathComponent.matchBitmask & FBSDKCodelessMatchBitmaskFieldText) > 0) {
NSString *text = viewPathComponent.text;
BOOL match = ((text.length == 0 && pathComponent.text.length == 0)
|| [text isEqualToString:pathComponent.text]);
if (!match) {
return NO;
}
}
if ((pathComponent.matchBitmask & FBSDKCodelessMatchBitmaskFieldTag) > 0
&& pathComponent.tag != viewPathComponent.tag) {
return NO;
}
if ((pathComponent.matchBitmask & FBSDKCodelessMatchBitmaskFieldHint) > 0) {
NSString *hint = viewPathComponent.hint;
BOOL match = ((hint.length == 0 && pathComponent.hint.length == 0)
|| [hint isEqualToString:pathComponent.hint]);
if (!match) {
return NO;
}
}
}
return YES;
}
+ (NSObject *)findViewByPath:(NSArray *)path parent:(NSObject *)parent level:(int)level {
if (level >= path.count) {
return nil;
}
FBSDKCodelessPathComponent *pathComponent = path[level];
// If found parent, skip to next level
if ([pathComponent.className isEqualToString:CODELESS_MAPPING_PARENT_CLASS_NAME]) {
NSObject *nextParent = [FBSDKViewHierarchy getParent:parent];
return [FBSDKEventBinding findViewByPath:path parent:nextParent level:level + 1];
} else if ([pathComponent.className isEqualToString:CODELESS_MAPPING_CURRENT_CLASS_NAME]) {
return parent;
}
NSArray *children;
if (parent) {
children = [FBSDKViewHierarchy getChildren:parent];
} else {
UIWindow *window = [UIApplication sharedApplication].delegate.window;
if (window) {
children = @[window];
} else {
return nil;
}
}
if (path.count - 1 == level) {
int index = pathComponent.index;
if (index >= 0) {
NSObject *child = index < children.count ? children[index] : nil;
if ([self match:child pathComponent:pathComponent]) {
return child;
}
} else {
for (NSObject *child in children) {
if ([self match:child pathComponent:pathComponent]) {
return child;
}
}
}
} else {
for (NSObject *child in children) {
NSObject *result = [self findViewByPath:path parent:child level:level + 1];
if (result) {
return result;
}
}
}
return nil;
}
// MARK: - find event parameters via relative path
+ (NSString *)findParameterOfPath:(NSArray *)path
pathType:(NSString *)pathType
sourceView:(UIView *)sourceView {
if (0 == path.count) {
return nil;
}
UIView *rootView = sourceView;
if (![pathType isEqualToString:CODELESS_PATH_TYPE_RELATIVE]) {
rootView = nil;
}
NSObject *foundObj = [self findViewByPath:path parent:rootView level:0];
return [FBSDKViewHierarchy getText:foundObj];
}
@end

View File

@ -1,388 +0,0 @@
// 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 "FBSDKEventBindingManager.h"
#import <objc/runtime.h>
#import <UIKit/UIKit.h>
#import "FBSDKCodelessMacros.h"
#import "FBSDKCodelessPathComponent.h"
#import "FBSDKEventBinding.h"
#import "FBSDKSwizzler.h"
#import "FBSDKTypeUtility.h"
#import "FBSDKViewHierarchy.h"
#define ReactNativeTargetKey @"target"
#define ReactNativeTouchEndEventName @"topTouchEnd"
#define ReactNativeClassRCTTextView "RCTTextView"
#define ReactNativeClassRCTImageView "RCTImageVIew"
#define ReactNativeClassRCTEventDispatcher "RCTEventDispatcher"
#define ReactNativeClassRCTTouchEvent "RCTTouchEvent"
static void fb_dispatch_on_main_thread(dispatch_block_t block) {
dispatch_async(dispatch_get_main_queue(), block);
}
static void fb_dispatch_on_default_thread(dispatch_block_t block) {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), block);
}
@interface FBSDKEventBindingManager ()
{
BOOL isStarted;
NSMutableDictionary *reactBindings;
NSSet *validClasses;
BOOL hasReactNative;
NSArray *eventBindings;
}
@end
@implementation FBSDKEventBindingManager
- (id)init {
self = [super init];
if (self) {
isStarted = NO;
hasReactNative = NO;
reactBindings = [NSMutableDictionary dictionary];
NSMutableSet *classes = [NSMutableSet set];
[classes addObject:[UIControl class]];
[classes addObject:[UITableView class]];
[classes addObject:[UICollectionView class]];
// ReactNative
Class classRCTRootView = objc_lookUpClass(ReactNativeClassRCTRootView);
if (classRCTRootView != nil) {
hasReactNative = YES;
Class classRCTView = objc_lookUpClass(ReactNativeClassRCTView);
Class classRCTTextView = objc_lookUpClass(ReactNativeClassRCTTextView);
Class classRCTImageView = objc_lookUpClass(ReactNativeClassRCTImageView);
if (classRCTView) {
[classes addObject:classRCTView];
}
if (classRCTTextView) {
[classes addObject:classRCTTextView];
}
if (classRCTImageView) {
[classes addObject:classRCTImageView];
}
}
validClasses = [NSSet setWithSet:classes];
}
return self;
}
+ (NSArray *)parseArray:(NSArray *)array {
NSMutableArray *result = [NSMutableArray array];
for (NSDictionary *json in array) {
FBSDKEventBinding *binding = [[FBSDKEventBinding alloc] initWithJSON:json];
[result addObject:binding];
}
return [result copy];
}
- (FBSDKEventBindingManager*)initWithJSON:(NSDictionary*)dict
{
if ((self = [super init])) {
NSArray *eventBindingsDict = [FBSDKTypeUtility arrayValue:dict[@"event_bindings"]];
NSMutableArray *bindings = [NSMutableArray array];
for (NSDictionary *d in eventBindingsDict) {
FBSDKEventBinding *e = [[FBSDKEventBinding alloc] initWithJSON:d];
[bindings addObject:e];
}
eventBindings = [bindings copy];
}
return self;
}
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wundeclared-selector"
- (void)start
{
if (isStarted) {
return;
}
isStarted = YES;
void (^blockToSuperview)(id view) = ^(id view) {
[self matchView:view delegate:nil];
};
void (^blockToWindow)(id view) = ^(id view) {
[self matchView:view delegate:nil];
};
[FBSDKSwizzler swizzleSelector:@selector(didMoveToSuperview)
onClass:[UIControl class]
withBlock:blockToSuperview named:@"map_control"];
[FBSDKSwizzler swizzleSelector:@selector(didMoveToWindow)
onClass:[UIControl class]
withBlock:blockToWindow named:@"map_control"];
// ReactNative
if (hasReactNative) { // If app is built via ReactNative
Class classRCTView = objc_lookUpClass(ReactNativeClassRCTView);
Class classRCTTextView = objc_lookUpClass(ReactNativeClassRCTTextView);
Class classRCTImageView = objc_lookUpClass(ReactNativeClassRCTImageView);
Class classRCTEventDispatcher = objc_lookUpClass(ReactNativeClassRCTEventDispatcher);
// All react-native views would be added tp RCTRootView, so no need to check didMoveToWindow
[FBSDKSwizzler swizzleSelector:@selector(didMoveToSuperview)
onClass:classRCTView
withBlock:blockToSuperview
named:@"match_react_native"];
[FBSDKSwizzler swizzleSelector:@selector(didMoveToSuperview)
onClass:classRCTTextView
withBlock:blockToSuperview
named:@"match_react_native"];
[FBSDKSwizzler swizzleSelector:@selector(didMoveToSuperview)
onClass:classRCTImageView
withBlock:blockToSuperview
named:@"match_react_native"];
[FBSDKSwizzler swizzleSelector:@selector(dispatchEvent:) onClass:classRCTEventDispatcher withBlock:^(id dispatcher, SEL command, id event){
if ([event isKindOfClass:objc_lookUpClass(ReactNativeClassRCTTouchEvent)]) {
@try {
NSArray<id> *eventArgs = [event arguments];
NSString *eventName = eventArgs[0];
NSArray<NSDictionary *> *touches = eventArgs[1];
if (eventName && touches && [eventName isEqualToString:ReactNativeTouchEndEventName]) {
for (NSDictionary<NSString *, id> *touch in touches) {
NSNumber *targetTag = touch[ReactNativeTargetKey];
FBSDKEventBinding *eventBinding = self->reactBindings[targetTag];
if (eventBinding) {
[eventBinding trackEvent:nil];
}
}
}
}
@catch(NSException *exception) {
// Catch exception here to prevent LytroKit from crashing app
}
}
} named:@"dispatch_rn_event"];
}
// UITableView
void (^tableViewBlock)(UITableView *tableView,
SEL cmd,
id<UITableViewDelegate> delegate) =
^(UITableView *tableView, SEL cmd, id<UITableViewDelegate> delegate) {
if (!delegate) {
return;
}
[self matchView:tableView delegate:delegate];
};
[FBSDKSwizzler swizzleSelector:@selector(setDelegate:)
onClass:[UITableView class]
withBlock:tableViewBlock
named:@"match_table_view"];
// UICollectionView
void (^collectionViewBlock)(UICollectionView *collectionView,
SEL cmd,
id<UICollectionViewDelegate> delegate) =
^(UICollectionView *collectionView, SEL cmd, id<UICollectionViewDelegate> delegate) {
if (nil == delegate) {
return;
}
[self matchView:collectionView delegate:delegate];
};
[FBSDKSwizzler swizzleSelector:@selector(setDelegate:)
onClass:[UICollectionView class]
withBlock:collectionViewBlock
named:@"handle_collection_view"];
}
- (void)rematchBindings {
if (0 == eventBindings.count) {
return;
}
NSArray *windows = [UIApplication sharedApplication].windows;
for (UIWindow *window in windows) {
[self matchSubviewsIn:window];
}
}
- (void)matchSubviewsIn:(UIView *)view {
if (!view) {
return;
}
for (UIView *subview in view.subviews) {
BOOL isValidClass = NO;
for (Class cls in validClasses) {
if ([subview isKindOfClass:cls]) {
isValidClass = YES;
break;
}
}
if (isValidClass) {
if ([subview isKindOfClass:[UITableView class]]) {
UITableView *tableView = (UITableView *)subview;
if (tableView.delegate) {
[self matchView:subview delegate:tableView.delegate];
}
} else if ([subview isKindOfClass:[UICollectionView class]]) {
UICollectionView *collectionView = (UICollectionView *)subview;
if (collectionView.delegate) {
[self matchView:subview delegate:collectionView.delegate];
}
} else {
[self matchView:subview delegate:nil];
}
}
if (![subview isKindOfClass:[UIControl class]]) {
[self matchSubviewsIn:subview];
}
}
}
// check if the view is matched to any event
- (void)matchView:(UIView *)view delegate:(id)delegate {
if (0 == eventBindings.count) {
return;
}
fb_dispatch_on_main_thread(^{
NSArray *path = [FBSDKViewHierarchy getPath:view];
fb_dispatch_on_default_thread(^{
if ([view isKindOfClass:[UIControl class]]) {
UIControl *control = (UIControl *)view;
for (FBSDKEventBinding *binding in self->eventBindings) {
if ([FBSDKEventBinding isPath:binding.path matchViewPath:path]) {
fb_dispatch_on_main_thread(^{
[control addTarget:binding
action:@selector(trackEvent:)
forControlEvents:UIControlEventTouchUpInside];
});
break;
}
}
} else if (self->hasReactNative
&& [view respondsToSelector:@selector(reactTag)]) {
for (FBSDKEventBinding *binding in self->eventBindings) {
if ([FBSDKEventBinding isPath:binding.path matchViewPath:path]) {
fb_dispatch_on_main_thread(^{
// React Native touchable event is targeted at first subview,
// so extract the first subview and set the binding for it
UIView *reactView = view.subviews.firstObject;
if (reactView) {
NSNumber *reactTag = [FBSDKViewHierarchy getViewReactTag:reactView];
if (reactTag != nil) {
self->reactBindings[reactTag] = binding;
}
}
});
break;
}
}
} else if ([view isKindOfClass:[UITableView class]]
&& [delegate conformsToProtocol:@protocol(UITableViewDelegate)]) {
fb_dispatch_on_default_thread(^{
NSMutableSet *matchedBindings = [NSMutableSet set];
for (FBSDKEventBinding *binding in self->eventBindings) {
if (binding.path.count > 1) {
NSArray *shortPath = [binding.path
subarrayWithRange:NSMakeRange(0, binding.path.count - 1)];
if ([FBSDKEventBinding isPath:shortPath matchViewPath:path]) {
[matchedBindings addObject:binding];
}
}
}
if (matchedBindings.count > 0) {
NSArray *bindings = matchedBindings.allObjects;
void (^block)(id, SEL, id, id) = ^(id target, SEL command, UITableView *tableView, NSIndexPath *indexPath) {
fb_dispatch_on_main_thread(^{
for (FBSDKEventBinding *binding in bindings) {
FBSDKCodelessPathComponent *component = binding.path.lastObject;
if ((component.section == -1 || component.section == indexPath.section)
&& (component.row == -1 || component.row == indexPath.row)) {
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
[binding trackEvent:cell];
}
}
});
};
[FBSDKSwizzler swizzleSelector:@selector(tableView:didSelectRowAtIndexPath:)
onClass:[delegate class]
withBlock:block
named:@"handle_table_view"];
}
});
} else if ([view isKindOfClass:[UICollectionView class]]
&& [delegate conformsToProtocol:@protocol(UICollectionViewDelegate)]) {
fb_dispatch_on_default_thread(^{
NSMutableSet *matchedBindings = [NSMutableSet set];
for (FBSDKEventBinding *binding in self->eventBindings) {
if (binding.path.count > 1) {
NSArray *shortPath = [binding.path
subarrayWithRange:NSMakeRange(0, binding.path.count - 1)];
if ([FBSDKEventBinding isPath:shortPath matchViewPath:path]) {
[matchedBindings addObject:binding];
}
}
}
if (matchedBindings.count > 0) {
NSArray *bindings = matchedBindings.allObjects;
void (^block)(id, SEL, id, id) = ^(id target, SEL command, UICollectionView *collectionView, NSIndexPath *indexPath) {
fb_dispatch_on_main_thread(^{
for (FBSDKEventBinding *binding in bindings) {
FBSDKCodelessPathComponent *component = binding.path.lastObject;
if ((component.section == -1 || component.section == indexPath.section)
&& (component.row == -1 || component.row == indexPath.row)) {
UICollectionViewCell *cell = [collectionView cellForItemAtIndexPath:indexPath];
[binding trackEvent:cell];
}
}
});
};
[FBSDKSwizzler swizzleSelector:@selector(collectionView:didSelectItemAtIndexPath:)
onClass:[delegate class]
withBlock:block
named:@"handle_collection_view"];
}
});
}
});
});
}
#pragma clang diagnostic pop
- (void)updateBindings:(NSArray *)bindings {
eventBindings = bindings;
[reactBindings removeAllObjects];
fb_dispatch_on_main_thread(^{
[self rematchBindings];
});
}
@end

View File

@ -1,38 +0,0 @@
// Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
//
// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,
// copy, modify, and distribute this software in source code or binary form for use
// in connection with the web services and APIs provided by Facebook.
//
// As with any software that integrates with the Facebook platform, your use of
// this software is subject to the Facebook Developer Principles and Policies
// [http://developers.facebook.com/policy/]. This copyright notice shall be
// included in all copies or substantial portions of the software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
@interface FBSDKViewHierarchy : NSObject
+ (NSObject *)getParent:(NSObject *)obj;
+ (NSArray<NSObject *> *)getChildren:(NSObject *)obj;
+ (NSArray<NSObject *> *)getPath:(NSObject *)obj;
+ (NSMutableDictionary<NSString *, id> *)getDetailAttributesOf:(NSObject *)obj;
+ (NSString *)getText:(NSObject *)obj;
+ (NSString *)getHint:(NSObject *)obj;
+ (NSIndexPath *)getIndexPath:(NSObject *)obj;
+ (NSUInteger)getClassBitmask:(NSObject *)obj;
+ (UITableView *)getParentTableView:(UIView *)cell;
+ (UICollectionView *)getParentCollectionView:(UIView *)cell;
+ (NSInteger)getTag:(NSObject *)obj;
+ (NSNumber *)getViewReactTag:(UIView *)view;
@end

View File

@ -1,616 +0,0 @@
// 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 "FBSDKViewHierarchy.h"
#import <objc/runtime.h>
#import <QuartzCore/QuartzCore.h>
#import "FBSDKCodelessMacros.h"
#import "FBSDKCodelessPathComponent.h"
#import "FBSDKCoreKit+Internal.h"
#define MAX_VIEW_HIERARCHY_LEVEL 35
typedef NS_ENUM(NSUInteger, FBCodelessClassBitmask) {
/*! Indicates that the class is subclass of UIControl */
FBCodelessClassBitmaskUIControl = 1 << 3,
/*! Indicates that the class is subclass of UIControl */
FBCodelessClassBitmaskUIButton = 1 << 4,
/*! Indicates that the class is ReactNative Button */
FBCodelessClassBitmaskReactNativeButton = 1 << 6,
/*! Indicates that the class is UITableViewCell */
FBCodelessClassBitmaskUITableViewCell = 1 << 7,
/*! Indicates that the class is UICollectionViewCell */
FBCodelessClassBitmaskUICollectionViewCell = 1 << 8,
/*! Indicates that the class is UILabel */
FBCodelessClassBitmaskLabel = 1 << 10,
/*! Indicates that the class is UITextView or UITextField*/
FBCodelessClassBitmaskInput = 1 << 11,
/*! Indicates that the class is UIPicker*/
FBCodelessClassBitmaskPicker = 1 << 12,
/*! Indicates that the class is UISwitch*/
FBCodelessClassBitmaskSwitch = 1 << 13,
/*! Indicates that the class is UIViewController*/
FBCodelessClassBitmaskUIViewController = 1 << 17,
};
@implementation FBSDKViewHierarchy
+ (NSArray*)getChildren:(NSObject*)obj
{
if ([obj isKindOfClass:[UIControl class]]) {
return nil;
}
NSMutableArray *children = [NSMutableArray array];
// children of window should be viewcontroller
if ([obj isKindOfClass:[UIWindow class]]) {
UIViewController *rootVC = ((UIWindow *)obj).rootViewController;
NSArray<UIView *> *subviews = ((UIWindow *)obj).subviews;
for (UIView *child in subviews) {
if (child != rootVC.view) {
UIViewController *vc = [FBSDKViewHierarchy getParentViewController:child];
if (vc != nil && vc.view == child) {
[children addObject:vc];
} else {
[children addObject:child];
}
} else {
if (rootVC) {
[children addObject:rootVC];
}
}
}
} else if ([obj isKindOfClass:[UIView class]]) {
NSArray<UIView *> *subviews = [((UIView *)obj).subviews copy];
for (UIView *child in subviews) {
UIViewController *vc = [FBSDKViewHierarchy getParentViewController:child];
if (vc && vc.view == child) {
[children addObject:vc];
} else {
[children addObject:child];
}
}
} else if ([obj isKindOfClass:[UINavigationController class]]) {
UIViewController *vc = ((UINavigationController*)obj).visibleViewController;
UIViewController *tc = ((UINavigationController*)obj).topViewController;
NSArray *nextChildren = [FBSDKViewHierarchy getChildren:((UIViewController*)obj).view];
for (NSObject *child in nextChildren) {
if (tc && [self isView:child superViewOfView:tc.view]) {
[children addObject:tc];
} else if (vc && [self isView:child superViewOfView:vc.view]) {
[children addObject:vc];
} else {
if (child != vc.view && child != tc.view) {
[children addObject:child];
} else {
if (vc && child == vc.view) {
[children addObject:vc];
} else if (tc && child == tc.view) {
[children addObject:tc];
}
}
}
}
if (vc && ![children containsObject:vc]) {
[children addObject:vc];
}
} else if ([obj isKindOfClass:[UITabBarController class]]) {
UIViewController *vc = ((UITabBarController *)obj).selectedViewController;
NSArray *nextChildren = [FBSDKViewHierarchy getChildren:((UIViewController*)obj).view];
for (NSObject *child in nextChildren) {
if (vc && [self isView:child superViewOfView:vc.view]) {
[children addObject:vc];
} else {
if (vc && child == vc.view) {
[children addObject:vc];
} else {
[children addObject:child];
}
}
}
if (vc && ![children containsObject:vc]) {
[children addObject:vc];
}
} else if ([obj isKindOfClass:[UIViewController class]]) {
UIViewController *vc = (UIViewController *)obj;
if (vc.isViewLoaded) {
NSArray *nextChildren = [FBSDKViewHierarchy getChildren:vc.view];
if (nextChildren.count > 0) {
[children addObjectsFromArray:nextChildren];
}
}
for (NSObject *child in vc.childViewControllers) {
[children addObject:child];
}
UIViewController *presentedVC = vc.presentedViewController;
if (presentedVC) {
[children addObject:presentedVC];
}
}
return children;
}
+ (NSObject *)getParent:(NSObject *)obj
{
if ([obj isKindOfClass:[UIView class]]) {
UIView *superview = ((UIView *)obj).superview;
UIViewController *superviewViewController = [FBSDKViewHierarchy
getParentViewController:superview];
if (superviewViewController && superviewViewController.view == superview) {
return superviewViewController;
}
if (superview && superview != obj) {
return superview;
}
}
else if ([obj isKindOfClass:[UIViewController class]]) {
UIViewController *vc = (UIViewController *)obj;
UIViewController *parentVC = vc.parentViewController;
UIViewController *presentingVC = vc.presentingViewController;
UINavigationController *nav = vc.navigationController;
UITabBarController *tab = vc.tabBarController;
if (nav) {
return nav;
}
if (tab) {
return tab;
}
if (parentVC) {
return parentVC;
}
if (presentingVC && presentingVC.presentedViewController == vc) {
return presentingVC;
}
// Return parent of view of UIViewController
NSObject *viewParent = [FBSDKViewHierarchy getParent:vc.view];
if (viewParent) {
return viewParent;
}
}
return nil;
}
+ (NSArray *)getPath:(NSObject *)obj
{
return [FBSDKViewHierarchy getPath:obj limit:MAX_VIEW_HIERARCHY_LEVEL];
}
+ (NSArray *)getPath:(NSObject *)obj limit:(int)limit
{
if (!obj || limit <= 0) {
return nil;
}
NSMutableArray *path;
NSObject *parent = [FBSDKViewHierarchy getParent:obj];
if (parent) {
NSArray *parentPath = [FBSDKViewHierarchy getPath:parent limit:limit - 1];
path = [NSMutableArray arrayWithArray:parentPath];
} else {
path = [NSMutableArray array];
}
NSDictionary *componentInfo = [FBSDKViewHierarchy getAttributesOf:obj parent:parent];
FBSDKCodelessPathComponent *pathComponent = [[FBSDKCodelessPathComponent alloc]
initWithJSON:componentInfo];
[path addObject:pathComponent];
return [NSArray arrayWithArray:path];
}
+ (NSDictionary<NSString *, id> *)getAttributesOf:(NSObject *)obj parent:(NSObject *)parent
{
NSMutableDictionary *componentInfo = [NSMutableDictionary dictionary];
componentInfo[CODELESS_MAPPING_CLASS_NAME_KEY] = NSStringFromClass([obj class]);
NSString *text = [FBSDKViewHierarchy getText:obj];
if (text) {
componentInfo[CODELESS_MAPPING_TEXT_KEY] = text;
}
NSString *hint = [FBSDKViewHierarchy getHint:obj];
if (hint) {
componentInfo[CODELESS_MAPPING_HINT_KEY] = hint;
}
NSIndexPath *indexPath = [FBSDKViewHierarchy getIndexPath:obj];
if (indexPath) {
componentInfo[CODELESS_MAPPING_SECTION_KEY] = @(indexPath.section);
componentInfo[CODELESS_MAPPING_ROW_KEY] = @(indexPath.row);
}
if (parent != nil) {
NSArray *children = [FBSDKViewHierarchy getChildren:parent];
NSUInteger index = [children indexOfObject:obj];
if (index != NSNotFound) {
componentInfo[CODELESS_MAPPING_INDEX_KEY] = @(index);
}
} else {
componentInfo[CODELESS_MAPPING_INDEX_KEY] = @0;
}
componentInfo[CODELESS_VIEW_TREE_TAG_KEY] = @([FBSDKViewHierarchy getTag:obj]);
return [componentInfo copy];
}
+ (NSMutableDictionary<NSString *, id> *)getDetailAttributesOf:(NSObject *)obj
{
if (!obj) {
return nil;
}
NSObject *parent = [FBSDKViewHierarchy getParent:obj];
NSDictionary *simpleAttributes = [FBSDKViewHierarchy getAttributesOf:obj parent:parent];
NSMutableDictionary *result = [NSMutableDictionary dictionaryWithDictionary:simpleAttributes];
NSString *className = NSStringFromClass([obj class]);
result[CODELESS_VIEW_TREE_CLASS_NAME_KEY] = className;
NSUInteger classBitmask = [FBSDKViewHierarchy getClassBitmask:obj];
result[CODELESS_VIEW_TREE_CLASS_TYPE_BIT_MASK_KEY] = [NSString stringWithFormat:@"%lu", (unsigned long)classBitmask];
if ([obj isKindOfClass:[UIControl class]]) {
// Get actions of UIControl
UIControl *control = (UIControl *)obj;
NSMutableSet *actions = [NSMutableSet set];
NSSet *targets = control.allTargets;
for (NSObject *target in targets) {
NSArray *ary = [control actionsForTarget:target forControlEvent:0];
if (ary.count > 0) {
[actions addObjectsFromArray:ary];
}
}
if (targets.count > 0) {
result[CODELESS_VIEW_TREE_ACTIONS_KEY] = actions.allObjects;
}
}
result[CODELESS_VIEW_TREE_DIMENSION_KEY] = [FBSDKViewHierarchy getDimensionOf:obj];
NSDictionary<NSString *, id> *textStyle = [FBSDKViewHierarchy getTextStyle:obj];
if (textStyle) {
result[CODELESS_VIEW_TREE_TEXT_STYLE_KEY] = textStyle;
}
return result;
}
+ (NSIndexPath *)getIndexPath:(NSObject *)obj
{
NSIndexPath *indexPath = nil;
if ([obj isKindOfClass:[UITableViewCell class]]) {
UITableView *tableView = [FBSDKViewHierarchy getParentTableView:(UIView *)obj];
indexPath = [tableView indexPathForCell:(UITableViewCell *)obj];
} else if ([obj isKindOfClass:[UICollectionViewCell class]]) {
UICollectionView *collectionView = [FBSDKViewHierarchy getParentCollectionView:(UIView *)obj];
indexPath = [collectionView indexPathForCell:(UICollectionViewCell *)obj];
}
return indexPath;
}
+ (NSString *)getText:(NSObject *)obj
{
NSString *text = nil;
if ([obj isKindOfClass:[UIButton class]]) {
text = ((UIButton *)obj).currentTitle;
} else if ([obj isKindOfClass:[UITextView class]] ||
[obj isKindOfClass:[UITextField class]] ||
[obj isKindOfClass:[UILabel class]]) {
text = ((UILabel *)obj).text;
} else if ([obj isKindOfClass:[UIPickerView class]]) {
UIPickerView *picker = (UIPickerView *)obj;
NSInteger sections = picker.numberOfComponents;
NSMutableArray *titles = [NSMutableArray array];
for (NSInteger i = 0; i < sections; i++) {
NSInteger row = [picker selectedRowInComponent:i];
NSString *title;
if ([picker.delegate
respondsToSelector:@selector(pickerView:titleForRow:forComponent:)]) {
title = [picker.delegate pickerView:picker titleForRow:row forComponent:i];
} else if ([picker.delegate
respondsToSelector:@selector(pickerView:attributedTitleForRow:forComponent:)]) {
title = [picker.delegate
pickerView:picker
attributedTitleForRow:row forComponent:i].string;
}
[titles addObject:title ?: @""];
}
if (titles.count > 0) {
text = [FBSDKInternalUtility JSONStringForObject:titles
error:NULL
invalidObjectHandler:NULL];
}
} else if ([obj isKindOfClass:[UIDatePicker class]]) {
UIDatePicker *picker = (UIDatePicker *)obj;
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
formatter.dateFormat = @"yyyy-MM-dd HH:mm:ssZ";
text = [formatter stringFromDate:picker.date];
} else if ([obj isKindOfClass:objc_lookUpClass("RCTTextView")]) {
NSTextStorage *textStorage = [FBSDKAppEventsUtility getVariable:@"_textStorage"
fromInstance:obj];
if (textStorage) {
text = textStorage.string;
}
} else if ([obj isKindOfClass:objc_lookUpClass("RCTBaseTextInputView")]) {
NSAttributedString *attributedText = [FBSDKAppEventsUtility getVariable:@"attributedText"
fromInstance:obj];
text = attributedText.string;
}
if ([obj conformsToProtocol:@protocol(UITextInput)]) {
id<UITextInput> input = (id<UITextInput>)obj;
if (input.secureTextEntry) {
text = nil;
} else {
switch (input.keyboardType) {
case UIKeyboardTypePhonePad:
case UIKeyboardTypeEmailAddress:
text = nil;
break;
default: break;
}
}
}
if ([FBSDKAppEventsUtility isSensitiveUserData:text]) {
return nil;
}
return text.length > 0 ? text : nil;
}
+ (NSDictionary<NSString *, id> *)getTextStyle:(NSObject *)obj
{
UIFont *font = nil;
if ([obj isKindOfClass:[UIButton class]]) {
font = ((UIButton *)obj).titleLabel.font;
} else if ([obj isKindOfClass:[UILabel class]]) {
font = ((UILabel *)obj).font;
} else if ([obj isKindOfClass:[UITextField class]]) {
font = ((UITextField *)obj).font;
} else if ([obj isKindOfClass:[UITextView class]]) {
font = ((UITextView *)obj).font;
}
if (font) {
UIFontDescriptorSymbolicTraits traits = font.fontDescriptor.symbolicTraits;
BOOL isBold = (traits & UIFontDescriptorTraitBold) != 0;
BOOL isItalic = (traits & UIFontDescriptorTraitItalic) != 0;
CGFloat fontSize = font.pointSize;
return @{
CODELESS_VIEW_TREE_TEXT_IS_BOLD_KEY: @(isBold),
CODELESS_VIEW_TREE_TEXT_IS_ITALIC_KEY: @(isItalic),
CODELESS_VIEW_TREE_TEXT_SIZE_KEY: @(fontSize)
};
}
return nil;
}
+ (NSString *)getHint:(NSObject *)obj
{
NSString *hint = nil;
if ([obj isKindOfClass:[UITextField class]]) {
hint = ((UITextField *)obj).placeholder;
} else if ([obj isKindOfClass:[UINavigationController class]]) {
UIViewController *top = ((UINavigationController *)obj).topViewController;
if (top) {
hint = NSStringFromClass([top class]);
}
}
return hint.length > 0 ? hint : nil;
}
+ (NSUInteger)getClassBitmask:(NSObject *)obj
{
NSUInteger bitmask = 0;
if ([obj isKindOfClass:[UIView class]]) {
if ([obj isKindOfClass:[UIControl class]]) {
bitmask |= FBCodelessClassBitmaskUIControl;
if ([obj isKindOfClass:[UIButton class]]) {
bitmask |= FBCodelessClassBitmaskUIButton;
} else if ([obj isKindOfClass:[UISwitch class]]) {
bitmask |= FBCodelessClassBitmaskSwitch;
}else if ([obj isKindOfClass:[UIDatePicker class]]) {
bitmask |= FBCodelessClassBitmaskPicker;
}
} else if ([obj isKindOfClass:[UITableViewCell class]]) {
bitmask |= FBCodelessClassBitmaskUITableViewCell;
} else if ([obj isKindOfClass:[UICollectionViewCell class]]) {
bitmask |= FBCodelessClassBitmaskUICollectionViewCell;
} else if ([obj isKindOfClass:[UIPickerView class]]) {
bitmask |= FBCodelessClassBitmaskPicker;
} else if ([obj isKindOfClass:[UILabel class]]) {
bitmask |= FBCodelessClassBitmaskLabel;
}
if ([FBSDKViewHierarchy isRCTButton:((UIView *)obj)]) {
bitmask |= FBCodelessClassBitmaskReactNativeButton;
}
// Check selector of UITextInput protocol instead of checking conformsToProtocol
if ([obj respondsToSelector:@selector(textInRange:)]) {
bitmask |= FBCodelessClassBitmaskInput;
}
} else if ([obj isKindOfClass:[UIViewController class]]) {
bitmask |= FBCodelessClassBitmaskUIViewController;
}
return bitmask;
}
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wundeclared-selector"
+ (BOOL)isRCTButton:(UIView *)view
{
if (view == nil) {
return NO;
}
Class classRCTView = objc_lookUpClass(ReactNativeClassRCTView);
if (classRCTView && [view isKindOfClass:classRCTView] &&
[view respondsToSelector:@selector(reactTagAtPoint:)] &&
[view respondsToSelector:@selector(reactTag)] &&
view.userInteractionEnabled) {
NSNumber *reactTag = [view performSelector:@selector(reactTagAtPoint:)
withObject:[NSValue valueWithCGPoint:view.frame.origin]];
// We get the reactTag at upper left of the view and thus check with its first subview
UIView *subView = view.subviews.firstObject;
NSNumber *subViewReactTag = [FBSDKViewHierarchy getViewReactTag:subView];
if (reactTag != nil && subViewReactTag != nil && ![subView isKindOfClass:classRCTView] && [reactTag isEqualToNumber:subViewReactTag]) {
return YES;
}
}
return NO;
}
+ (NSNumber *)getViewReactTag:(UIView *)view
{
if (view != nil && [view respondsToSelector:@selector(reactTag)]) {
NSNumber *reactTag = [view performSelector:@selector(reactTag)];
if (reactTag != nil && [reactTag isKindOfClass:[NSNumber class]]) {
return reactTag;
}
}
return nil;
}
#pragma clang diagnostic pop
+ (BOOL)isView:(NSObject *)obj1 superViewOfView:(UIView *)obj2
{
if (![obj1 isKindOfClass:[UIView class]]
|| ![obj2 isKindOfClass:[UIView class]]) {
return NO;
}
UIView *view1 = (UIView *)obj1;
UIView *view2 = (UIView *)obj2;
UIView *superview = view2;
while (superview) {
superview = superview.superview;
if (superview == view1) {
return YES;
}
}
return NO;
}
+ (UIViewController *)getParentViewController:(UIView *)view
{
UIResponder *parentResponder = view;
while (parentResponder) {
parentResponder = parentResponder.nextResponder;
if ([parentResponder isKindOfClass:[UIViewController class]]) {
return (UIViewController *)parentResponder;
}
}
return nil;
}
+ (UITableView *)getParentTableView:(UIView *)cell
{
UIView *superview = cell.superview;
while (superview) {
if ([superview isKindOfClass:[UITableView class]]) {
return (UITableView *)superview;
}
superview = superview.superview;
}
return nil;
}
+ (UICollectionView *)getParentCollectionView:(UIView *)cell
{
UIView *superview = cell.superview;
while (superview) {
if ([superview isKindOfClass:[UICollectionView class]]) {
return (UICollectionView *)superview;
}
superview = superview.superview;
}
return nil;
}
+ (NSInteger)getTag:(NSObject *)obj
{
if ([obj isKindOfClass:[UIView class]]) {
return ((UIView *)obj).tag;
} else if ([obj isKindOfClass:[UIViewController class]]) {
return ((UIViewController *)obj).view.tag;
}
return 0;
}
+ (NSDictionary<NSString *, NSNumber *> *)getDimensionOf:(NSObject *)obj
{
UIView *view = nil;
if ([obj isKindOfClass:[UIView class]]) {
view = (UIView *)obj;
} else if ([obj isKindOfClass:[UIViewController class]]) {
view = ((UIViewController *)obj).view;
}
CGRect frame = view.frame;
CGPoint offset = CGPointZero;
if ([view isKindOfClass:[UIScrollView class]])
offset = ((UIScrollView *)view).contentOffset;
return @{
CODELESS_VIEW_TREE_TOP_KEY: @((int)frame.origin.y),
CODELESS_VIEW_TREE_LEFT_KEY: @((int)frame.origin.x),
CODELESS_VIEW_TREE_WIDTH_KEY: @((int)frame.size.width),
CODELESS_VIEW_TREE_HEIGHT_KEY: @((int)frame.size.height),
CODELESS_VIEW_TREE_OFFSET_X_KEY: @((int)offset.x),
CODELESS_VIEW_TREE_OFFSET_Y_KEY: @((int)offset.y),
CODELESS_VIEW_TREE_VISIBILITY_KEY: view.isHidden ? @4 : @0
};
}
@end

View File

@ -17,6 +17,7 @@
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#import <FBSDKCoreKit/FBSDKAppEvents.h>
#import <FBSDKCoreKit/FBSDKMacros.h>
#import "FBSDKAppEventsUtility.h"
@ -24,178 +25,147 @@
// Internally known event names
FOUNDATION_EXPORT NSString *const FBSDKAppEventNamePurchased;
FBSDK_EXTERN NSString *const FBSDKAppEventNamePurchased;
/** Use to log that the share dialog was launched */
FOUNDATION_EXPORT NSString *const FBSDKAppEventNameShareSheetLaunch;
FBSDK_EXTERN NSString *const FBSDKAppEventNameShareSheetLaunch;
/** Use to log that the share dialog was dismissed */
FOUNDATION_EXPORT NSString *const FBSDKAppEventNameShareSheetDismiss;
FBSDK_EXTERN NSString *const FBSDKAppEventNameShareSheetDismiss;
/** Use to log that the permissions UI was launched */
FOUNDATION_EXPORT NSString *const FBSDKAppEventNamePermissionsUILaunch;
FBSDK_EXTERN NSString *const FBSDKAppEventNamePermissionsUILaunch;
/** Use to log that the permissions UI was dismissed */
FOUNDATION_EXPORT NSString *const FBSDKAppEventNamePermissionsUIDismiss;
FBSDK_EXTERN NSString *const FBSDKAppEventNamePermissionsUIDismiss;
/** Use to log that the login view was used */
FOUNDATION_EXPORT NSString *const FBSDKAppEventNameLoginViewUsage;
FBSDK_EXTERN NSString *const FBSDKAppEventNameLoginViewUsage;
/*! Use to log that the share tray launched. */
FOUNDATION_EXPORT NSString *const FBSDKAppEventNameShareTrayDidLaunch;
FBSDK_EXTERN NSString *const FBSDKAppEventNameShareTrayDidLaunch;
/*! Use to log that the person selected a sharing target. */
FOUNDATION_EXPORT NSString *const FBSDKAppEventNameShareTrayDidSelectActivity;
FBSDK_EXTERN NSString *const FBSDKAppEventNameShareTrayDidSelectActivity;
// Internally known event parameters
/** String parameter specifying the outcome of a dialog invocation */
FOUNDATION_EXPORT NSString *const FBSDKAppEventParameterDialogOutcome;
FBSDK_EXTERN NSString *const FBSDKAppEventParameterDialogOutcome;
/** Parameter key used to specify which application launches this application. */
FOUNDATION_EXPORT NSString *const FBSDKAppEventParameterLaunchSource;
FBSDK_EXTERN NSString *const FBSDKAppEventParameterLaunchSource;
/** Use to log the result of a call to FBDialogs presentShareDialogWithParams: */
FOUNDATION_EXPORT NSString *const FBSDKAppEventNameFBDialogsPresentShareDialog;
FBSDK_EXTERN NSString *const FBSDKAppEventNameFBDialogsPresentShareDialog;
/** Use to log the result of a call to FBDialogs presentShareDialogWithOpenGraphActionParams: */
FOUNDATION_EXPORT NSString *const FBSDKAppEventNameFBDialogsPresentShareDialogOG;
FBSDK_EXTERN NSString *const FBSDKAppEventNameFBDialogsPresentShareDialogOG;
/** Use to log the result of a call to FBDialogs presentLikeDialogWithLikeParams: */
FOUNDATION_EXPORT NSString *const FBSDKAppEventNameFBDialogsPresentLikeDialogOG;
FBSDK_EXTERN NSString *const FBSDKAppEventNameFBDialogsPresentLikeDialogOG;
FOUNDATION_EXPORT NSString *const FBSDKAppEventNameFBDialogsPresentShareDialogPhoto;
FOUNDATION_EXPORT NSString *const FBSDKAppEventNameFBDialogsPresentMessageDialog;
FOUNDATION_EXPORT NSString *const FBSDKAppEventNameFBDialogsPresentMessageDialogPhoto;
FOUNDATION_EXPORT NSString *const FBSDKAppEventNameFBDialogsPresentMessageDialogOG;
FBSDK_EXTERN NSString *const FBSDKAppEventNameFBDialogsPresentShareDialogPhoto;
FBSDK_EXTERN NSString *const FBSDKAppEventNameFBDialogsPresentMessageDialog;
FBSDK_EXTERN NSString *const FBSDKAppEventNameFBDialogsPresentMessageDialogPhoto;
FBSDK_EXTERN NSString *const FBSDKAppEventNameFBDialogsPresentMessageDialogOG;
/** Use to log the start of an auth request that cannot be fulfilled by the token cache */
FOUNDATION_EXPORT NSString *const FBSDKAppEventNameFBSessionAuthStart;
FBSDK_EXTERN NSString *const FBSDKAppEventNameFBSessionAuthStart;
/** Use to log the end of an auth request that was not fulfilled by the token cache */
FOUNDATION_EXPORT NSString *const FBSDKAppEventNameFBSessionAuthEnd;
FBSDK_EXTERN NSString *const FBSDKAppEventNameFBSessionAuthEnd;
/** Use to log the start of a specific auth method as part of an auth request */
FOUNDATION_EXPORT NSString *const FBSDKAppEventNameFBSessionAuthMethodStart;
FBSDK_EXTERN NSString *const FBSDKAppEventNameFBSessionAuthMethodStart;
/** Use to log the end of the last tried auth method as part of an auth request */
FOUNDATION_EXPORT NSString *const FBSDKAppEventNameFBSessionAuthMethodEnd;
FBSDK_EXTERN NSString *const FBSDKAppEventNameFBSessionAuthMethodEnd;
/** Use to log the timestamp for the transition to the Facebook native login dialog */
FOUNDATION_EXPORT NSString *const FBSDKAppEventNameFBDialogsNativeLoginDialogStart;
FBSDK_EXTERN NSString *const FBSDKAppEventNameFBDialogsNativeLoginDialogStart;
/** Use to log the timestamp for the transition back to the app after the Facebook native login dialog */
FOUNDATION_EXPORT NSString *const FBSDKAppEventNameFBDialogsNativeLoginDialogEnd;
FBSDK_EXTERN NSString *const FBSDKAppEventNameFBDialogsNativeLoginDialogEnd;
/** Use to log the e2e timestamp metrics for web login */
FOUNDATION_EXPORT NSString *const FBSDKAppEventNameFBDialogsWebLoginCompleted;
FBSDK_EXTERN NSString *const FBSDKAppEventNameFBDialogsWebLoginCompleted;
/** Use to log the result of the App Switch OS AlertView. Only available on OS >= iOS10 */
FOUNDATION_EXPORT NSString *const FBSDKAppEventNameFBSessionFASLoginDialogResult;
/** Use to log the live streaming events from sdk */
FOUNDATION_EXPORT NSString *const FBSDKAppEventNameFBSDKLiveStreamingStart;
FOUNDATION_EXPORT NSString *const FBSDKAppEventNameFBSDKLiveStreamingStop;
FOUNDATION_EXPORT NSString *const FBSDKAppEventNameFBSDKLiveStreamingPause;
FOUNDATION_EXPORT NSString *const FBSDKAppEventNameFBSDKLiveStreamingResume;
FOUNDATION_EXPORT NSString *const FBSDKAppEventNameFBSDKLiveStreamingError;
FOUNDATION_EXPORT NSString *const FBSDKAppEventNameFBSDKLiveStreamingUpdateStatus;
FOUNDATION_EXPORT NSString *const FBSDKAppEventNameFBSDKLiveStreamingVideoID;
FOUNDATION_EXPORT NSString *const FBSDKAppEventNameFBSDKLiveStreamingMic;
FOUNDATION_EXPORT NSString *const FBSDKAppEventNameFBSDKLiveStreamingCamera;
FBSDK_EXTERN NSString *const FBSDKAppEventNameFBSessionFASLoginDialogResult;
/** Use to log the results of a share dialog */
FOUNDATION_EXPORT NSString *const FBSDLAppEventNameFBSDKEventShareDialogResult;
FOUNDATION_EXPORT NSString *const FBSDKAppEventNameFBSDKEventMessengerShareDialogResult;
FOUNDATION_EXPORT NSString *const FBSDKAppEventNameFBSDKEventAppInviteShareDialogResult;
FBSDK_EXTERN NSString *const FBSDLAppEventNameFBSDKEventShareDialogResult;
FBSDK_EXTERN NSString *const FBSDKAppEventNameFBSDKEventMessengerShareDialogResult;
FBSDK_EXTERN NSString *const FBSDKAppEventNameFBSDKEventAppInviteShareDialogResult;
FOUNDATION_EXPORT NSString *const FBSDKAppEventNameFBSDKEventShareDialogShow;
FOUNDATION_EXPORT NSString *const FBSDKAppEventNameFBSDKEventMessengerShareDialogShow;
FOUNDATION_EXPORT NSString *const FBSDKAppEventNameFBSDKEventAppInviteShareDialogShow;
FBSDK_EXTERN NSString *const FBSDKAppEventNameFBSDKEventShareDialogShow;
FBSDK_EXTERN NSString *const FBSDKAppEventNameFBSDKEventMessengerShareDialogShow;
FBSDK_EXTERN NSString *const FBSDKAppEventNameFBSDKEventAppInviteShareDialogShow;
FOUNDATION_EXPORT NSString *const FBSDKAppEventParameterDialogMode;
FOUNDATION_EXPORT NSString *const FBSDKAppEventParameterDialogShareContentType;
FOUNDATION_EXPORT NSString *const FBSDKAppEventParameterDialogShareContentUUID;
FOUNDATION_EXPORT NSString *const FBSDKAppEventParameterDialogShareContentPageID;
FBSDK_EXTERN NSString *const FBSDKAppEventParameterDialogMode;
FBSDK_EXTERN NSString *const FBSDKAppEventParameterDialogShareContentType;
FBSDK_EXTERN NSString *const FBSDKAppEventParameterDialogShareContentUUID;
FBSDK_EXTERN NSString *const FBSDKAppEventParameterDialogShareContentPageID;
/*! Use to log parameters for share tray use */
FOUNDATION_EXPORT NSString *const FBSDKAppEventParameterShareTrayActivityName;
FOUNDATION_EXPORT NSString *const FBSDKAppEventParameterShareTrayResult;
/*! Use to log parameters for live streaming*/
FOUNDATION_EXPORT NSString *const FBSDKAppEventParameterLiveStreamingPrevStatus;
FOUNDATION_EXPORT NSString *const FBSDKAppEventParameterLiveStreamingStatus;
FOUNDATION_EXPORT NSString *const FBSDKAppEventParameterLiveStreamingError;
FOUNDATION_EXPORT NSString *const FBSDKAppEventParameterLiveStreamingVideoID;
FOUNDATION_EXPORT NSString *const FBSDKAppEventParameterLiveStreamingMicEnabled;
FOUNDATION_EXPORT NSString *const FBSDKAppEventParameterLiveStreamingCameraEnabled;
FBSDK_EXTERN NSString *const FBSDKAppEventParameterShareTrayActivityName;
FBSDK_EXTERN NSString *const FBSDKAppEventParameterShareTrayResult;
// Internally known event parameter values
FOUNDATION_EXPORT NSString *const FBSDKAppEventsDialogOutcomeValue_Completed;
FOUNDATION_EXPORT NSString *const FBSDKAppEventsDialogOutcomeValue_Cancelled;
FOUNDATION_EXPORT NSString *const FBSDKAppEventsDialogOutcomeValue_Failed;
FBSDK_EXTERN NSString *const FBSDKAppEventsDialogOutcomeValue_Completed;
FBSDK_EXTERN NSString *const FBSDKAppEventsDialogOutcomeValue_Cancelled;
FBSDK_EXTERN NSString *const FBSDKAppEventsDialogOutcomeValue_Failed;
FOUNDATION_EXPORT NSString *const FBSDKAppEventsDialogShareContentTypeOpenGraph;
FOUNDATION_EXPORT NSString *const FBSDKAppEventsDialogShareContentTypeStatus;
FOUNDATION_EXPORT NSString *const FBSDKAppEventsDialogShareContentTypePhoto;
FOUNDATION_EXPORT NSString *const FBSDKAppEventsDialogShareContentTypeVideo;
FOUNDATION_EXPORT NSString *const FBSDKAppEventsDialogShareContentTypeCamera;
FOUNDATION_EXPORT NSString *const FBSDKAppEventsDialogShareContentTypeMessengerGenericTemplate;
FOUNDATION_EXPORT NSString *const FBSDKAppEventsDialogShareContentTypeMessengerMediaTemplate;
FOUNDATION_EXPORT NSString *const FBSDKAppEventsDialogShareContentTypeMessengerOpenGraphMusicTemplate;
FOUNDATION_EXPORT NSString *const FBSDKAppEventsDialogShareContentTypeUnknown;
FBSDK_EXTERN NSString *const FBSDKAppEventsDialogShareContentTypeOpenGraph;
FBSDK_EXTERN NSString *const FBSDKAppEventsDialogShareContentTypeStatus;
FBSDK_EXTERN NSString *const FBSDKAppEventsDialogShareContentTypePhoto;
FBSDK_EXTERN NSString *const FBSDKAppEventsDialogShareContentTypeVideo;
FBSDK_EXTERN NSString *const FBSDKAppEventsDialogShareContentTypeCamera;
FBSDK_EXTERN NSString *const FBSDKAppEventsDialogShareContentTypeMessengerGenericTemplate;
FBSDK_EXTERN NSString *const FBSDKAppEventsDialogShareContentTypeMessengerMediaTemplate;
FBSDK_EXTERN NSString *const FBSDKAppEventsDialogShareContentTypeMessengerOpenGraphMusicTemplate;
FBSDK_EXTERN NSString *const FBSDKAppEventsDialogShareContentTypeUnknown;
FOUNDATION_EXPORT NSString *const FBSDKAppEventsDialogShareModeAutomatic;
FOUNDATION_EXPORT NSString *const FBSDKAppEventsDialogShareModeBrowser;
FOUNDATION_EXPORT NSString *const FBSDKAppEventsDialogShareModeNative;
FOUNDATION_EXPORT NSString *const FBSDKAppEventsDialogShareModeShareSheet;
FOUNDATION_EXPORT NSString *const FBSDKAppEventsDialogShareModeWeb;
FOUNDATION_EXPORT NSString *const FBSDKAppEventsDialogShareModeFeedBrowser;
FOUNDATION_EXPORT NSString *const FBSDKAppEventsDialogShareModeFeedWeb;
FOUNDATION_EXPORT NSString *const FBSDKAppEventsDialogShareModeUnknown;
FBSDK_EXTERN NSString *const FBSDKAppEventsDialogShareModeAutomatic;
FBSDK_EXTERN NSString *const FBSDKAppEventsDialogShareModeBrowser;
FBSDK_EXTERN NSString *const FBSDKAppEventsDialogShareModeNative;
FBSDK_EXTERN NSString *const FBSDKAppEventsDialogShareModeShareSheet;
FBSDK_EXTERN NSString *const FBSDKAppEventsDialogShareModeWeb;
FBSDK_EXTERN NSString *const FBSDKAppEventsDialogShareModeFeedBrowser;
FBSDK_EXTERN NSString *const FBSDKAppEventsDialogShareModeFeedWeb;
FBSDK_EXTERN NSString *const FBSDKAppEventsDialogShareModeUnknown;
FOUNDATION_EXPORT NSString *const FBSDKAppEventsNativeLoginDialogStartTime;
FOUNDATION_EXPORT NSString *const FBSDKAppEventsNativeLoginDialogEndTime;
FBSDK_EXTERN NSString *const FBSDKAppEventsNativeLoginDialogStartTime;
FBSDK_EXTERN NSString *const FBSDKAppEventsNativeLoginDialogEndTime;
FOUNDATION_EXPORT NSString *const FBSDKAppEventsWebLoginE2E;
FBSDK_EXTERN NSString *const FBSDKAppEventsWebLoginE2E;
FOUNDATION_EXPORT NSString *const FBSDKAppEventNameFBSDKLikeButtonImpression;
FOUNDATION_EXPORT NSString *const FBSDKAppEventNameFBSDKLoginButtonImpression;
FOUNDATION_EXPORT NSString *const FBSDKAppEventNameFBSDKSendButtonImpression;
FOUNDATION_EXPORT NSString *const FBSDKAppEventNameFBSDKShareButtonImpression;
FOUNDATION_EXPORT NSString *const FBSDKAppEventNameFBSDKLiveStreamingButtonImpression;
FBSDK_EXTERN NSString *const FBSDKAppEventNameFBSDKLikeButtonImpression;
FBSDK_EXTERN NSString *const FBSDKAppEventNameFBSDKLoginButtonImpression;
FBSDK_EXTERN NSString *const FBSDKAppEventNameFBSDKSendButtonImpression;
FBSDK_EXTERN NSString *const FBSDKAppEventNameFBSDKShareButtonImpression;
FOUNDATION_EXPORT NSString *const FBSDKAppEventNameFBSDKSmartLoginService;
FBSDK_EXTERN NSString *const FBSDKAppEventNameFBSDKSmartLoginService;
FOUNDATION_EXPORT NSString *const FBSDKAppEventNameFBSDKLikeButtonDidTap;
FOUNDATION_EXPORT NSString *const FBSDKAppEventNameFBSDKLoginButtonDidTap;
FOUNDATION_EXPORT NSString *const FBSDKAppEventNameFBSDKSendButtonDidTap;
FOUNDATION_EXPORT NSString *const FBSDKAppEventNameFBSDKShareButtonDidTap;
FOUNDATION_EXPORT NSString *const FBSDKAppEventNameFBSDKLiveStreamingButtonDidTap;
FBSDK_EXTERN NSString *const FBSDKAppEventNameFBSDKLikeButtonDidTap;
FBSDK_EXTERN NSString *const FBSDKAppEventNameFBSDKLoginButtonDidTap;
FBSDK_EXTERN NSString *const FBSDKAppEventNameFBSDKSendButtonDidTap;
FBSDK_EXTERN NSString *const FBSDKAppEventNameFBSDKShareButtonDidTap;
FOUNDATION_EXPORT NSString *const FBSDKAppEventNameFBSDKLikeControlDidDisable;
FOUNDATION_EXPORT NSString *const FBSDKAppEventNameFBSDKLikeControlDidLike;
FOUNDATION_EXPORT NSString *const FBSDKAppEventNameFBSDKLikeControlDidPresentDialog;
FOUNDATION_EXPORT NSString *const FBSDKAppEventNameFBSDKLikeControlDidTap;
FOUNDATION_EXPORT NSString *const FBSDKAppEventNameFBSDKLikeControlDidUnlike;
FOUNDATION_EXPORT NSString *const FBSDKAppEventNameFBSDKLikeControlError;
FOUNDATION_EXPORT NSString *const FBSDKAppEventNameFBSDKLikeControlImpression;
FOUNDATION_EXPORT NSString *const FBSDKAppEventNameFBSDKLikeControlNetworkUnavailable;
FBSDK_EXTERN NSString *const FBSDKAppEventNameFBSDKLikeControlDidDisable;
FBSDK_EXTERN NSString *const FBSDKAppEventNameFBSDKLikeControlDidLike;
FBSDK_EXTERN NSString *const FBSDKAppEventNameFBSDKLikeControlDidPresentDialog;
FBSDK_EXTERN NSString *const FBSDKAppEventNameFBSDKLikeControlDidTap;
FBSDK_EXTERN NSString *const FBSDKAppEventNameFBSDKLikeControlDidUnlike;
FBSDK_EXTERN NSString *const FBSDKAppEventNameFBSDKLikeControlError;
FBSDK_EXTERN NSString *const FBSDKAppEventNameFBSDKLikeControlImpression;
FBSDK_EXTERN NSString *const FBSDKAppEventNameFBSDKLikeControlNetworkUnavailable;
FOUNDATION_EXPORT NSString *const FBSDKAppEventParameterDialogErrorMessage;
FOUNDATION_EXPORT NSString *const FBSDKAppEventParameterLogTime;
FOUNDATION_EXPORT NSString *const FBSDKAppEventsWKWebViewMessagesHandlerKey;
FOUNDATION_EXPORT NSString *const FBSDKAppEventsWKWebViewMessagesActionKey;
FOUNDATION_EXPORT NSString *const FBSDKAppEventsWKWebViewMessagesEventKey;
FOUNDATION_EXPORT NSString *const FBSDKAppEventsWKWebViewMessagesParamsKey;
FOUNDATION_EXPORT NSString *const FBSDKAppEventsWKWebViewMessagesPixelTrackKey;
FOUNDATION_EXPORT NSString *const FBSDKAppEventsWKWebViewMessagesPixelTrackCustomKey;
FOUNDATION_EXPORT NSString *const FBSDKAppEventsWKWebViewMessagesPixelTrackSingleKey;
FOUNDATION_EXPORT NSString *const FBSDKAppEventsWKWebViewMessagesPixelTrackSingleCustomKey;
FOUNDATION_EXPORT NSString *const FBSDKAppEventsWKWebViewMessagesPixelIDKey;
FBSDK_EXTERN NSString *const FBSDKAppEventParameterDialogErrorMessage;
FBSDK_EXTERN NSString *const FBSDKAppEventParameterLogTime;
@interface FBSDKAppEvents (Internal)
@ -206,6 +176,5 @@ FOUNDATION_EXPORT NSString *const FBSDKAppEventsWKWebViewMessagesPixelIDKey;
+ (FBSDKAppEvents *)singleton;
- (void)flushForReason:(FBSDKAppEventsFlushReason)flushReason;
- (void)registerNotifications;
@end

View File

@ -147,7 +147,7 @@ static const u_int FB_GIGABYTE = 1024 * 1024 * 1024; // bytes
_shortVersion = [mainBundle objectForInfoDictionaryKey:@"CFBundleShortVersionString"];
// Locale stuff
_language = [NSLocale currentLocale].localeIdentifier;
_language = [[NSLocale currentLocale] localeIdentifier];
// Device stuff
UIDevice *device = [UIDevice currentDevice];
@ -165,7 +165,7 @@ static const u_int FB_GIGABYTE = 1024 * 1024 * 1024; // bytes
_machine = @(systemInfo.machine);
// Disk space stuff
float totalDiskSpace = [FBSDKAppEventsDeviceInfo _getTotalDiskSpace].floatValue;
float totalDiskSpace = [[FBSDKAppEventsDeviceInfo _getTotalDiskSpace] floatValue];
_totalDiskSpaceGB = (unsigned long long)round(totalDiskSpace / FB_GIGABYTE);
}
@ -194,7 +194,7 @@ static const u_int FB_GIGABYTE = 1024 * 1024 * 1024; // bytes
}
// Remaining disk space
float remainingDiskSpace = [FBSDKAppEventsDeviceInfo _getRemainingDiskSpace].floatValue;
float remainingDiskSpace = [[FBSDKAppEventsDeviceInfo _getRemainingDiskSpace] floatValue];
unsigned long long newRemainingDiskSpaceGB = (unsigned long long)round(remainingDiskSpace / FB_GIGABYTE);
if (_remainingDiskSpaceGB != newRemainingDiskSpaceGB) {
_remainingDiskSpaceGB = newRemainingDiskSpaceGB;
@ -237,14 +237,14 @@ static const u_int FB_GIGABYTE = 1024 * 1024 * 1024; // bytes
{
NSDictionary *attrs = [[[NSFileManager alloc] init] attributesOfFileSystemForPath:NSHomeDirectory()
error:nil];
return attrs[NSFileSystemSize];
return [attrs objectForKey:NSFileSystemSize];
}
+ (NSNumber *)_getRemainingDiskSpace
{
NSDictionary *attrs = [[[NSFileManager alloc] init] attributesOfFileSystemForPath:NSHomeDirectory()
error:nil];
return attrs[NSFileSystemFreeSize];
return [attrs objectForKey:NSFileSystemFreeSize];
}
+ (uint)_coreCount
@ -270,8 +270,8 @@ static const u_int FB_GIGABYTE = 1024 * 1024 * 1024; // bytes
#else
// Dynamically load class for this so calling app doesn't need to link framework in.
CTTelephonyNetworkInfo *networkInfo = [[fbsdkdfl_CTTelephonyNetworkInfoClass() alloc] init];
CTCarrier *carrier = networkInfo.subscriberCellularProvider;
return carrier.carrierName ?: @"NoCarrier";
CTCarrier *carrier = [networkInfo subscriberCellularProvider];
return [carrier carrierName] ?: @"NoCarrier";
#endif
}

View File

@ -21,18 +21,16 @@
// this type is not thread safe.
@interface FBSDKAppEventsState : NSObject<NSCopying, NSSecureCoding>
@property (nonatomic, readonly, copy) NSArray *events;
@property (nonatomic, readonly, assign) NSUInteger numSkipped;
@property (nonatomic, readonly, copy) NSString *tokenString;
@property (nonatomic, readonly, copy) NSString *appID;
@property (nonatomic, readonly) BOOL areAllEventsImplicit;
@property (readonly, copy) NSArray *events;
@property (readonly, assign) NSUInteger numSkipped;
@property (readonly, copy) NSString *tokenString;
@property (readonly, copy) NSString *appID;
- (instancetype)init NS_UNAVAILABLE;
+ (instancetype)new NS_UNAVAILABLE;
- (instancetype)initWithToken:(NSString *)tokenString appID:(NSString *)appID NS_DESIGNATED_INITIALIZER;
- (void)addEvent:(NSDictionary *)eventDictionary isImplicit:(BOOL)isImplicit;
- (void)addEventsFromAppEventState:(FBSDKAppEventsState *)appEventsState;
- (BOOL)areAllEventsImplicit;
- (BOOL)isCompatibleWithAppEventsState:(FBSDKAppEventsState *)appEventsState;
- (BOOL)isCompatibleWithTokenString:(NSString *)tokenString appID:(NSString *)appID;
- (NSString *)JSONStringForEvents:(BOOL)includeImplicitEvents;

View File

@ -19,6 +19,7 @@
#import "FBSDKAppEventsState.h"
#import "FBSDKInternalUtility.h"
#import "FBSDKMacros.h"
#define FBSDK_APPEVENTSTATE_ISIMPLICIT_KEY @"isImplicit"
@ -36,6 +37,12 @@
NSMutableArray *_mutableEvents;
}
- (instancetype)init
{
FBSDK_NOT_DESIGNATED_INITIALIZER(initWithToken:appID:);
return [self initWithToken:nil appID:nil];
}
- (instancetype)initWithToken:(NSString *)tokenString appID:(NSString *)appID
{
if ((self = [super init])) {
@ -111,7 +118,7 @@
_numSkipped++;
} else {
[_mutableEvents addObject:@{
@"event" : [eventDictionary mutableCopy],
@"event" : eventDictionary,
FBSDK_APPEVENTSTATE_ISIMPLICIT_KEY : @(isImplicit)
}];
}

View File

@ -39,9 +39,6 @@ typedef NS_ENUM(NSUInteger, FBSDKAppEventsFlushReason)
@interface FBSDKAppEventsUtility : NSObject
- (instancetype)init NS_UNAVAILABLE;
+ (instancetype)new NS_UNAVAILABLE;
+ (NSMutableDictionary *)activityParametersDictionaryForEvent:(NSString *)eventCategory
implicitEventsOnly:(BOOL)implicitEventsOnly
shouldAccessAdvertisingID:(BOOL)shouldAccessAdvertisingID;
@ -56,9 +53,5 @@ typedef NS_ENUM(NSUInteger, FBSDKAppEventsFlushReason)
+ (NSString *)tokenStringToUseFor:(FBSDKAccessToken *)token;
+ (long)unixTimeNow;
+ (BOOL)validateIdentifier:(NSString *)identifier;
+ (id)getVariable:(NSString *)variableName fromInstance:(NSObject *)instance;
+ (NSNumber *)getNumberValue:(NSString *)text;
+ (BOOL)isDebugBuild;
+ (BOOL)isSensitiveUserData:(NSString *)text;
@end

View File

@ -18,8 +18,6 @@
#import "FBSDKAppEventsUtility.h"
#import <objc/runtime.h>
#import <AdSupport/AdSupport.h>
#import "FBSDKAccessToken.h"
@ -30,6 +28,7 @@
#import "FBSDKError.h"
#import "FBSDKInternalUtility.h"
#import "FBSDKLogger.h"
#import "FBSDKMacros.h"
#import "FBSDKSettings.h"
#import "FBSDKTimeSpentData.h"
@ -45,10 +44,8 @@
NSMutableDictionary *parameters = [NSMutableDictionary dictionary];
parameters[@"event"] = eventCategory;
#if __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_7_0
NSString *attributionID = [[self class] attributionID]; // Only present on iOS 6 and below.
[FBSDKInternalUtility dictionary:parameters setObject:attributionID forKey:@"attribution"];
#endif
if (!implicitEventsOnly && shouldAccessAdvertisingID) {
NSString *advertiserID = [[self class] advertiserID];
@ -60,19 +57,15 @@
FBSDKAdvertisingTrackingStatus advertisingTrackingStatus = [[self class] advertisingTrackingStatus];
if (advertisingTrackingStatus != FBSDKAdvertisingTrackingUnspecified) {
BOOL allowed = (advertisingTrackingStatus == FBSDKAdvertisingTrackingAllowed);
parameters[@"advertiser_tracking_enabled"] = @(allowed).stringValue;
parameters[@"advertiser_tracking_enabled"] = [@(allowed) stringValue];
}
parameters[@"application_tracking_enabled"] = @(!FBSDKSettings.limitEventAndDataUsage).stringValue;
parameters[@"application_tracking_enabled"] = [@(!FBSDKSettings.limitEventAndDataUsage) stringValue];
NSString *userID = [FBSDKAppEvents userID];
if (userID) {
parameters[@"app_user_id"] = userID;
}
NSString *userData = [FBSDKAppEvents getUserData];
if (userData){
parameters[@"ud"] = userData;
}
[FBSDKAppEventsDeviceInfo extendDictionaryWithDeviceInfo:parameters];
@ -82,8 +75,8 @@
dispatch_once(&fetchBundleOnce, ^{
NSBundle *mainBundle = [NSBundle mainBundle];
urlSchemes = [[NSMutableArray alloc] init];
for (NSDictionary<NSString *, id> *fields in [mainBundle objectForInfoDictionaryKey:@"CFBundleURLTypes"]) {
NSArray<NSString *> *schemesForType = fields[@"CFBundleURLSchemes"];
for (NSDictionary *fields in [mainBundle objectForInfoDictionaryKey:@"CFBundleURLTypes"]) {
NSArray *schemesForType = [fields objectForKey:@"CFBundleURLSchemes"];
if (schemesForType) {
[urlSchemes addObjectsFromArray:schemesForType];
}
@ -91,7 +84,8 @@
});
if (urlSchemes.count > 0) {
parameters[@"url_schemes"] = [FBSDKInternalUtility JSONStringForObject:urlSchemes error:NULL invalidObjectHandler:NULL];
[parameters setObject:[FBSDKInternalUtility JSONStringForObject:urlSchemes error:NULL invalidObjectHandler:NULL]
forKey:@"url_schemes"];
}
return parameters;
@ -99,16 +93,12 @@
+ (NSString *)advertiserID
{
if (![[FBSDKSettings advertiserIDCollectionEnabled] boolValue]) {
return nil;
}
NSString *result = nil;
Class ASIdentifierManagerClass = fbsdkdfl_ASIdentifierManagerClass();
if ([ASIdentifierManagerClass class]) {
ASIdentifierManager *manager = [ASIdentifierManagerClass sharedManager];
result = manager.advertisingIdentifier.UUIDString;
result = [[manager advertisingIdentifier] UUIDString];
}
return result;
@ -125,7 +115,7 @@
if ([ASIdentifierManagerClass class]) {
ASIdentifierManager *manager = [ASIdentifierManagerClass sharedManager];
if (manager) {
status = manager.advertisingTrackingEnabled ? FBSDKAdvertisingTrackingAllowed : FBSDKAdvertisingTrackingDisallowed;
status = [manager isAdvertisingTrackingEnabled] ? FBSDKAdvertisingTrackingAllowed : FBSDKAdvertisingTrackingDisallowed;
}
}
});
@ -142,7 +132,7 @@
// Generate a new anonymous ID. Create as a UUID, but then prepend the fairly
// arbitrary 'XZ' to the front so it's easily distinguishable from IDFA's which
// will only contain hex.
result = [NSString stringWithFormat:@"XZ%@", [NSUUID UUID].UUIDString];
result = [NSString stringWithFormat:@"XZ%@", [[NSUUID UUID] UUIDString]];
[self persistAnonymousID:result];
}
@ -154,7 +144,7 @@
#if TARGET_OS_TV
return nil;
#else
return [UIPasteboard pasteboardWithName:@"fb_app_attribution" create:NO].string;
return [[UIPasteboard pasteboardWithName:@"fb_app_attribution" create:NO] string];
#endif
}
@ -218,7 +208,7 @@
}
[FBSDKLogger singleShotLogEntry:behaviorToLog logEntry:msg];
NSError *error = [NSError fbErrorWithCode:FBSDKErrorAppEventsFlush message:msg];
NSError *error = [FBSDKError errorWithCode:FBSDKAppEventsFlushErrorCode message:msg];
[[NSNotificationCenter defaultCenter] postNotificationName:FBSDKAppEventsLoggingResultNotification object:error];
}
@ -301,7 +291,7 @@ restOfStringCharacterSet:(NSCharacterSet *)restOfStringCharacterSet
{
NSSearchPathDirectory directory = NSLibraryDirectory;
NSArray *paths = NSSearchPathForDirectoriesInDomains(directory, NSUserDomainMask, YES);
NSString *docDirectory = paths[0];
NSString *docDirectory = [paths objectAtIndex:0];
return [docDirectory stringByAppendingPathComponent:filename];
}
@ -313,7 +303,7 @@ restOfStringCharacterSet:(NSCharacterSet *)restOfStringCharacterSet
encoding:NSASCIIStringEncoding
error:nil];
NSDictionary *results = [FBSDKInternalUtility objectForJSONString:content error:NULL];
return results[FBSDK_APPEVENTSUTILITY_ANONYMOUSID_KEY];
return [results objectForKey:FBSDK_APPEVENTSUTILITY_ANONYMOUSID_KEY];
}
// Given a candidate token (which may be nil), find the real token to string to use.
@ -341,134 +331,13 @@ restOfStringCharacterSet:(NSCharacterSet *)restOfStringCharacterSet
+ (long)unixTimeNow
{
return (long)round([NSDate date].timeIntervalSince1970);
return (long)round([[NSDate date] timeIntervalSince1970]);
}
+ (id)getVariable:(NSString *)variableName fromInstance:(NSObject *)instance {
Ivar ivar = class_getInstanceVariable([instance class], variableName.UTF8String);
if (ivar != NULL) {
const char *encoding = ivar_getTypeEncoding(ivar);
if (encoding != NULL && encoding[0] == '@') {
return object_getIvar(instance, ivar);
}
}
- (instancetype)init
{
FBSDK_NO_DESIGNATED_INITIALIZER();
return nil;
}
+ (NSNumber *)getNumberValue:(NSString *)text {
NSNumber *value = @0;
NSLocale *locale = [NSLocale currentLocale];
NSString *ds = [locale objectForKey:NSLocaleDecimalSeparator] ?: @".";
NSString *gs = [locale objectForKey:NSLocaleGroupingSeparator] ?: @",";
NSString *separators = [ds stringByAppendingString:gs];
NSString *regex = [NSString stringWithFormat:@"[+-]?([0-9]+[%1$@]?)?[%1$@]?([0-9]+[%1$@]?)+", separators];
NSRegularExpression *re = [NSRegularExpression regularExpressionWithPattern:regex
options:0
error:nil];
NSTextCheckingResult *match = [re firstMatchInString:text
options:0
range:NSMakeRange(0, text.length)];
if (match) {
NSString *validText = [text substringWithRange:match.range];
NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init];
formatter.locale = locale;
formatter.numberStyle = NSNumberFormatterDecimalStyle;
value = [formatter numberFromString:validText];
if (nil == value) {
value = @(validText.floatValue);
}
}
return value;
}
+ (BOOL)isDebugBuild {
#if TARGET_IPHONE_SIMULATOR
return YES;
#else
BOOL isDevelopment = NO;
// There is no provisioning profile in AppStore Apps.
@try
{
NSData *data = [NSData dataWithContentsOfFile:[NSBundle.mainBundle pathForResource:@"embedded" ofType:@"mobileprovision"]];
if (data) {
const char *bytes = [data bytes];
NSMutableString *profile = [[NSMutableString alloc] initWithCapacity:data.length];
for (NSUInteger i = 0; i < data.length; i++) {
[profile appendFormat:@"%c", bytes[i]];
}
// Look for debug value, if detected we're in a development build.
NSString *cleared = [[profile componentsSeparatedByCharactersInSet:NSCharacterSet.whitespaceAndNewlineCharacterSet] componentsJoinedByString:@""];
isDevelopment = ([cleared rangeOfString:@"<key>get-task-allow</key><true/>"].length > 0);
}
return isDevelopment;
}
@catch(NSException *exception)
{
}
return NO;
#endif
}
+ (BOOL)isSensitiveUserData:(NSString *)text
{
if (0 == text.length) {
return NO;
}
return [self isEmailAddress:text] || [self isCreditCardNumber:text];
}
+ (BOOL)isCreditCardNumber:(NSString *)text
{
text = [[text componentsSeparatedByCharactersInSet:[NSCharacterSet.decimalDigitCharacterSet invertedSet]] componentsJoinedByString:@""];
if (text.doubleValue == 0) {
return NO;
}
if (text.length < 9 || text.length > 21) {
return NO;
}
const char *chars = [text cStringUsingEncoding:NSUTF8StringEncoding];
if (NULL == chars) {
return NO;
}
BOOL isOdd = YES;
int oddSum = 0;
int evenSum = 0;
for (int i = (int)text.length - 1; i >= 0; i--) {
int digit = chars[i] - '0';
if (isOdd)
oddSum += digit;
else
evenSum += digit / 5 + (2 * digit) % 10;
isOdd = !isOdd;
}
return ((oddSum + evenSum) % 10 == 0);
}
+ (BOOL)isEmailAddress:(NSString *)text
{
NSString *pattern = @"[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,4}";
NSRegularExpression *regex = [[NSRegularExpression alloc] initWithPattern:pattern options:NSRegularExpressionCaseInsensitive error:nil];
NSUInteger matches = [regex numberOfMatchesInString:text options:0 range:NSMakeRange(0, [text length])];
return matches > 0;
}
@end

View File

@ -1,26 +0,0 @@
// 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.
#if !TARGET_OS_TV
#import <Foundation/Foundation.h>
#import <WebKit/WebKit.h>
@interface FBSDKHybridAppEventsScriptMessageHandler : NSObject <WKScriptMessageHandler>
@end
#endif

View File

@ -1,62 +0,0 @@
// 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 "FBSDKHybridAppEventsScriptMessageHandler.h"
#import <FBSDKCoreKit/FBSDKAppEvents.h>
#import "FBSDKAppEvents+Internal.h"
NSString *const FBSDKAppEventsWKWebViewMessagesPixelReferralParamKey = @"_fb_pixel_referral_id";
@class WKUserContentController;
@implementation FBSDKHybridAppEventsScriptMessageHandler
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message {
if ([message.name isEqualToString:FBSDKAppEventsWKWebViewMessagesHandlerKey]) {
NSString *event = message.body[FBSDKAppEventsWKWebViewMessagesEventKey];
if (event.length > 0) {
NSString *stringedParams = message.body[FBSDKAppEventsWKWebViewMessagesParamsKey];
NSMutableDictionary <NSObject *, NSObject *> *params = nil;
NSError *jsonParseError = nil;
if ([stringedParams isKindOfClass:[NSString class]]) {
params = [NSJSONSerialization JSONObjectWithData:[stringedParams dataUsingEncoding:NSUTF8StringEncoding]
options:NSJSONReadingMutableContainers
error:&jsonParseError
];
}
NSString *pixelID = message.body[FBSDKAppEventsWKWebViewMessagesPixelIDKey];
if (pixelID == nil) {
[FBSDKAppEventsUtility logAndNotify:@"Can't bridge an event without a referral Pixel ID. Check your webview Pixel configuration."];
return;
}
if (jsonParseError != nil || ![params isKindOfClass:[NSDictionary class]] || params == nil) {
[FBSDKAppEventsUtility logAndNotify:@"Could not find parameters for your Pixel request. Check your webview Pixel configuration."];
params = [[NSMutableDictionary alloc] initWithObjectsAndKeys:pixelID, FBSDKAppEventsWKWebViewMessagesPixelReferralParamKey, nil];
}
else {
params[FBSDKAppEventsWKWebViewMessagesPixelReferralParamKey] = pixelID;
}
[FBSDKAppEvents logEvent:event parameters:params];
}
}
}
@end

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