- Upgrade Libraries
This commit is contained in:
parent
060efc0c83
commit
f84e3ef366
@ -1,4 +1,4 @@
|
|||||||
platform :ios, '9.0'
|
platform :ios, '10.0'
|
||||||
|
|
||||||
target 'PNObject_Example' do
|
target 'PNObject_Example' do
|
||||||
pod 'PNObject', :path => '../'
|
pod 'PNObject', :path => '../'
|
||||||
|
|||||||
@ -14,33 +14,35 @@ PODS:
|
|||||||
- AFNetworking/Serialization (3.2.1)
|
- AFNetworking/Serialization (3.2.1)
|
||||||
- AFNetworking/UIKit (3.2.1):
|
- AFNetworking/UIKit (3.2.1):
|
||||||
- AFNetworking/NSURLSession
|
- AFNetworking/NSURLSession
|
||||||
- Bolts (1.9.0):
|
|
||||||
- Bolts/AppLinks (= 1.9.0)
|
|
||||||
- Bolts/Tasks (= 1.9.0)
|
|
||||||
- Bolts/AppLinks (1.9.0):
|
|
||||||
- Bolts/Tasks
|
|
||||||
- Bolts/Tasks (1.9.0)
|
|
||||||
- CodFis-Helper (0.1.3)
|
- CodFis-Helper (0.1.3)
|
||||||
- DDDKeychainWrapper (1.0.0)
|
- DDDKeychainWrapper (1.0.0)
|
||||||
- DJLocalization (1.2.2):
|
- DJLocalization (1.2.2):
|
||||||
- DJLocalization/Core (= 1.2.2)
|
- DJLocalization/Core (= 1.2.2)
|
||||||
- DJLocalization/Core (1.2.2)
|
- DJLocalization/Core (1.2.2)
|
||||||
- Expecta (1.0.6)
|
- Expecta (1.0.6)
|
||||||
- FBSDKCoreKit (4.41.0):
|
- FBSDKCoreKit (5.8.0):
|
||||||
- Bolts (~> 1.9)
|
- FBSDKCoreKit/Basics (= 5.8.0)
|
||||||
- FBSDKLoginKit (4.41.0):
|
- FBSDKCoreKit/Core (= 5.8.0)
|
||||||
- FBSDKCoreKit
|
- FBSDKCoreKit/Basics (5.8.0)
|
||||||
- FBSDKPlacesKit (4.41.0):
|
- FBSDKCoreKit/Core (5.8.0):
|
||||||
- FBSDKCoreKit
|
- FBSDKCoreKit/Basics
|
||||||
- FBSDKShareKit (4.41.0):
|
- FBSDKLoginKit (5.8.0):
|
||||||
- FBSDKCoreKit
|
- FBSDKLoginKit/Login (= 5.8.0)
|
||||||
|
- FBSDKLoginKit/Login (5.8.0):
|
||||||
|
- FBSDKCoreKit (~> 5.0)
|
||||||
|
- FBSDKPlacesKit (5.3.0):
|
||||||
|
- FBSDKCoreKit (~> 5.0)
|
||||||
|
- FBSDKShareKit (5.8.0):
|
||||||
|
- FBSDKShareKit/Share (= 5.8.0)
|
||||||
|
- FBSDKShareKit/Share (5.8.0):
|
||||||
|
- FBSDKCoreKit (~> 5.0)
|
||||||
- NSDataAES (0.2.2)
|
- NSDataAES (0.2.2)
|
||||||
- NSDate_Utils (1.1.0):
|
- NSDate_Utils (1.1.0):
|
||||||
- DJLocalization
|
- DJLocalization
|
||||||
- NSString-Helper (1.2.0)
|
- NSString-Helper (1.2.0)
|
||||||
- nv-ios-http-status (0.0.1)
|
- nv-ios-http-status (0.0.1)
|
||||||
- PEAR-FileManager-iOS (1.3.1)
|
- PEAR-FileManager-iOS (1.3.1)
|
||||||
- PNObject (2.6.4):
|
- PNObject (2.6.5):
|
||||||
- AFNetworking
|
- AFNetworking
|
||||||
- CodFis-Helper
|
- CodFis-Helper
|
||||||
- DDDKeychainWrapper
|
- DDDKeychainWrapper
|
||||||
@ -57,11 +59,11 @@ PODS:
|
|||||||
- RZDataBinding
|
- RZDataBinding
|
||||||
- StrongestPasswordValidator
|
- StrongestPasswordValidator
|
||||||
- UIDevice-Utils
|
- UIDevice-Utils
|
||||||
- PureLayout (3.1.4)
|
- PureLayout (3.1.5)
|
||||||
- RZDataBinding (2.1.1)
|
- RZDataBinding (2.1.1)
|
||||||
- Specta (1.0.7)
|
- Specta (1.0.7)
|
||||||
- StrongestPasswordValidator (0.1.2)
|
- StrongestPasswordValidator (0.1.2)
|
||||||
- UIDevice-Utils (1.0.9)
|
- UIDevice-Utils (1.1.0)
|
||||||
|
|
||||||
DEPENDENCIES:
|
DEPENDENCIES:
|
||||||
- Expecta
|
- Expecta
|
||||||
@ -70,9 +72,8 @@ DEPENDENCIES:
|
|||||||
- Specta
|
- Specta
|
||||||
|
|
||||||
SPEC REPOS:
|
SPEC REPOS:
|
||||||
https://github.com/cocoapods/specs.git:
|
trunk:
|
||||||
- AFNetworking
|
- AFNetworking
|
||||||
- Bolts
|
|
||||||
- CodFis-Helper
|
- CodFis-Helper
|
||||||
- DDDKeychainWrapper
|
- DDDKeychainWrapper
|
||||||
- DJLocalization
|
- DJLocalization
|
||||||
@ -98,27 +99,26 @@ EXTERNAL SOURCES:
|
|||||||
|
|
||||||
SPEC CHECKSUMS:
|
SPEC CHECKSUMS:
|
||||||
AFNetworking: b6f891fdfaed196b46c7a83cf209e09697b94057
|
AFNetworking: b6f891fdfaed196b46c7a83cf209e09697b94057
|
||||||
Bolts: ac6567323eac61e203f6a9763667d0f711be34c8
|
|
||||||
CodFis-Helper: 28be4c74d7202542459d72354f59b1215871de87
|
CodFis-Helper: 28be4c74d7202542459d72354f59b1215871de87
|
||||||
DDDKeychainWrapper: e681a4daba6448786fa83b4941f58102a33b1897
|
DDDKeychainWrapper: e681a4daba6448786fa83b4941f58102a33b1897
|
||||||
DJLocalization: 0c84029af375647d4104a42ae36be87194c46c47
|
DJLocalization: 0c84029af375647d4104a42ae36be87194c46c47
|
||||||
Expecta: 3b6bd90a64b9a1dcb0b70aa0e10a7f8f631667d5
|
Expecta: 3b6bd90a64b9a1dcb0b70aa0e10a7f8f631667d5
|
||||||
FBSDKCoreKit: 974810fe3806173f3777c68062fa8ed6fa59b59d
|
FBSDKCoreKit: e7dcac0aabcfb09d0166998edd95fe3b05a0ce5d
|
||||||
FBSDKLoginKit: 159a5c2eebe6a0774c3b128f5085128679233d2b
|
FBSDKLoginKit: 1b0cf04df0370b37404213157b060d6666ede814
|
||||||
FBSDKPlacesKit: 8dc2ca787f8934c021876d9e51bf3a5508b0675c
|
FBSDKPlacesKit: 0388766304ff7a89630bcc211db9f500d549f403
|
||||||
FBSDKShareKit: 79dfd0c51f1a241f33e219fcc39e7cc69534b900
|
FBSDKShareKit: abc29e1bb4f9f59f679adf1ae191006d68455f96
|
||||||
NSDataAES: 967ea3337476a80e9838a533c25d570a06855ed0
|
NSDataAES: 967ea3337476a80e9838a533c25d570a06855ed0
|
||||||
NSDate_Utils: c858a89da6e204ecf53aca48dbccb4da4d25bc9e
|
NSDate_Utils: c858a89da6e204ecf53aca48dbccb4da4d25bc9e
|
||||||
NSString-Helper: 1c259caa6c845e79e0bb45ee25e34f95d86d2317
|
NSString-Helper: 1c259caa6c845e79e0bb45ee25e34f95d86d2317
|
||||||
nv-ios-http-status: b6c2b5fc8656cc19e0d3000dadce2080b99d0e2f
|
nv-ios-http-status: b6c2b5fc8656cc19e0d3000dadce2080b99d0e2f
|
||||||
PEAR-FileManager-iOS: 3bc403f68a53483f5629aa822f4649e40275c4d3
|
PEAR-FileManager-iOS: 3bc403f68a53483f5629aa822f4649e40275c4d3
|
||||||
PNObject: 5d8947012a711816bceedce57d07762327ac57c6
|
PNObject: 050cb74316db4833c551ae9732db81f6fb8c6416
|
||||||
PureLayout: f08c01b8dec00bb14a1fefa3de4c7d9c265df85e
|
PureLayout: 9b4ad47b2f0388c84ff534af23d96e720c1b875a
|
||||||
RZDataBinding: 289e2fbdce8b9585afef69def83425c5d380ffbd
|
RZDataBinding: 289e2fbdce8b9585afef69def83425c5d380ffbd
|
||||||
Specta: 3e1bd89c3517421982dc4d1c992503e48bd5fe66
|
Specta: 3e1bd89c3517421982dc4d1c992503e48bd5fe66
|
||||||
StrongestPasswordValidator: 921e42615bdf353513c6f925bffd4fc29865dbd7
|
StrongestPasswordValidator: 921e42615bdf353513c6f925bffd4fc29865dbd7
|
||||||
UIDevice-Utils: 6ba44475416a1e823f214a8ed26fc9a0761db096
|
UIDevice-Utils: 9efdf0f9fb3c07a53595d39981d3c04ce39aba5f
|
||||||
|
|
||||||
PODFILE CHECKSUM: eec9c921f7aee591fd1fdea1fd3e5a191b74a436
|
PODFILE CHECKSUM: 1dc1681e732f85afd3765f49346295b2d8460102
|
||||||
|
|
||||||
COCOAPODS: 1.6.0
|
COCOAPODS: 1.8.4
|
||||||
|
|||||||
@ -1,42 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2014, Facebook, Inc.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* This source code is licensed under the BSD-style license found in the
|
|
||||||
* LICENSE file in the root directory of this source tree. An additional grant
|
|
||||||
* of patent rights can be found in the PATENTS file in the same directory.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#import <Foundation/Foundation.h>
|
|
||||||
|
|
||||||
#import <Bolts/BFCancellationTokenRegistration.h>
|
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_BEGIN
|
|
||||||
|
|
||||||
/*!
|
|
||||||
A block that will be called when a token is cancelled.
|
|
||||||
*/
|
|
||||||
typedef void(^BFCancellationBlock)(void);
|
|
||||||
|
|
||||||
/*!
|
|
||||||
The consumer view of a CancellationToken.
|
|
||||||
Propagates notification that operations should be canceled.
|
|
||||||
A BFCancellationToken has methods to inspect whether the token has been cancelled.
|
|
||||||
*/
|
|
||||||
@interface BFCancellationToken : NSObject
|
|
||||||
|
|
||||||
/*!
|
|
||||||
Whether cancellation has been requested for this token source.
|
|
||||||
*/
|
|
||||||
@property (nonatomic, assign, readonly, getter=isCancellationRequested) BOOL cancellationRequested;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
Register a block to be notified when the token is cancelled.
|
|
||||||
If the token is already cancelled the delegate will be notified immediately.
|
|
||||||
*/
|
|
||||||
- (BFCancellationTokenRegistration *)registerCancellationObserverWithBlock:(BFCancellationBlock)block;
|
|
||||||
|
|
||||||
@end
|
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_END
|
|
||||||
144
Example/Pods/Bolts/Bolts/Common/BFCancellationToken.m
generated
144
Example/Pods/Bolts/Bolts/Common/BFCancellationToken.m
generated
@ -1,144 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2014, Facebook, Inc.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* This source code is licensed under the BSD-style license found in the
|
|
||||||
* LICENSE file in the root directory of this source tree. An additional grant
|
|
||||||
* of patent rights can be found in the PATENTS file in the same directory.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#import "BFCancellationToken.h"
|
|
||||||
#import "BFCancellationTokenRegistration.h"
|
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_BEGIN
|
|
||||||
|
|
||||||
@interface BFCancellationToken ()
|
|
||||||
|
|
||||||
@property (nullable, nonatomic, strong) NSMutableArray *registrations;
|
|
||||||
@property (nonatomic, strong) NSObject *lock;
|
|
||||||
@property (nonatomic) BOOL disposed;
|
|
||||||
|
|
||||||
@end
|
|
||||||
|
|
||||||
@interface BFCancellationTokenRegistration (BFCancellationToken)
|
|
||||||
|
|
||||||
+ (instancetype)registrationWithToken:(BFCancellationToken *)token delegate:(BFCancellationBlock)delegate;
|
|
||||||
|
|
||||||
- (void)notifyDelegate;
|
|
||||||
|
|
||||||
@end
|
|
||||||
|
|
||||||
@implementation BFCancellationToken
|
|
||||||
|
|
||||||
@synthesize cancellationRequested = _cancellationRequested;
|
|
||||||
|
|
||||||
#pragma mark - Initializer
|
|
||||||
|
|
||||||
- (instancetype)init {
|
|
||||||
self = [super init];
|
|
||||||
if (!self) return self;
|
|
||||||
|
|
||||||
_registrations = [NSMutableArray array];
|
|
||||||
_lock = [NSObject new];
|
|
||||||
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark - Custom Setters/Getters
|
|
||||||
|
|
||||||
- (BOOL)isCancellationRequested {
|
|
||||||
@synchronized(self.lock) {
|
|
||||||
[self throwIfDisposed];
|
|
||||||
return _cancellationRequested;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)cancel {
|
|
||||||
NSArray *registrations;
|
|
||||||
@synchronized(self.lock) {
|
|
||||||
[self throwIfDisposed];
|
|
||||||
if (_cancellationRequested) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
[NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(cancelPrivate) object:nil];
|
|
||||||
_cancellationRequested = YES;
|
|
||||||
registrations = [self.registrations copy];
|
|
||||||
}
|
|
||||||
|
|
||||||
[self notifyCancellation:registrations];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)notifyCancellation:(NSArray *)registrations {
|
|
||||||
for (BFCancellationTokenRegistration *registration in registrations) {
|
|
||||||
[registration notifyDelegate];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (BFCancellationTokenRegistration *)registerCancellationObserverWithBlock:(BFCancellationBlock)block {
|
|
||||||
@synchronized(self.lock) {
|
|
||||||
BFCancellationTokenRegistration *registration = [BFCancellationTokenRegistration registrationWithToken:self delegate:[block copy]];
|
|
||||||
[self.registrations addObject:registration];
|
|
||||||
|
|
||||||
return registration;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)unregisterRegistration:(BFCancellationTokenRegistration *)registration {
|
|
||||||
@synchronized(self.lock) {
|
|
||||||
[self throwIfDisposed];
|
|
||||||
[self.registrations removeObject:registration];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Delay on a non-public method to prevent interference with a user calling performSelector or
|
|
||||||
// cancelPreviousPerformRequestsWithTarget on the public method
|
|
||||||
- (void)cancelPrivate {
|
|
||||||
[self cancel];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)cancelAfterDelay:(int)millis {
|
|
||||||
[self throwIfDisposed];
|
|
||||||
if (millis < -1) {
|
|
||||||
[NSException raise:NSInvalidArgumentException format:@"Delay must be >= -1"];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (millis == 0) {
|
|
||||||
[self cancel];
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
@synchronized(self.lock) {
|
|
||||||
[self throwIfDisposed];
|
|
||||||
[NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(cancelPrivate) object:nil];
|
|
||||||
if (self.cancellationRequested) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (millis != -1) {
|
|
||||||
double delay = (double)millis / 1000;
|
|
||||||
[self performSelector:@selector(cancelPrivate) withObject:nil afterDelay:delay];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)dispose {
|
|
||||||
@synchronized(self.lock) {
|
|
||||||
if (self.disposed) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
[self.registrations makeObjectsPerformSelector:@selector(dispose)];
|
|
||||||
self.registrations = nil;
|
|
||||||
self.disposed = YES;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)throwIfDisposed {
|
|
||||||
if (self.disposed) {
|
|
||||||
[NSException raise:NSInternalInconsistencyException format:@"Object already disposed"];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_END
|
|
||||||
@ -1,29 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2014, Facebook, Inc.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* This source code is licensed under the BSD-style license found in the
|
|
||||||
* LICENSE file in the root directory of this source tree. An additional grant
|
|
||||||
* of patent rights can be found in the PATENTS file in the same directory.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#import <Foundation/Foundation.h>
|
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_BEGIN
|
|
||||||
|
|
||||||
/*!
|
|
||||||
Represents the registration of a cancellation observer with a cancellation token.
|
|
||||||
Can be used to unregister the observer at a later time.
|
|
||||||
*/
|
|
||||||
@interface BFCancellationTokenRegistration : NSObject
|
|
||||||
|
|
||||||
/*!
|
|
||||||
Removes the cancellation observer registered with the token
|
|
||||||
and releases all resources associated with this registration.
|
|
||||||
*/
|
|
||||||
- (void)dispose;
|
|
||||||
|
|
||||||
@end
|
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_END
|
|
||||||
@ -1,79 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2014, Facebook, Inc.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* This source code is licensed under the BSD-style license found in the
|
|
||||||
* LICENSE file in the root directory of this source tree. An additional grant
|
|
||||||
* of patent rights can be found in the PATENTS file in the same directory.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#import "BFCancellationTokenRegistration.h"
|
|
||||||
|
|
||||||
#import "BFCancellationToken.h"
|
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_BEGIN
|
|
||||||
|
|
||||||
@interface BFCancellationTokenRegistration ()
|
|
||||||
|
|
||||||
@property (nonatomic, weak) BFCancellationToken *token;
|
|
||||||
@property (nullable, nonatomic, strong) BFCancellationBlock cancellationObserverBlock;
|
|
||||||
@property (nonatomic, strong) NSObject *lock;
|
|
||||||
@property (nonatomic) BOOL disposed;
|
|
||||||
|
|
||||||
@end
|
|
||||||
|
|
||||||
@interface BFCancellationToken (BFCancellationTokenRegistration)
|
|
||||||
|
|
||||||
- (void)unregisterRegistration:(BFCancellationTokenRegistration *)registration;
|
|
||||||
|
|
||||||
@end
|
|
||||||
|
|
||||||
@implementation BFCancellationTokenRegistration
|
|
||||||
|
|
||||||
+ (instancetype)registrationWithToken:(BFCancellationToken *)token delegate:(BFCancellationBlock)delegate {
|
|
||||||
BFCancellationTokenRegistration *registration = [BFCancellationTokenRegistration new];
|
|
||||||
registration.token = token;
|
|
||||||
registration.cancellationObserverBlock = delegate;
|
|
||||||
return registration;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (instancetype)init {
|
|
||||||
self = [super init];
|
|
||||||
if (!self) return self;
|
|
||||||
|
|
||||||
_lock = [NSObject new];
|
|
||||||
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)dispose {
|
|
||||||
@synchronized(self.lock) {
|
|
||||||
if (self.disposed) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
self.disposed = YES;
|
|
||||||
}
|
|
||||||
|
|
||||||
BFCancellationToken *token = self.token;
|
|
||||||
if (token != nil) {
|
|
||||||
[token unregisterRegistration:self];
|
|
||||||
self.token = nil;
|
|
||||||
}
|
|
||||||
self.cancellationObserverBlock = nil;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)notifyDelegate {
|
|
||||||
@synchronized(self.lock) {
|
|
||||||
[self throwIfDisposed];
|
|
||||||
self.cancellationObserverBlock();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)throwIfDisposed {
|
|
||||||
NSAssert(!self.disposed, @"Object already disposed");
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_END
|
|
||||||
@ -1,60 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2014, Facebook, Inc.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* This source code is licensed under the BSD-style license found in the
|
|
||||||
* LICENSE file in the root directory of this source tree. An additional grant
|
|
||||||
* of patent rights can be found in the PATENTS file in the same directory.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#import <Foundation/Foundation.h>
|
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_BEGIN
|
|
||||||
|
|
||||||
@class BFCancellationToken;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
BFCancellationTokenSource represents the producer side of a CancellationToken.
|
|
||||||
Signals to a CancellationToken that it should be canceled.
|
|
||||||
It is a cancellation token that also has methods
|
|
||||||
for changing the state of a token by cancelling it.
|
|
||||||
*/
|
|
||||||
@interface BFCancellationTokenSource : NSObject
|
|
||||||
|
|
||||||
/*!
|
|
||||||
Creates a new cancellation token source.
|
|
||||||
*/
|
|
||||||
+ (instancetype)cancellationTokenSource;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
The cancellation token associated with this CancellationTokenSource.
|
|
||||||
*/
|
|
||||||
@property (nonatomic, strong, readonly) BFCancellationToken *token;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
Whether cancellation has been requested for this token source.
|
|
||||||
*/
|
|
||||||
@property (nonatomic, assign, readonly, getter=isCancellationRequested) BOOL cancellationRequested;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
Cancels the token if it has not already been cancelled.
|
|
||||||
*/
|
|
||||||
- (void)cancel;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
Schedules a cancel operation on this CancellationTokenSource after the specified number of milliseconds.
|
|
||||||
@param millis The number of milliseconds to wait before completing the returned task.
|
|
||||||
If delay is `0` the cancel is executed immediately. If delay is `-1` any scheduled cancellation is stopped.
|
|
||||||
*/
|
|
||||||
- (void)cancelAfterDelay:(int)millis;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
Releases all resources associated with this token source,
|
|
||||||
including disposing of all registrations.
|
|
||||||
*/
|
|
||||||
- (void)dispose;
|
|
||||||
|
|
||||||
@end
|
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_END
|
|
||||||
@ -1,64 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2014, Facebook, Inc.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* This source code is licensed under the BSD-style license found in the
|
|
||||||
* LICENSE file in the root directory of this source tree. An additional grant
|
|
||||||
* of patent rights can be found in the PATENTS file in the same directory.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#import "BFCancellationTokenSource.h"
|
|
||||||
|
|
||||||
#import "BFCancellationToken.h"
|
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_BEGIN
|
|
||||||
|
|
||||||
@interface BFCancellationToken (BFCancellationTokenSource)
|
|
||||||
|
|
||||||
- (void)cancel;
|
|
||||||
- (void)cancelAfterDelay:(int)millis;
|
|
||||||
|
|
||||||
- (void)dispose;
|
|
||||||
- (void)throwIfDisposed;
|
|
||||||
|
|
||||||
@end
|
|
||||||
|
|
||||||
@implementation BFCancellationTokenSource
|
|
||||||
|
|
||||||
#pragma mark - Initializer
|
|
||||||
|
|
||||||
- (instancetype)init {
|
|
||||||
self = [super init];
|
|
||||||
if (!self) return self;
|
|
||||||
|
|
||||||
_token = [BFCancellationToken new];
|
|
||||||
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
+ (instancetype)cancellationTokenSource {
|
|
||||||
return [BFCancellationTokenSource new];
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark - Custom Setters/Getters
|
|
||||||
|
|
||||||
- (BOOL)isCancellationRequested {
|
|
||||||
return _token.isCancellationRequested;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)cancel {
|
|
||||||
[_token cancel];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)cancelAfterDelay:(int)millis {
|
|
||||||
[_token cancelAfterDelay:millis];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)dispose {
|
|
||||||
[_token dispose];
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_END
|
|
||||||
62
Example/Pods/Bolts/Bolts/Common/BFExecutor.h
generated
62
Example/Pods/Bolts/Bolts/Common/BFExecutor.h
generated
@ -1,62 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2014, Facebook, Inc.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* This source code is licensed under the BSD-style license found in the
|
|
||||||
* LICENSE file in the root directory of this source tree. An additional grant
|
|
||||||
* of patent rights can be found in the PATENTS file in the same directory.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#import <Foundation/Foundation.h>
|
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_BEGIN
|
|
||||||
|
|
||||||
/*!
|
|
||||||
An object that can run a given block.
|
|
||||||
*/
|
|
||||||
@interface BFExecutor : NSObject
|
|
||||||
|
|
||||||
/*!
|
|
||||||
Returns a default executor, which runs continuations immediately until the call stack gets too
|
|
||||||
deep, then dispatches to a new GCD queue.
|
|
||||||
*/
|
|
||||||
+ (instancetype)defaultExecutor;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
Returns an executor that runs continuations on the thread where the previous task was completed.
|
|
||||||
*/
|
|
||||||
+ (instancetype)immediateExecutor;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
Returns an executor that runs continuations on the main thread.
|
|
||||||
*/
|
|
||||||
+ (instancetype)mainThreadExecutor;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
Returns a new executor that uses the given block to execute continuations.
|
|
||||||
@param block The block to use.
|
|
||||||
*/
|
|
||||||
+ (instancetype)executorWithBlock:(void(^)(void(^block)(void)))block;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
Returns a new executor that runs continuations on the given queue.
|
|
||||||
@param queue The instance of `dispatch_queue_t` to dispatch all continuations onto.
|
|
||||||
*/
|
|
||||||
+ (instancetype)executorWithDispatchQueue:(dispatch_queue_t)queue;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
Returns a new executor that runs continuations on the given queue.
|
|
||||||
@param queue The instance of `NSOperationQueue` to run all continuations on.
|
|
||||||
*/
|
|
||||||
+ (instancetype)executorWithOperationQueue:(NSOperationQueue *)queue;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
Runs the given block using this executor's particular strategy.
|
|
||||||
@param block The block to execute.
|
|
||||||
*/
|
|
||||||
- (void)execute:(void(^)(void))block;
|
|
||||||
|
|
||||||
@end
|
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_END
|
|
||||||
136
Example/Pods/Bolts/Bolts/Common/BFExecutor.m
generated
136
Example/Pods/Bolts/Bolts/Common/BFExecutor.m
generated
@ -1,136 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2014, Facebook, Inc.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* This source code is licensed under the BSD-style license found in the
|
|
||||||
* LICENSE file in the root directory of this source tree. An additional grant
|
|
||||||
* of patent rights can be found in the PATENTS file in the same directory.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#import "BFExecutor.h"
|
|
||||||
|
|
||||||
#import <pthread.h>
|
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_BEGIN
|
|
||||||
|
|
||||||
/*!
|
|
||||||
Get the remaining stack-size of the current thread.
|
|
||||||
|
|
||||||
@param totalSize The total stack size of the current thread.
|
|
||||||
|
|
||||||
@return The remaining size, in bytes, available to the current thread.
|
|
||||||
|
|
||||||
@note This function cannot be inlined, as otherwise the internal implementation could fail to report the proper
|
|
||||||
remaining stack space.
|
|
||||||
*/
|
|
||||||
__attribute__((noinline)) static size_t remaining_stack_size(size_t *restrict totalSize) {
|
|
||||||
pthread_t currentThread = pthread_self();
|
|
||||||
|
|
||||||
// NOTE: We must store stack pointers as uint8_t so that the pointer math is well-defined
|
|
||||||
uint8_t *endStack = pthread_get_stackaddr_np(currentThread);
|
|
||||||
*totalSize = pthread_get_stacksize_np(currentThread);
|
|
||||||
|
|
||||||
// NOTE: If the function is inlined, this value could be incorrect
|
|
||||||
uint8_t *frameAddr = __builtin_frame_address(0);
|
|
||||||
|
|
||||||
return (*totalSize) - (size_t)(endStack - frameAddr);
|
|
||||||
}
|
|
||||||
|
|
||||||
@interface BFExecutor ()
|
|
||||||
|
|
||||||
@property (nonatomic, copy) void(^block)(void(^block)(void));
|
|
||||||
|
|
||||||
@end
|
|
||||||
|
|
||||||
@implementation BFExecutor
|
|
||||||
|
|
||||||
#pragma mark - Executor methods
|
|
||||||
|
|
||||||
+ (instancetype)defaultExecutor {
|
|
||||||
static BFExecutor *defaultExecutor = NULL;
|
|
||||||
static dispatch_once_t onceToken;
|
|
||||||
dispatch_once(&onceToken, ^{
|
|
||||||
defaultExecutor = [self executorWithBlock:^void(void(^block)(void)) {
|
|
||||||
// We prefer to run everything possible immediately, so that there is callstack information
|
|
||||||
// when debugging. However, we don't want the stack to get too deep, so if the remaining stack space
|
|
||||||
// is less than 10% of the total space, we dispatch to another GCD queue.
|
|
||||||
size_t totalStackSize = 0;
|
|
||||||
size_t remainingStackSize = remaining_stack_size(&totalStackSize);
|
|
||||||
|
|
||||||
if (remainingStackSize < (totalStackSize / 10)) {
|
|
||||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), block);
|
|
||||||
} else {
|
|
||||||
@autoreleasepool {
|
|
||||||
block();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}];
|
|
||||||
});
|
|
||||||
return defaultExecutor;
|
|
||||||
}
|
|
||||||
|
|
||||||
+ (instancetype)immediateExecutor {
|
|
||||||
static BFExecutor *immediateExecutor = NULL;
|
|
||||||
static dispatch_once_t onceToken;
|
|
||||||
dispatch_once(&onceToken, ^{
|
|
||||||
immediateExecutor = [self executorWithBlock:^void(void(^block)(void)) {
|
|
||||||
block();
|
|
||||||
}];
|
|
||||||
});
|
|
||||||
return immediateExecutor;
|
|
||||||
}
|
|
||||||
|
|
||||||
+ (instancetype)mainThreadExecutor {
|
|
||||||
static BFExecutor *mainThreadExecutor = NULL;
|
|
||||||
static dispatch_once_t onceToken;
|
|
||||||
dispatch_once(&onceToken, ^{
|
|
||||||
mainThreadExecutor = [self executorWithBlock:^void(void(^block)(void)) {
|
|
||||||
if (![NSThread isMainThread]) {
|
|
||||||
dispatch_async(dispatch_get_main_queue(), block);
|
|
||||||
} else {
|
|
||||||
@autoreleasepool {
|
|
||||||
block();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}];
|
|
||||||
});
|
|
||||||
return mainThreadExecutor;
|
|
||||||
}
|
|
||||||
|
|
||||||
+ (instancetype)executorWithBlock:(void(^)(void(^block)(void)))block {
|
|
||||||
return [[self alloc] initWithBlock:block];
|
|
||||||
}
|
|
||||||
|
|
||||||
+ (instancetype)executorWithDispatchQueue:(dispatch_queue_t)queue {
|
|
||||||
return [self executorWithBlock:^void(void(^block)(void)) {
|
|
||||||
dispatch_async(queue, block);
|
|
||||||
}];
|
|
||||||
}
|
|
||||||
|
|
||||||
+ (instancetype)executorWithOperationQueue:(NSOperationQueue *)queue {
|
|
||||||
return [self executorWithBlock:^void(void(^block)(void)) {
|
|
||||||
[queue addOperation:[NSBlockOperation blockOperationWithBlock:block]];
|
|
||||||
}];
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark - Initializer
|
|
||||||
|
|
||||||
- (instancetype)initWithBlock:(void(^)(void(^block)(void)))block {
|
|
||||||
self = [super init];
|
|
||||||
if (!self) return self;
|
|
||||||
|
|
||||||
_block = block;
|
|
||||||
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark - Execution
|
|
||||||
|
|
||||||
- (void)execute:(void(^)(void))block {
|
|
||||||
self.block(block);
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_END
|
|
||||||
25
Example/Pods/Bolts/Bolts/Common/BFGeneric.h
generated
25
Example/Pods/Bolts/Bolts/Common/BFGeneric.h
generated
@ -1,25 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2014, Facebook, Inc.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* This source code is licensed under the BSD-style license found in the
|
|
||||||
* LICENSE file in the root directory of this source tree. An additional grant
|
|
||||||
* of patent rights can be found in the PATENTS file in the same directory.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#import <Foundation/Foundation.h>
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
/**
|
|
||||||
This exists to use along with `BFTask` and `BFTaskCompletionSource`.
|
|
||||||
|
|
||||||
Instead of returning a `BFTask` with no generic type, or a generic type of 'NSNull'
|
|
||||||
when there is no usable result from a task, we use the type 'BFVoid', which will always have a value of `nil`.
|
|
||||||
|
|
||||||
This allows you to provide a more enforced API contract to the caller,
|
|
||||||
as sending any message to `BFVoid` will result in a compile time error.
|
|
||||||
*/
|
|
||||||
@class _BFVoid_Nonexistant;
|
|
||||||
typedef _BFVoid_Nonexistant *BFVoid;
|
|
||||||
266
Example/Pods/Bolts/Bolts/Common/BFTask.h
generated
266
Example/Pods/Bolts/Bolts/Common/BFTask.h
generated
@ -1,266 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2014, Facebook, Inc.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* This source code is licensed under the BSD-style license found in the
|
|
||||||
* LICENSE file in the root directory of this source tree. An additional grant
|
|
||||||
* of patent rights can be found in the PATENTS file in the same directory.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#import <Foundation/Foundation.h>
|
|
||||||
|
|
||||||
#import <Bolts/BFCancellationToken.h>
|
|
||||||
#import <Bolts/BFGeneric.h>
|
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_BEGIN
|
|
||||||
|
|
||||||
/*!
|
|
||||||
Error domain used if there was multiple errors on <BFTask taskForCompletionOfAllTasks:>.
|
|
||||||
*/
|
|
||||||
extern NSString *const BFTaskErrorDomain;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
An error code used for <BFTask taskForCompletionOfAllTasks:>, if there were multiple errors.
|
|
||||||
*/
|
|
||||||
extern NSInteger const kBFMultipleErrorsError;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
An error userInfo key used if there were multiple errors on <BFTask taskForCompletionOfAllTasks:>.
|
|
||||||
Value type is `NSArray<NSError *> *`.
|
|
||||||
*/
|
|
||||||
extern NSString *const BFTaskMultipleErrorsUserInfoKey;
|
|
||||||
|
|
||||||
@class BFExecutor;
|
|
||||||
@class BFTask;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
The consumer view of a Task. A BFTask has methods to
|
|
||||||
inspect the state of the task, and to add continuations to
|
|
||||||
be run once the task is complete.
|
|
||||||
*/
|
|
||||||
@interface BFTask<__covariant ResultType> : NSObject
|
|
||||||
|
|
||||||
/*!
|
|
||||||
A block that can act as a continuation for a task.
|
|
||||||
*/
|
|
||||||
typedef __nullable id(^BFContinuationBlock)(BFTask<ResultType> *t);
|
|
||||||
|
|
||||||
/*!
|
|
||||||
Creates a task that is already completed with the given result.
|
|
||||||
@param result The result for the task.
|
|
||||||
*/
|
|
||||||
+ (instancetype)taskWithResult:(nullable ResultType)result;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
Creates a task that is already completed with the given error.
|
|
||||||
@param error The error for the task.
|
|
||||||
*/
|
|
||||||
+ (instancetype)taskWithError:(NSError *)error;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
Creates a task that is already cancelled.
|
|
||||||
*/
|
|
||||||
+ (instancetype)cancelledTask;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
Returns a task that will be completed (with result == nil) once
|
|
||||||
all of the input tasks have completed.
|
|
||||||
@param tasks An `NSArray` of the tasks to use as an input.
|
|
||||||
*/
|
|
||||||
+ (instancetype)taskForCompletionOfAllTasks:(nullable NSArray<BFTask *> *)tasks;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
Returns a task that will be completed once all of the input tasks have completed.
|
|
||||||
If all tasks complete successfully without being faulted or cancelled the result will be
|
|
||||||
an `NSArray` of all task results in the order they were provided.
|
|
||||||
@param tasks An `NSArray` of the tasks to use as an input.
|
|
||||||
*/
|
|
||||||
+ (instancetype)taskForCompletionOfAllTasksWithResults:(nullable NSArray<BFTask *> *)tasks;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
Returns a task that will be completed once there is at least one successful task.
|
|
||||||
The first task to successuly complete will set the result, all other tasks results are
|
|
||||||
ignored.
|
|
||||||
@param tasks An `NSArray` of the tasks to use as an input.
|
|
||||||
*/
|
|
||||||
+ (instancetype)taskForCompletionOfAnyTask:(nullable NSArray<BFTask *> *)tasks;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
Returns a task that will be completed a certain amount of time in the future.
|
|
||||||
@param millis The approximate number of milliseconds to wait before the
|
|
||||||
task will be finished (with result == nil).
|
|
||||||
*/
|
|
||||||
+ (BFTask<BFVoid> *)taskWithDelay:(int)millis;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
Returns a task that will be completed a certain amount of time in the future.
|
|
||||||
@param millis The approximate number of milliseconds to wait before the
|
|
||||||
task will be finished (with result == nil).
|
|
||||||
@param token The cancellation token (optional).
|
|
||||||
*/
|
|
||||||
+ (BFTask<BFVoid> *)taskWithDelay:(int)millis cancellationToken:(nullable BFCancellationToken *)token;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
Returns a task that will be completed after the given block completes with
|
|
||||||
the specified executor.
|
|
||||||
@param executor A BFExecutor responsible for determining how the
|
|
||||||
continuation block will be run.
|
|
||||||
@param block The block to immediately schedule to run with the given executor.
|
|
||||||
@returns A task that will be completed after block has run.
|
|
||||||
If block returns a BFTask, then the task returned from
|
|
||||||
this method will not be completed until that task is completed.
|
|
||||||
*/
|
|
||||||
+ (instancetype)taskFromExecutor:(BFExecutor *)executor withBlock:(nullable id (^)(void))block;
|
|
||||||
|
|
||||||
// Properties that will be set on the task once it is completed.
|
|
||||||
|
|
||||||
/*!
|
|
||||||
The result of a successful task.
|
|
||||||
*/
|
|
||||||
@property (nullable, nonatomic, strong, readonly) ResultType result;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
The error of a failed task.
|
|
||||||
*/
|
|
||||||
@property (nullable, nonatomic, strong, readonly) NSError *error;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
Whether this task has been cancelled.
|
|
||||||
*/
|
|
||||||
@property (nonatomic, assign, readonly, getter=isCancelled) BOOL cancelled;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
Whether this task has completed due to an error.
|
|
||||||
*/
|
|
||||||
@property (nonatomic, assign, readonly, getter=isFaulted) BOOL faulted;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
Whether this task has completed.
|
|
||||||
*/
|
|
||||||
@property (nonatomic, assign, readonly, getter=isCompleted) BOOL completed;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
Enqueues the given block to be run once this task is complete.
|
|
||||||
This method uses a default execution strategy. The block will be
|
|
||||||
run on the thread where the previous task completes, unless the
|
|
||||||
the stack depth is too deep, in which case it will be run on a
|
|
||||||
dispatch queue with default priority.
|
|
||||||
@param block The block to be run once this task is complete.
|
|
||||||
@returns A task that will be completed after block has run.
|
|
||||||
If block returns a BFTask, then the task returned from
|
|
||||||
this method will not be completed until that task is completed.
|
|
||||||
*/
|
|
||||||
- (BFTask *)continueWithBlock:(BFContinuationBlock)block NS_SWIFT_NAME(continueWith(block:));
|
|
||||||
|
|
||||||
/*!
|
|
||||||
Enqueues the given block to be run once this task is complete.
|
|
||||||
This method uses a default execution strategy. The block will be
|
|
||||||
run on the thread where the previous task completes, unless the
|
|
||||||
the stack depth is too deep, in which case it will be run on a
|
|
||||||
dispatch queue with default priority.
|
|
||||||
@param block The block to be run once this task is complete.
|
|
||||||
@param cancellationToken The cancellation token (optional).
|
|
||||||
@returns A task that will be completed after block has run.
|
|
||||||
If block returns a BFTask, then the task returned from
|
|
||||||
this method will not be completed until that task is completed.
|
|
||||||
*/
|
|
||||||
- (BFTask *)continueWithBlock:(BFContinuationBlock)block
|
|
||||||
cancellationToken:(nullable BFCancellationToken *)cancellationToken NS_SWIFT_NAME(continueWith(block:cancellationToken:));
|
|
||||||
|
|
||||||
/*!
|
|
||||||
Enqueues the given block to be run once this task is complete.
|
|
||||||
@param executor A BFExecutor responsible for determining how the
|
|
||||||
continuation block will be run.
|
|
||||||
@param block The block to be run once this task is complete.
|
|
||||||
@returns A task that will be completed after block has run.
|
|
||||||
If block returns a BFTask, then the task returned from
|
|
||||||
this method will not be completed until that task is completed.
|
|
||||||
*/
|
|
||||||
- (BFTask *)continueWithExecutor:(BFExecutor *)executor
|
|
||||||
withBlock:(BFContinuationBlock)block NS_SWIFT_NAME(continueWith(executor:block:));
|
|
||||||
|
|
||||||
/*!
|
|
||||||
Enqueues the given block to be run once this task is complete.
|
|
||||||
@param executor A BFExecutor responsible for determining how the
|
|
||||||
continuation block will be run.
|
|
||||||
@param block The block to be run once this task is complete.
|
|
||||||
@param cancellationToken The cancellation token (optional).
|
|
||||||
@returns A task that will be completed after block has run.
|
|
||||||
If block returns a BFTask, then the task returned from
|
|
||||||
his method will not be completed until that task is completed.
|
|
||||||
*/
|
|
||||||
- (BFTask *)continueWithExecutor:(BFExecutor *)executor
|
|
||||||
block:(BFContinuationBlock)block
|
|
||||||
cancellationToken:(nullable BFCancellationToken *)cancellationToken
|
|
||||||
NS_SWIFT_NAME(continueWith(executor:block:cancellationToken:));
|
|
||||||
|
|
||||||
/*!
|
|
||||||
Identical to continueWithBlock:, except that the block is only run
|
|
||||||
if this task did not produce a cancellation or an error.
|
|
||||||
If it did, then the failure will be propagated to the returned
|
|
||||||
task.
|
|
||||||
@param block The block to be run once this task is complete.
|
|
||||||
@returns A task that will be completed after block has run.
|
|
||||||
If block returns a BFTask, then the task returned from
|
|
||||||
this method will not be completed until that task is completed.
|
|
||||||
*/
|
|
||||||
- (BFTask *)continueWithSuccessBlock:(BFContinuationBlock)block NS_SWIFT_NAME(continueOnSuccessWith(block:));
|
|
||||||
|
|
||||||
/*!
|
|
||||||
Identical to continueWithBlock:, except that the block is only run
|
|
||||||
if this task did not produce a cancellation or an error.
|
|
||||||
If it did, then the failure will be propagated to the returned
|
|
||||||
task.
|
|
||||||
@param block The block to be run once this task is complete.
|
|
||||||
@param cancellationToken The cancellation token (optional).
|
|
||||||
@returns A task that will be completed after block has run.
|
|
||||||
If block returns a BFTask, then the task returned from
|
|
||||||
this method will not be completed until that task is completed.
|
|
||||||
*/
|
|
||||||
- (BFTask *)continueWithSuccessBlock:(BFContinuationBlock)block
|
|
||||||
cancellationToken:(nullable BFCancellationToken *)cancellationToken
|
|
||||||
NS_SWIFT_NAME(continueOnSuccessWith(block:cancellationToken:));
|
|
||||||
|
|
||||||
/*!
|
|
||||||
Identical to continueWithExecutor:withBlock:, except that the block
|
|
||||||
is only run if this task did not produce a cancellation, error, or an error.
|
|
||||||
If it did, then the failure will be propagated to the returned task.
|
|
||||||
@param executor A BFExecutor responsible for determining how the
|
|
||||||
continuation block will be run.
|
|
||||||
@param block The block to be run once this task is complete.
|
|
||||||
@returns A task that will be completed after block has run.
|
|
||||||
If block returns a BFTask, then the task returned from
|
|
||||||
this method will not be completed until that task is completed.
|
|
||||||
*/
|
|
||||||
- (BFTask *)continueWithExecutor:(BFExecutor *)executor
|
|
||||||
withSuccessBlock:(BFContinuationBlock)block NS_SWIFT_NAME(continueOnSuccessWith(executor:block:));
|
|
||||||
|
|
||||||
/*!
|
|
||||||
Identical to continueWithExecutor:withBlock:, except that the block
|
|
||||||
is only run if this task did not produce a cancellation or an error.
|
|
||||||
If it did, then the failure will be propagated to the returned task.
|
|
||||||
@param executor A BFExecutor responsible for determining how the
|
|
||||||
continuation block will be run.
|
|
||||||
@param block The block to be run once this task is complete.
|
|
||||||
@param cancellationToken The cancellation token (optional).
|
|
||||||
@returns A task that will be completed after block has run.
|
|
||||||
If block returns a BFTask, then the task returned from
|
|
||||||
this method will not be completed until that task is completed.
|
|
||||||
*/
|
|
||||||
- (BFTask *)continueWithExecutor:(BFExecutor *)executor
|
|
||||||
successBlock:(BFContinuationBlock)block
|
|
||||||
cancellationToken:(nullable BFCancellationToken *)cancellationToken
|
|
||||||
NS_SWIFT_NAME(continueOnSuccessWith(executor:block:cancellationToken:));
|
|
||||||
|
|
||||||
/*!
|
|
||||||
Waits until this operation is completed.
|
|
||||||
This method is inefficient and consumes a thread resource while
|
|
||||||
it's running. It should be avoided. This method logs a warning
|
|
||||||
message if it is used on the main thread.
|
|
||||||
*/
|
|
||||||
- (void)waitUntilFinished;
|
|
||||||
|
|
||||||
@end
|
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_END
|
|
||||||
465
Example/Pods/Bolts/Bolts/Common/BFTask.m
generated
465
Example/Pods/Bolts/Bolts/Common/BFTask.m
generated
@ -1,465 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2014, Facebook, Inc.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* This source code is licensed under the BSD-style license found in the
|
|
||||||
* LICENSE file in the root directory of this source tree. An additional grant
|
|
||||||
* of patent rights can be found in the PATENTS file in the same directory.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#import "BFTask.h"
|
|
||||||
|
|
||||||
#import <libkern/OSAtomic.h>
|
|
||||||
|
|
||||||
#import "Bolts.h"
|
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_BEGIN
|
|
||||||
|
|
||||||
__attribute__ ((noinline)) void warnBlockingOperationOnMainThread() {
|
|
||||||
NSLog(@"Warning: A long-running operation is being executed on the main thread. \n"
|
|
||||||
" Break on warnBlockingOperationOnMainThread() to debug.");
|
|
||||||
}
|
|
||||||
|
|
||||||
NSString *const BFTaskErrorDomain = @"bolts";
|
|
||||||
NSInteger const kBFMultipleErrorsError = 80175001;
|
|
||||||
|
|
||||||
NSString *const BFTaskMultipleErrorsUserInfoKey = @"errors";
|
|
||||||
|
|
||||||
@interface BFTask () {
|
|
||||||
id _result;
|
|
||||||
NSError *_error;
|
|
||||||
}
|
|
||||||
|
|
||||||
@property (nonatomic, assign, readwrite, getter=isCancelled) BOOL cancelled;
|
|
||||||
@property (nonatomic, assign, readwrite, getter=isFaulted) BOOL faulted;
|
|
||||||
@property (nonatomic, assign, readwrite, getter=isCompleted) BOOL completed;
|
|
||||||
|
|
||||||
@property (nonatomic, strong) NSObject *lock;
|
|
||||||
@property (nonatomic, strong) NSCondition *condition;
|
|
||||||
@property (nonatomic, strong) NSMutableArray *callbacks;
|
|
||||||
|
|
||||||
@end
|
|
||||||
|
|
||||||
@implementation BFTask
|
|
||||||
|
|
||||||
#pragma mark - Initializer
|
|
||||||
|
|
||||||
- (instancetype)init {
|
|
||||||
self = [super init];
|
|
||||||
if (!self) return self;
|
|
||||||
|
|
||||||
_lock = [[NSObject alloc] init];
|
|
||||||
_condition = [[NSCondition alloc] init];
|
|
||||||
_callbacks = [NSMutableArray array];
|
|
||||||
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (instancetype)initWithResult:(nullable id)result {
|
|
||||||
self = [super init];
|
|
||||||
if (!self) return self;
|
|
||||||
|
|
||||||
[self trySetResult:result];
|
|
||||||
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (instancetype)initWithError:(NSError *)error {
|
|
||||||
self = [super init];
|
|
||||||
if (!self) return self;
|
|
||||||
|
|
||||||
[self trySetError:error];
|
|
||||||
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (instancetype)initCancelled {
|
|
||||||
self = [super init];
|
|
||||||
if (!self) return self;
|
|
||||||
|
|
||||||
[self trySetCancelled];
|
|
||||||
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark - Task Class methods
|
|
||||||
|
|
||||||
+ (instancetype)taskWithResult:(nullable id)result {
|
|
||||||
return [[self alloc] initWithResult:result];
|
|
||||||
}
|
|
||||||
|
|
||||||
+ (instancetype)taskWithError:(NSError *)error {
|
|
||||||
return [[self alloc] initWithError:error];
|
|
||||||
}
|
|
||||||
|
|
||||||
+ (instancetype)cancelledTask {
|
|
||||||
return [[self alloc] initCancelled];
|
|
||||||
}
|
|
||||||
|
|
||||||
+ (instancetype)taskForCompletionOfAllTasks:(nullable NSArray<BFTask *> *)tasks {
|
|
||||||
__block int32_t total = (int32_t)tasks.count;
|
|
||||||
if (total == 0) {
|
|
||||||
return [self taskWithResult:nil];
|
|
||||||
}
|
|
||||||
|
|
||||||
__block int32_t cancelled = 0;
|
|
||||||
NSObject *lock = [[NSObject alloc] init];
|
|
||||||
NSMutableArray *errors = [NSMutableArray array];
|
|
||||||
|
|
||||||
BFTaskCompletionSource *tcs = [BFTaskCompletionSource taskCompletionSource];
|
|
||||||
for (BFTask *task in tasks) {
|
|
||||||
[task continueWithBlock:^id(BFTask *t) {
|
|
||||||
if (t.error) {
|
|
||||||
@synchronized (lock) {
|
|
||||||
[errors addObject:t.error];
|
|
||||||
}
|
|
||||||
} else if (t.cancelled) {
|
|
||||||
OSAtomicIncrement32Barrier(&cancelled);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (OSAtomicDecrement32Barrier(&total) == 0) {
|
|
||||||
if (errors.count > 0) {
|
|
||||||
if (errors.count == 1) {
|
|
||||||
tcs.error = [errors firstObject];
|
|
||||||
} else {
|
|
||||||
NSError *error = [NSError errorWithDomain:BFTaskErrorDomain
|
|
||||||
code:kBFMultipleErrorsError
|
|
||||||
userInfo:@{ BFTaskMultipleErrorsUserInfoKey: errors }];
|
|
||||||
tcs.error = error;
|
|
||||||
}
|
|
||||||
} else if (cancelled > 0) {
|
|
||||||
[tcs cancel];
|
|
||||||
} else {
|
|
||||||
tcs.result = nil;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil;
|
|
||||||
}];
|
|
||||||
}
|
|
||||||
return tcs.task;
|
|
||||||
}
|
|
||||||
|
|
||||||
+ (instancetype)taskForCompletionOfAllTasksWithResults:(nullable NSArray<BFTask *> *)tasks {
|
|
||||||
return [[self taskForCompletionOfAllTasks:tasks] continueWithSuccessBlock:^id(BFTask * __unused task) {
|
|
||||||
return [tasks valueForKey:@"result"];
|
|
||||||
}];
|
|
||||||
}
|
|
||||||
|
|
||||||
+ (instancetype)taskForCompletionOfAnyTask:(nullable NSArray<BFTask *> *)tasks
|
|
||||||
{
|
|
||||||
__block int32_t total = (int32_t)tasks.count;
|
|
||||||
if (total == 0) {
|
|
||||||
return [self taskWithResult:nil];
|
|
||||||
}
|
|
||||||
|
|
||||||
__block int completed = 0;
|
|
||||||
__block int32_t cancelled = 0;
|
|
||||||
|
|
||||||
NSObject *lock = [NSObject new];
|
|
||||||
NSMutableArray<NSError *> *errors = [NSMutableArray new];
|
|
||||||
|
|
||||||
BFTaskCompletionSource *source = [BFTaskCompletionSource taskCompletionSource];
|
|
||||||
for (BFTask *task in tasks) {
|
|
||||||
[task continueWithBlock:^id(BFTask *t) {
|
|
||||||
if (t.error != nil) {
|
|
||||||
@synchronized(lock) {
|
|
||||||
[errors addObject:t.error];
|
|
||||||
}
|
|
||||||
} else if (t.cancelled) {
|
|
||||||
OSAtomicIncrement32Barrier(&cancelled);
|
|
||||||
} else {
|
|
||||||
if(OSAtomicCompareAndSwap32Barrier(0, 1, &completed)) {
|
|
||||||
[source setResult:t.result];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (OSAtomicDecrement32Barrier(&total) == 0 &&
|
|
||||||
OSAtomicCompareAndSwap32Barrier(0, 1, &completed)) {
|
|
||||||
if (cancelled > 0) {
|
|
||||||
[source cancel];
|
|
||||||
} else if (errors.count > 0) {
|
|
||||||
if (errors.count == 1) {
|
|
||||||
source.error = errors.firstObject;
|
|
||||||
} else {
|
|
||||||
NSError *error = [NSError errorWithDomain:BFTaskErrorDomain
|
|
||||||
code:kBFMultipleErrorsError
|
|
||||||
userInfo:@{ @"errors": errors }];
|
|
||||||
source.error = error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Abort execution of per tasks continuations
|
|
||||||
return nil;
|
|
||||||
}];
|
|
||||||
}
|
|
||||||
return source.task;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
+ (BFTask<BFVoid> *)taskWithDelay:(int)millis {
|
|
||||||
BFTaskCompletionSource *tcs = [BFTaskCompletionSource taskCompletionSource];
|
|
||||||
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, millis * NSEC_PER_MSEC);
|
|
||||||
dispatch_after(popTime, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void){
|
|
||||||
tcs.result = nil;
|
|
||||||
});
|
|
||||||
return tcs.task;
|
|
||||||
}
|
|
||||||
|
|
||||||
+ (BFTask<BFVoid> *)taskWithDelay:(int)millis cancellationToken:(nullable BFCancellationToken *)token {
|
|
||||||
if (token.cancellationRequested) {
|
|
||||||
return [BFTask cancelledTask];
|
|
||||||
}
|
|
||||||
|
|
||||||
BFTaskCompletionSource *tcs = [BFTaskCompletionSource taskCompletionSource];
|
|
||||||
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, millis * NSEC_PER_MSEC);
|
|
||||||
dispatch_after(popTime, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void){
|
|
||||||
if (token.cancellationRequested) {
|
|
||||||
[tcs cancel];
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
tcs.result = nil;
|
|
||||||
});
|
|
||||||
return tcs.task;
|
|
||||||
}
|
|
||||||
|
|
||||||
+ (instancetype)taskFromExecutor:(BFExecutor *)executor withBlock:(nullable id (^)(void))block {
|
|
||||||
return [[self taskWithResult:nil] continueWithExecutor:executor withBlock:^id(BFTask *task) {
|
|
||||||
return block();
|
|
||||||
}];
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark - Custom Setters/Getters
|
|
||||||
|
|
||||||
- (nullable id)result {
|
|
||||||
@synchronized(self.lock) {
|
|
||||||
return _result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (BOOL)trySetResult:(nullable id)result {
|
|
||||||
@synchronized(self.lock) {
|
|
||||||
if (self.completed) {
|
|
||||||
return NO;
|
|
||||||
}
|
|
||||||
self.completed = YES;
|
|
||||||
_result = result;
|
|
||||||
[self runContinuations];
|
|
||||||
return YES;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (nullable NSError *)error {
|
|
||||||
@synchronized(self.lock) {
|
|
||||||
return _error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (BOOL)trySetError:(NSError *)error {
|
|
||||||
@synchronized(self.lock) {
|
|
||||||
if (self.completed) {
|
|
||||||
return NO;
|
|
||||||
}
|
|
||||||
self.completed = YES;
|
|
||||||
self.faulted = YES;
|
|
||||||
_error = error;
|
|
||||||
[self runContinuations];
|
|
||||||
return YES;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (BOOL)isCancelled {
|
|
||||||
@synchronized(self.lock) {
|
|
||||||
return _cancelled;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (BOOL)isFaulted {
|
|
||||||
@synchronized(self.lock) {
|
|
||||||
return _faulted;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (BOOL)trySetCancelled {
|
|
||||||
@synchronized(self.lock) {
|
|
||||||
if (self.completed) {
|
|
||||||
return NO;
|
|
||||||
}
|
|
||||||
self.completed = YES;
|
|
||||||
self.cancelled = YES;
|
|
||||||
[self runContinuations];
|
|
||||||
return YES;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (BOOL)isCompleted {
|
|
||||||
@synchronized(self.lock) {
|
|
||||||
return _completed;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)runContinuations {
|
|
||||||
@synchronized(self.lock) {
|
|
||||||
[self.condition lock];
|
|
||||||
[self.condition broadcast];
|
|
||||||
[self.condition unlock];
|
|
||||||
for (void (^callback)(void) in self.callbacks) {
|
|
||||||
callback();
|
|
||||||
}
|
|
||||||
[self.callbacks removeAllObjects];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark - Chaining methods
|
|
||||||
|
|
||||||
- (BFTask *)continueWithExecutor:(BFExecutor *)executor withBlock:(BFContinuationBlock)block {
|
|
||||||
return [self continueWithExecutor:executor block:block cancellationToken:nil];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (BFTask *)continueWithExecutor:(BFExecutor *)executor
|
|
||||||
block:(BFContinuationBlock)block
|
|
||||||
cancellationToken:(nullable BFCancellationToken *)cancellationToken {
|
|
||||||
BFTaskCompletionSource *tcs = [BFTaskCompletionSource taskCompletionSource];
|
|
||||||
|
|
||||||
// Capture all of the state that needs to used when the continuation is complete.
|
|
||||||
dispatch_block_t executionBlock = ^{
|
|
||||||
if (cancellationToken.cancellationRequested) {
|
|
||||||
[tcs cancel];
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
id result = block(self);
|
|
||||||
if ([result isKindOfClass:[BFTask class]]) {
|
|
||||||
|
|
||||||
id (^setupWithTask) (BFTask *) = ^id(BFTask *task) {
|
|
||||||
if (cancellationToken.cancellationRequested || task.cancelled) {
|
|
||||||
[tcs cancel];
|
|
||||||
} else if (task.error) {
|
|
||||||
tcs.error = task.error;
|
|
||||||
} else {
|
|
||||||
tcs.result = task.result;
|
|
||||||
}
|
|
||||||
return nil;
|
|
||||||
};
|
|
||||||
|
|
||||||
BFTask *resultTask = (BFTask *)result;
|
|
||||||
|
|
||||||
if (resultTask.completed) {
|
|
||||||
setupWithTask(resultTask);
|
|
||||||
} else {
|
|
||||||
[resultTask continueWithBlock:setupWithTask];
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
tcs.result = result;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
BOOL completed;
|
|
||||||
@synchronized(self.lock) {
|
|
||||||
completed = self.completed;
|
|
||||||
if (!completed) {
|
|
||||||
[self.callbacks addObject:[^{
|
|
||||||
[executor execute:executionBlock];
|
|
||||||
} copy]];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (completed) {
|
|
||||||
[executor execute:executionBlock];
|
|
||||||
}
|
|
||||||
|
|
||||||
return tcs.task;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (BFTask *)continueWithBlock:(BFContinuationBlock)block {
|
|
||||||
return [self continueWithExecutor:[BFExecutor defaultExecutor] block:block cancellationToken:nil];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (BFTask *)continueWithBlock:(BFContinuationBlock)block cancellationToken:(nullable BFCancellationToken *)cancellationToken {
|
|
||||||
return [self continueWithExecutor:[BFExecutor defaultExecutor] block:block cancellationToken:cancellationToken];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (BFTask *)continueWithExecutor:(BFExecutor *)executor
|
|
||||||
withSuccessBlock:(BFContinuationBlock)block {
|
|
||||||
return [self continueWithExecutor:executor successBlock:block cancellationToken:nil];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (BFTask *)continueWithExecutor:(BFExecutor *)executor
|
|
||||||
successBlock:(BFContinuationBlock)block
|
|
||||||
cancellationToken:(nullable BFCancellationToken *)cancellationToken {
|
|
||||||
if (cancellationToken.cancellationRequested) {
|
|
||||||
return [BFTask cancelledTask];
|
|
||||||
}
|
|
||||||
|
|
||||||
return [self continueWithExecutor:executor block:^id(BFTask *task) {
|
|
||||||
if (task.faulted || task.cancelled) {
|
|
||||||
return task;
|
|
||||||
} else {
|
|
||||||
return block(task);
|
|
||||||
}
|
|
||||||
} cancellationToken:cancellationToken];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (BFTask *)continueWithSuccessBlock:(BFContinuationBlock)block {
|
|
||||||
return [self continueWithExecutor:[BFExecutor defaultExecutor] successBlock:block cancellationToken:nil];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (BFTask *)continueWithSuccessBlock:(BFContinuationBlock)block cancellationToken:(nullable BFCancellationToken *)cancellationToken {
|
|
||||||
return [self continueWithExecutor:[BFExecutor defaultExecutor] successBlock:block cancellationToken:cancellationToken];
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark - Syncing Task (Avoid it)
|
|
||||||
|
|
||||||
- (void)warnOperationOnMainThread {
|
|
||||||
warnBlockingOperationOnMainThread();
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)waitUntilFinished {
|
|
||||||
if ([NSThread isMainThread]) {
|
|
||||||
[self warnOperationOnMainThread];
|
|
||||||
}
|
|
||||||
|
|
||||||
@synchronized(self.lock) {
|
|
||||||
if (self.completed) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
[self.condition lock];
|
|
||||||
}
|
|
||||||
// TODO: (nlutsenko) Restructure this to use Bolts-Swift thread access synchronization architecture
|
|
||||||
// In the meantime, it's absolutely safe to get `_completed` aka an ivar, as long as it's a `BOOL` aka less than word size.
|
|
||||||
while (!_completed) {
|
|
||||||
[self.condition wait];
|
|
||||||
}
|
|
||||||
[self.condition unlock];
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark - NSObject
|
|
||||||
|
|
||||||
- (NSString *)description {
|
|
||||||
// Acquire the data from the locked properties
|
|
||||||
BOOL completed;
|
|
||||||
BOOL cancelled;
|
|
||||||
BOOL faulted;
|
|
||||||
NSString *resultDescription = nil;
|
|
||||||
|
|
||||||
@synchronized(self.lock) {
|
|
||||||
completed = self.completed;
|
|
||||||
cancelled = self.cancelled;
|
|
||||||
faulted = self.faulted;
|
|
||||||
resultDescription = completed ? [NSString stringWithFormat:@" result = %@", self.result] : @"";
|
|
||||||
}
|
|
||||||
|
|
||||||
// Description string includes status information and, if available, the
|
|
||||||
// result since in some ways this is what a promise actually "is".
|
|
||||||
return [NSString stringWithFormat:@"<%@: %p; completed = %@; cancelled = %@; faulted = %@;%@>",
|
|
||||||
NSStringFromClass([self class]),
|
|
||||||
self,
|
|
||||||
completed ? @"YES" : @"NO",
|
|
||||||
cancelled ? @"YES" : @"NO",
|
|
||||||
faulted ? @"YES" : @"NO",
|
|
||||||
resultDescription];
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_END
|
|
||||||
@ -1,75 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2014, Facebook, Inc.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* This source code is licensed under the BSD-style license found in the
|
|
||||||
* LICENSE file in the root directory of this source tree. An additional grant
|
|
||||||
* of patent rights can be found in the PATENTS file in the same directory.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#import <Foundation/Foundation.h>
|
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_BEGIN
|
|
||||||
|
|
||||||
@class BFTask<__covariant ResultType>;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
A BFTaskCompletionSource represents the producer side of tasks.
|
|
||||||
It is a task that also has methods for changing the state of the
|
|
||||||
task by settings its completion values.
|
|
||||||
*/
|
|
||||||
@interface BFTaskCompletionSource<__covariant ResultType> : NSObject
|
|
||||||
|
|
||||||
/*!
|
|
||||||
Creates a new unfinished task.
|
|
||||||
*/
|
|
||||||
+ (instancetype)taskCompletionSource;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
The task associated with this TaskCompletionSource.
|
|
||||||
*/
|
|
||||||
@property (nonatomic, strong, readonly) BFTask<ResultType> *task;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
Completes the task by setting the result.
|
|
||||||
Attempting to set this for a completed task will raise an exception.
|
|
||||||
@param result The result of the task.
|
|
||||||
*/
|
|
||||||
- (void)setResult:(nullable ResultType)result NS_SWIFT_NAME(set(result:));
|
|
||||||
|
|
||||||
/*!
|
|
||||||
Completes the task by setting the error.
|
|
||||||
Attempting to set this for a completed task will raise an exception.
|
|
||||||
@param error The error for the task.
|
|
||||||
*/
|
|
||||||
- (void)setError:(NSError *)error NS_SWIFT_NAME(set(error:));
|
|
||||||
|
|
||||||
/*!
|
|
||||||
Completes the task by marking it as cancelled.
|
|
||||||
Attempting to set this for a completed task will raise an exception.
|
|
||||||
*/
|
|
||||||
- (void)cancel;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
Sets the result of the task if it wasn't already completed.
|
|
||||||
@returns whether the new value was set.
|
|
||||||
*/
|
|
||||||
- (BOOL)trySetResult:(nullable ResultType)result NS_SWIFT_NAME(trySet(result:));
|
|
||||||
|
|
||||||
/*!
|
|
||||||
Sets the error of the task if it wasn't already completed.
|
|
||||||
@param error The error for the task.
|
|
||||||
@returns whether the new value was set.
|
|
||||||
*/
|
|
||||||
- (BOOL)trySetError:(NSError *)error NS_SWIFT_NAME(trySet(error:));
|
|
||||||
|
|
||||||
/*!
|
|
||||||
Sets the cancellation state of the task if it wasn't already completed.
|
|
||||||
@returns whether the new value was set.
|
|
||||||
*/
|
|
||||||
- (BOOL)trySetCancelled;
|
|
||||||
|
|
||||||
@end
|
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_END
|
|
||||||
@ -1,79 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2014, Facebook, Inc.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* This source code is licensed under the BSD-style license found in the
|
|
||||||
* LICENSE file in the root directory of this source tree. An additional grant
|
|
||||||
* of patent rights can be found in the PATENTS file in the same directory.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#import "BFTaskCompletionSource.h"
|
|
||||||
|
|
||||||
#import "BFTask.h"
|
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_BEGIN
|
|
||||||
|
|
||||||
@interface BFTask (BFTaskCompletionSource)
|
|
||||||
|
|
||||||
- (BOOL)trySetResult:(nullable id)result;
|
|
||||||
- (BOOL)trySetError:(NSError *)error;
|
|
||||||
- (BOOL)trySetCancelled;
|
|
||||||
|
|
||||||
@end
|
|
||||||
|
|
||||||
@implementation BFTaskCompletionSource
|
|
||||||
|
|
||||||
#pragma mark - Initializer
|
|
||||||
|
|
||||||
+ (instancetype)taskCompletionSource {
|
|
||||||
return [[self alloc] init];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (instancetype)init {
|
|
||||||
self = [super init];
|
|
||||||
if (!self) return self;
|
|
||||||
|
|
||||||
_task = [[BFTask alloc] init];
|
|
||||||
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark - Custom Setters/Getters
|
|
||||||
|
|
||||||
- (void)setResult:(nullable id)result {
|
|
||||||
if (![self.task trySetResult:result]) {
|
|
||||||
[NSException raise:NSInternalInconsistencyException
|
|
||||||
format:@"Cannot set the result on a completed task."];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)setError:(NSError *)error {
|
|
||||||
if (![self.task trySetError:error]) {
|
|
||||||
[NSException raise:NSInternalInconsistencyException
|
|
||||||
format:@"Cannot set the error on a completed task."];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)cancel {
|
|
||||||
if (![self.task trySetCancelled]) {
|
|
||||||
[NSException raise:NSInternalInconsistencyException
|
|
||||||
format:@"Cannot cancel a completed task."];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (BOOL)trySetResult:(nullable id)result {
|
|
||||||
return [self.task trySetResult:result];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (BOOL)trySetError:(NSError *)error {
|
|
||||||
return [self.task trySetError:error];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (BOOL)trySetCancelled {
|
|
||||||
return [self.task trySetCancelled];
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_END
|
|
||||||
39
Example/Pods/Bolts/Bolts/Common/Bolts.h
generated
39
Example/Pods/Bolts/Bolts/Common/Bolts.h
generated
@ -1,39 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2014, Facebook, Inc.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* This source code is licensed under the BSD-style license found in the
|
|
||||||
* LICENSE file in the root directory of this source tree. An additional grant
|
|
||||||
* of patent rights can be found in the PATENTS file in the same directory.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#import <Bolts/BFCancellationToken.h>
|
|
||||||
#import <Bolts/BFCancellationTokenRegistration.h>
|
|
||||||
#import <Bolts/BFCancellationTokenSource.h>
|
|
||||||
#import <Bolts/BFExecutor.h>
|
|
||||||
#import <Bolts/BFGeneric.h>
|
|
||||||
#import <Bolts/BFTask.h>
|
|
||||||
#import <Bolts/BFTaskCompletionSource.h>
|
|
||||||
|
|
||||||
#if __has_include(<Bolts/BFAppLink.h>) && TARGET_OS_IPHONE && !TARGET_OS_WATCH && !TARGET_OS_TV
|
|
||||||
#import <Bolts/BFAppLink.h>
|
|
||||||
#import <Bolts/BFAppLinkNavigation.h>
|
|
||||||
#import <Bolts/BFAppLinkResolving.h>
|
|
||||||
#import <Bolts/BFAppLinkReturnToRefererController.h>
|
|
||||||
#import <Bolts/BFAppLinkReturnToRefererView.h>
|
|
||||||
#import <Bolts/BFAppLinkTarget.h>
|
|
||||||
#import <Bolts/BFMeasurementEvent.h>
|
|
||||||
#import <Bolts/BFURL.h>
|
|
||||||
#import <Bolts/BFWebViewAppLinkResolver.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_BEGIN
|
|
||||||
|
|
||||||
/**
|
|
||||||
A string containing the version of the Bolts Framework used by the current application.
|
|
||||||
*/
|
|
||||||
extern NSString *const BoltsFrameworkVersionString;
|
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_END
|
|
||||||
17
Example/Pods/Bolts/Bolts/Common/Bolts.m
generated
17
Example/Pods/Bolts/Bolts/Common/Bolts.m
generated
@ -1,17 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2014, Facebook, Inc.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* This source code is licensed under the BSD-style license found in the
|
|
||||||
* LICENSE file in the root directory of this source tree. An additional grant
|
|
||||||
* of patent rights can be found in the PATENTS file in the same directory.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#import "Bolts.h"
|
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_BEGIN
|
|
||||||
|
|
||||||
NSString *const BoltsFrameworkVersionString = @"1.9.0";
|
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_END
|
|
||||||
49
Example/Pods/Bolts/Bolts/iOS/BFAppLink.h
generated
49
Example/Pods/Bolts/Bolts/iOS/BFAppLink.h
generated
@ -1,49 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2014, Facebook, Inc.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* This source code is licensed under the BSD-style license found in the
|
|
||||||
* LICENSE file in the root directory of this source tree. An additional grant
|
|
||||||
* of patent rights can be found in the PATENTS file in the same directory.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#import <Foundation/Foundation.h>
|
|
||||||
|
|
||||||
/*! The version of the App Link protocol that this library supports */
|
|
||||||
FOUNDATION_EXPORT NSString *const BFAppLinkVersion;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
Contains App Link metadata relevant for navigation on this device
|
|
||||||
derived from the HTML at a given URL.
|
|
||||||
*/
|
|
||||||
@interface BFAppLink : NSObject
|
|
||||||
|
|
||||||
/*!
|
|
||||||
Creates a BFAppLink with the given list of BFAppLinkTargets and target URL.
|
|
||||||
|
|
||||||
Generally, this will only be used by implementers of the BFAppLinkResolving 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 BFAppLinkTargets 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 *)targets
|
|
||||||
webURL:(NSURL *)webURL;
|
|
||||||
|
|
||||||
/*! The URL from which this BFAppLink 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 *targets;
|
|
||||||
|
|
||||||
/*! The fallback web URL to use if no targets are installed on this device. */
|
|
||||||
@property (nonatomic, strong, readonly) NSURL *webURL;
|
|
||||||
|
|
||||||
@end
|
|
||||||
62
Example/Pods/Bolts/Bolts/iOS/BFAppLink.m
generated
62
Example/Pods/Bolts/Bolts/iOS/BFAppLink.m
generated
@ -1,62 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2014, Facebook, Inc.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* This source code is licensed under the BSD-style license found in the
|
|
||||||
* LICENSE file in the root directory of this source tree. An additional grant
|
|
||||||
* of patent rights can be found in the PATENTS file in the same directory.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#import "BFAppLink_Internal.h"
|
|
||||||
|
|
||||||
NSString *const BFAppLinkDataParameterName = @"al_applink_data";
|
|
||||||
NSString *const BFAppLinkTargetKeyName = @"target_url";
|
|
||||||
NSString *const BFAppLinkUserAgentKeyName = @"user_agent";
|
|
||||||
NSString *const BFAppLinkExtrasKeyName = @"extras";
|
|
||||||
NSString *const BFAppLinkRefererAppLink = @"referer_app_link";
|
|
||||||
NSString *const BFAppLinkRefererAppName = @"app_name";
|
|
||||||
NSString *const BFAppLinkRefererUrl = @"url";
|
|
||||||
NSString *const BFAppLinkVersionKeyName = @"version";
|
|
||||||
NSString *const BFAppLinkVersion = @"1.0";
|
|
||||||
|
|
||||||
@interface BFAppLink ()
|
|
||||||
|
|
||||||
@property (nonatomic, strong, readwrite) NSURL *sourceURL;
|
|
||||||
@property (nonatomic, copy, readwrite) NSArray *targets;
|
|
||||||
@property (nonatomic, strong, readwrite) NSURL *webURL;
|
|
||||||
|
|
||||||
@property (nonatomic, assign, readwrite, getter=isBackToReferrer) BOOL backToReferrer;
|
|
||||||
|
|
||||||
@end
|
|
||||||
|
|
||||||
@implementation BFAppLink
|
|
||||||
|
|
||||||
+ (instancetype)appLinkWithSourceURL:(NSURL *)sourceURL
|
|
||||||
targets:(NSArray *)targets
|
|
||||||
webURL:(NSURL *)webURL
|
|
||||||
isBackToReferrer:(BOOL)isBackToReferrer {
|
|
||||||
BFAppLink *link = [[self alloc] initWithIsBackToReferrer:isBackToReferrer];
|
|
||||||
link.sourceURL = sourceURL;
|
|
||||||
link.targets = [targets copy];
|
|
||||||
link.webURL = webURL;
|
|
||||||
return link;
|
|
||||||
}
|
|
||||||
|
|
||||||
+ (instancetype)appLinkWithSourceURL:(NSURL *)sourceURL
|
|
||||||
targets:(NSArray *)targets
|
|
||||||
webURL:(NSURL *)webURL {
|
|
||||||
return [self appLinkWithSourceURL:sourceURL
|
|
||||||
targets:targets
|
|
||||||
webURL:webURL
|
|
||||||
isBackToReferrer:NO];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (BFAppLink *)initWithIsBackToReferrer:(BOOL)backToReferrer {
|
|
||||||
if ((self = [super init])) {
|
|
||||||
_backToReferrer = backToReferrer;
|
|
||||||
}
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
|
||||||
114
Example/Pods/Bolts/Bolts/iOS/BFAppLinkNavigation.h
generated
114
Example/Pods/Bolts/Bolts/iOS/BFAppLinkNavigation.h
generated
@ -1,114 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2014, Facebook, Inc.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* This source code is licensed under the BSD-style license found in the
|
|
||||||
* LICENSE file in the root directory of this source tree. An additional grant
|
|
||||||
* of patent rights can be found in the PATENTS file in the same directory.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#import <Foundation/Foundation.h>
|
|
||||||
|
|
||||||
#import <Bolts/BFAppLink.h>
|
|
||||||
|
|
||||||
/*!
|
|
||||||
The result of calling navigate on a BFAppLinkNavigation
|
|
||||||
*/
|
|
||||||
typedef NS_ENUM(NSInteger, BFAppLinkNavigationType) {
|
|
||||||
/*! Indicates that the navigation failed and no app was opened */
|
|
||||||
BFAppLinkNavigationTypeFailure,
|
|
||||||
/*! Indicates that the navigation succeeded by opening the URL in the browser */
|
|
||||||
BFAppLinkNavigationTypeBrowser,
|
|
||||||
/*! Indicates that the navigation succeeded by opening the URL in an app on the device */
|
|
||||||
BFAppLinkNavigationTypeApp
|
|
||||||
};
|
|
||||||
|
|
||||||
@protocol BFAppLinkResolving;
|
|
||||||
@class BFTask;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
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 BFAppLinkNavigations themselves.
|
|
||||||
*/
|
|
||||||
NS_EXTENSION_UNAVAILABLE_IOS("Not available in app extension")
|
|
||||||
@interface BFAppLinkNavigation : 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 *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 *appLinkData;
|
|
||||||
|
|
||||||
/*! The AppLink to navigate to */
|
|
||||||
@property (nonatomic, strong, readonly) BFAppLink *appLink;
|
|
||||||
|
|
||||||
/*! Creates an AppLinkNavigation with the given link, extras, and App Link data */
|
|
||||||
+ (instancetype)navigationWithAppLink:(BFAppLink *)appLink
|
|
||||||
extras:(NSDictionary *)extras
|
|
||||||
appLinkData:(NSDictionary *)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 *)callbackAppLinkDataForAppWithName:(NSString *)appName url:(NSString *)url;
|
|
||||||
|
|
||||||
/*! Performs the navigation */
|
|
||||||
- (BFAppLinkNavigationType)navigate:(NSError **)error;
|
|
||||||
|
|
||||||
/*! Returns a BFAppLink for the given URL */
|
|
||||||
+ (BFTask *)resolveAppLinkInBackground:(NSURL *)destination;
|
|
||||||
|
|
||||||
/*! Returns a BFAppLink for the given URL using the given App Link resolution strategy */
|
|
||||||
+ (BFTask *)resolveAppLinkInBackground:(NSURL *)destination resolver:(id<BFAppLinkResolving>)resolver;
|
|
||||||
|
|
||||||
/*! Navigates to a BFAppLink and returns whether it opened in-app or in-browser */
|
|
||||||
+ (BFAppLinkNavigationType)navigateToAppLink:(BFAppLink *)link error:(NSError **)error;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
Returns a BFAppLinkNavigationType based on a BFAppLink.
|
|
||||||
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.)
|
|
||||||
*/
|
|
||||||
+ (BFAppLinkNavigationType)navigationTypeForLink:(BFAppLink *)link;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
Return navigation type for current instance.
|
|
||||||
No-side-effect version of navigate:
|
|
||||||
*/
|
|
||||||
- (BFAppLinkNavigationType)navigationType;
|
|
||||||
|
|
||||||
/*! Navigates to a URL (an asynchronous action) and returns a BFNavigationType */
|
|
||||||
+ (BFTask *)navigateToURLInBackground:(NSURL *)destination;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
Navigates to a URL (an asynchronous action) using the given App Link resolution
|
|
||||||
strategy and returns a BFNavigationType
|
|
||||||
*/
|
|
||||||
+ (BFTask *)navigateToURLInBackground:(NSURL *)destination resolver:(id<BFAppLinkResolving>)resolver;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
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<BFAppLinkResolving>)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 Bolts.
|
|
||||||
*/
|
|
||||||
+ (void)setDefaultResolver:(id<BFAppLinkResolving>)resolver;
|
|
||||||
|
|
||||||
@end
|
|
||||||
284
Example/Pods/Bolts/Bolts/iOS/BFAppLinkNavigation.m
generated
284
Example/Pods/Bolts/Bolts/iOS/BFAppLinkNavigation.m
generated
@ -1,284 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2014, Facebook, Inc.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* This source code is licensed under the BSD-style license found in the
|
|
||||||
* LICENSE file in the root directory of this source tree. An additional grant
|
|
||||||
* of patent rights can be found in the PATENTS file in the same directory.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#import "BFAppLinkNavigation.h"
|
|
||||||
|
|
||||||
#import <Bolts/Bolts.h>
|
|
||||||
|
|
||||||
#import "BFMeasurementEvent_Internal.h"
|
|
||||||
#import "BFAppLink_Internal.h"
|
|
||||||
|
|
||||||
FOUNDATION_EXPORT NSString *const BFAppLinkDataParameterName;
|
|
||||||
FOUNDATION_EXPORT NSString *const BFAppLinkTargetKeyName;
|
|
||||||
FOUNDATION_EXPORT NSString *const BFAppLinkUserAgentKeyName;
|
|
||||||
FOUNDATION_EXPORT NSString *const BFAppLinkExtrasKeyName;
|
|
||||||
FOUNDATION_EXPORT NSString *const BFAppLinkVersionKeyName;
|
|
||||||
FOUNDATION_EXPORT NSString *const BFAppLinkRefererAppLink;
|
|
||||||
FOUNDATION_EXPORT NSString *const BFAppLinkRefererAppName;
|
|
||||||
FOUNDATION_EXPORT NSString *const BFAppLinkRefererUrl;
|
|
||||||
|
|
||||||
static id<BFAppLinkResolving> defaultResolver;
|
|
||||||
|
|
||||||
@interface BFAppLinkNavigation ()
|
|
||||||
|
|
||||||
@property (nonatomic, copy, readwrite) NSDictionary *extras;
|
|
||||||
@property (nonatomic, copy, readwrite) NSDictionary *appLinkData;
|
|
||||||
@property (nonatomic, strong, readwrite) BFAppLink *appLink;
|
|
||||||
|
|
||||||
@end
|
|
||||||
|
|
||||||
@implementation BFAppLinkNavigation
|
|
||||||
|
|
||||||
+ (instancetype)navigationWithAppLink:(BFAppLink *)appLink
|
|
||||||
extras:(NSDictionary *)extras
|
|
||||||
appLinkData:(NSDictionary *)appLinkData {
|
|
||||||
BFAppLinkNavigation *navigation = [[self alloc] init];
|
|
||||||
navigation.appLink = appLink;
|
|
||||||
navigation.extras = extras;
|
|
||||||
navigation.appLinkData = appLinkData;
|
|
||||||
return navigation;
|
|
||||||
}
|
|
||||||
|
|
||||||
+ (NSDictionary *)callbackAppLinkDataForAppWithName:(NSString *)appName url:(NSString *)url {
|
|
||||||
return @{BFAppLinkRefererAppLink: @{BFAppLinkRefererAppName: appName, BFAppLinkRefererUrl: url}};
|
|
||||||
}
|
|
||||||
|
|
||||||
- (NSString *)stringByEscapingQueryString:(NSString *)string {
|
|
||||||
#if __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_7_0 || __MAC_OS_X_VERSION_MIN_REQUIRED >= __MAC_10_9
|
|
||||||
return [string stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];
|
|
||||||
#else
|
|
||||||
return (NSString *)CFBridgingRelease(CFURLCreateStringByAddingPercentEscapes(NULL,
|
|
||||||
(CFStringRef)string,
|
|
||||||
NULL,
|
|
||||||
(CFStringRef) @":/?#[]@!$&'()*+,;=",
|
|
||||||
kCFStringEncodingUTF8));
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
- (NSURL *)appLinkURLWithTargetURL:(NSURL *)targetUrl error:(NSError **)error {
|
|
||||||
NSMutableDictionary *appLinkData = [NSMutableDictionary dictionaryWithDictionary:self.appLinkData ?: @{}];
|
|
||||||
|
|
||||||
// Add applink protocol data
|
|
||||||
if (!appLinkData[BFAppLinkUserAgentKeyName]) {
|
|
||||||
appLinkData[BFAppLinkUserAgentKeyName] = [NSString stringWithFormat:@"Bolts iOS %@", BoltsFrameworkVersionString];
|
|
||||||
}
|
|
||||||
if (!appLinkData[BFAppLinkVersionKeyName]) {
|
|
||||||
appLinkData[BFAppLinkVersionKeyName] = BFAppLinkVersion;
|
|
||||||
}
|
|
||||||
appLinkData[BFAppLinkTargetKeyName] = [self.appLink.sourceURL absoluteString];
|
|
||||||
appLinkData[BFAppLinkExtrasKeyName] = 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 ? @"&" : @"?",
|
|
||||||
BFAppLinkDataParameterName,
|
|
||||||
encoded];
|
|
||||||
|
|
||||||
return [NSURL URLWithString:endUrlString];
|
|
||||||
} else {
|
|
||||||
if (error) {
|
|
||||||
*error = jsonError;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If there was an error encoding the app link data, fail hard.
|
|
||||||
return nil;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (BFAppLinkNavigationType)navigate:(NSError **)error {
|
|
||||||
NSURL *openedURL = nil;
|
|
||||||
NSError *encodingError = nil;
|
|
||||||
BFAppLinkNavigationType retType = BFAppLinkNavigationTypeFailure;
|
|
||||||
|
|
||||||
// Find the first eligible/launchable target in the BFAppLink.
|
|
||||||
for (BFAppLinkTarget *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 = BFAppLinkNavigationTypeApp;
|
|
||||||
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 = BFAppLinkNavigationTypeBrowser;
|
|
||||||
openedURL = appLinkBrowserURL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[self postAppLinkNavigateEventNotificationWithTargetURL:openedURL
|
|
||||||
error:error ? *error : nil
|
|
||||||
type:retType];
|
|
||||||
return retType;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)postAppLinkNavigateEventNotificationWithTargetURL:(NSURL *)outputURL error:(NSError *)error type:(BFAppLinkNavigationType)type {
|
|
||||||
NSString *const EVENT_YES_VAL = @"1";
|
|
||||||
NSString *const EVENT_NO_VAL = @"0";
|
|
||||||
NSMutableDictionary *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 BFAppLinkNavigationTypeFailure:
|
|
||||||
success = EVENT_NO_VAL;
|
|
||||||
linkType = @"fail";
|
|
||||||
break;
|
|
||||||
case BFAppLinkNavigationTypeBrowser:
|
|
||||||
success = EVENT_YES_VAL;
|
|
||||||
linkType = @"web";
|
|
||||||
break;
|
|
||||||
case BFAppLinkNavigationTypeApp:
|
|
||||||
success = EVENT_YES_VAL;
|
|
||||||
linkType = @"app";
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (success) {
|
|
||||||
logData[@"success"] = success;
|
|
||||||
}
|
|
||||||
if (linkType) {
|
|
||||||
logData[@"type"] = linkType;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ([self.appLink isBackToReferrer]) {
|
|
||||||
[BFMeasurementEvent postNotificationForEventName:BFAppLinkNavigateBackToReferrerEventName args:logData];
|
|
||||||
} else {
|
|
||||||
[BFMeasurementEvent postNotificationForEventName:BFAppLinkNavigateOutEventName args:logData];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
+ (BFTask *)resolveAppLinkInBackground:(NSURL *)destination resolver:(id<BFAppLinkResolving>)resolver {
|
|
||||||
return [resolver appLinkFromURLInBackground:destination];
|
|
||||||
}
|
|
||||||
|
|
||||||
+ (BFTask *)resolveAppLinkInBackground:(NSURL *)destination {
|
|
||||||
return [self resolveAppLinkInBackground:destination resolver:[self defaultResolver]];
|
|
||||||
}
|
|
||||||
|
|
||||||
+ (BFTask *)navigateToURLInBackground:(NSURL *)destination {
|
|
||||||
return [self navigateToURLInBackground:destination
|
|
||||||
resolver:[self defaultResolver]];
|
|
||||||
}
|
|
||||||
|
|
||||||
+ (BFTask *)navigateToURLInBackground:(NSURL *)destination
|
|
||||||
resolver:(id<BFAppLinkResolving>)resolver {
|
|
||||||
BFTask *resolutionTask = [self resolveAppLinkInBackground:destination
|
|
||||||
resolver:resolver];
|
|
||||||
return [resolutionTask continueWithExecutor:[BFExecutor mainThreadExecutor]
|
|
||||||
withSuccessBlock:^id(BFTask *task) {
|
|
||||||
NSError *error = nil;
|
|
||||||
BFAppLinkNavigationType result = [self navigateToAppLink:task.result
|
|
||||||
error:&error];
|
|
||||||
if (error) {
|
|
||||||
return [BFTask taskWithError:error];
|
|
||||||
} else {
|
|
||||||
return @(result);
|
|
||||||
}
|
|
||||||
}];
|
|
||||||
}
|
|
||||||
|
|
||||||
+ (BFAppLinkNavigationType)navigateToAppLink:(BFAppLink *)link error:(NSError **)error {
|
|
||||||
return [[BFAppLinkNavigation navigationWithAppLink:link
|
|
||||||
extras:nil
|
|
||||||
appLinkData:nil] navigate:error];
|
|
||||||
}
|
|
||||||
|
|
||||||
+ (BFAppLinkNavigationType)navigationTypeForLink:(BFAppLink *)link {
|
|
||||||
return [[self navigationWithAppLink:link extras:nil appLinkData:nil] navigationType];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (BFAppLinkNavigationType)navigationType {
|
|
||||||
BFAppLinkTarget *eligibleTarget = nil;
|
|
||||||
for (BFAppLinkTarget *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 BFAppLinkNavigationTypeApp;
|
|
||||||
} else {
|
|
||||||
return BFAppLinkNavigationTypeFailure;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (self.appLink.webURL != nil) {
|
|
||||||
NSURL *appLinkURL = [self appLinkURLWithTargetURL:eligibleTarget.URL error:nil];
|
|
||||||
if (appLinkURL != nil) {
|
|
||||||
return BFAppLinkNavigationTypeBrowser;
|
|
||||||
} else {
|
|
||||||
return BFAppLinkNavigationTypeFailure;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return BFAppLinkNavigationTypeFailure;
|
|
||||||
}
|
|
||||||
|
|
||||||
+ (id<BFAppLinkResolving>)defaultResolver {
|
|
||||||
if (defaultResolver) {
|
|
||||||
return defaultResolver;
|
|
||||||
}
|
|
||||||
return [BFWebViewAppLinkResolver sharedInstance];
|
|
||||||
}
|
|
||||||
|
|
||||||
+ (void)setDefaultResolver:(id<BFAppLinkResolving>)resolver {
|
|
||||||
defaultResolver = resolver;
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
|
||||||
30
Example/Pods/Bolts/Bolts/iOS/BFAppLinkResolving.h
generated
30
Example/Pods/Bolts/Bolts/iOS/BFAppLinkResolving.h
generated
@ -1,30 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2014, Facebook, Inc.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* This source code is licensed under the BSD-style license found in the
|
|
||||||
* LICENSE file in the root directory of this source tree. An additional grant
|
|
||||||
* of patent rights can be found in the PATENTS file in the same directory.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#import <Foundation/Foundation.h>
|
|
||||||
|
|
||||||
@class BFTask;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
Implement this protocol to provide an alternate strategy for resolving
|
|
||||||
App Links that may include pre-fetching, caching, or querying for App Link
|
|
||||||
data from an index provided by a service provider.
|
|
||||||
*/
|
|
||||||
@protocol BFAppLinkResolving <NSObject>
|
|
||||||
|
|
||||||
/*!
|
|
||||||
Asynchronously resolves App Link data for a given URL.
|
|
||||||
|
|
||||||
@param url The URL to resolve into an App Link.
|
|
||||||
@returns A BFTask that will return a BFAppLink for the given URL.
|
|
||||||
*/
|
|
||||||
- (BFTask *)appLinkFromURLInBackground:(NSURL *)url NS_EXTENSION_UNAVAILABLE_IOS("Not available in app extension");
|
|
||||||
|
|
||||||
@end
|
|
||||||
@ -1,88 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2014, Facebook, Inc.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* This source code is licensed under the BSD-style license found in the
|
|
||||||
* LICENSE file in the root directory of this source tree. An additional grant
|
|
||||||
* of patent rights can be found in the PATENTS file in the same directory.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#import <Foundation/Foundation.h>
|
|
||||||
#import <UIKit/UIKit.h>
|
|
||||||
|
|
||||||
#import <Bolts/BFAppLinkReturnToRefererView.h>
|
|
||||||
|
|
||||||
@class BFAppLink;
|
|
||||||
@class BFAppLinkReturnToRefererController;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
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 BFAppLinkReturnToRefererControllerDelegate <NSObject>
|
|
||||||
|
|
||||||
@optional
|
|
||||||
|
|
||||||
/*! Called when the user has tapped to navigate, but before the navigation has been performed. */
|
|
||||||
- (void)returnToRefererController:(BFAppLinkReturnToRefererController *)controller
|
|
||||||
willNavigateToAppLink:(BFAppLink *)appLink;
|
|
||||||
|
|
||||||
/*! Called after the navigation has been attempted, with an indication of whether the referer
|
|
||||||
app link was successfully opened. */
|
|
||||||
- (void)returnToRefererController:(BFAppLinkReturnToRefererController *)controller
|
|
||||||
didNavigateToAppLink:(BFAppLink *)url
|
|
||||||
type:(BFAppLinkNavigationType)type;
|
|
||||||
|
|
||||||
@end
|
|
||||||
|
|
||||||
/*!
|
|
||||||
A controller class that implements default behavior for a BFAppLinkReturnToRefererView, 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 BFAppLinkReturnToRefererController : NSObject <BFAppLinkReturnToRefererViewDelegate>
|
|
||||||
|
|
||||||
/*!
|
|
||||||
The delegate that will be notified when the user navigates back to the referer.
|
|
||||||
*/
|
|
||||||
@property (nonatomic, weak) id<BFAppLinkReturnToRefererControllerDelegate> delegate;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
The BFAppLinkReturnToRefererView this controller is controlling.
|
|
||||||
*/
|
|
||||||
@property (nonatomic, strong) BFAppLinkReturnToRefererView *view;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
Initializes a controller suitable for controlling a BFAppLinkReturnToRefererView that is to be displayed
|
|
||||||
contained within another UIView (i.e., not displayed above the navigation bar).
|
|
||||||
*/
|
|
||||||
- (instancetype)init;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
Initializes a controller suitable for controlling a BFAppLinkReturnToRefererView 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 BFAppLinkReturnToRefererView with the specified referer information. If nil or missing data,
|
|
||||||
the view will not be displayed. */
|
|
||||||
- (void)showViewForRefererAppLink:(BFAppLink *)refererAppLink;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
Shows the BFAppLinkReturnToRefererView 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
|
|
||||||
@ -1,230 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2014, Facebook, Inc.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* This source code is licensed under the BSD-style license found in the
|
|
||||||
* LICENSE file in the root directory of this source tree. An additional grant
|
|
||||||
* of patent rights can be found in the PATENTS file in the same directory.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#import "BFAppLinkReturnToRefererController.h"
|
|
||||||
|
|
||||||
#import "BFAppLink.h"
|
|
||||||
#import "BFAppLinkReturnToRefererView_Internal.h"
|
|
||||||
#import "BFURL_Internal.h"
|
|
||||||
|
|
||||||
static const CFTimeInterval kBFViewAnimationDuration = 0.25f;
|
|
||||||
|
|
||||||
@implementation BFAppLinkReturnToRefererController {
|
|
||||||
UINavigationController *_navigationController;
|
|
||||||
BFAppLinkReturnToRefererView *_view;
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark - Object lifecycle
|
|
||||||
|
|
||||||
- (instancetype)init {
|
|
||||||
return [self initForDisplayAboveNavController:nil];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (instancetype)initForDisplayAboveNavController:(UINavigationController *)navController {
|
|
||||||
self = [super 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
|
|
||||||
|
|
||||||
- (BFAppLinkReturnToRefererView *)view {
|
|
||||||
if (!_view) {
|
|
||||||
self.view = [[BFAppLinkReturnToRefererView alloc] initWithFrame:CGRectZero];
|
|
||||||
if (_navigationController) {
|
|
||||||
[_navigationController.view addSubview:_view];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return _view;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)setView:(BFAppLinkReturnToRefererView *)view {
|
|
||||||
if (_view != view) {
|
|
||||||
_view.delegate = nil;
|
|
||||||
}
|
|
||||||
|
|
||||||
_view = view;
|
|
||||||
_view.delegate = self;
|
|
||||||
|
|
||||||
if (_navigationController) {
|
|
||||||
_view.includeStatusBarInSize = BFIncludeStatusBarInSizeAlways;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)showViewForRefererAppLink:(BFAppLink *)refererAppLink {
|
|
||||||
self.view.refererAppLink = refererAppLink;
|
|
||||||
|
|
||||||
[_view sizeToFit];
|
|
||||||
|
|
||||||
if (_navigationController) {
|
|
||||||
if (!_view.closed) {
|
|
||||||
dispatch_async(dispatch_get_main_queue(), ^{
|
|
||||||
[self moveNavigationBar];
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)showViewForRefererURL:(NSURL *)url {
|
|
||||||
BFAppLink *appLink = [BFURL URLForRenderBackToReferrerBarURL:url].appLinkReferer;
|
|
||||||
[self showViewForRefererAppLink:appLink];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)removeFromNavController {
|
|
||||||
if (_navigationController) {
|
|
||||||
[_view removeFromSuperview];
|
|
||||||
_navigationController = nil;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark - BFAppLinkReturnToRefererViewDelegate
|
|
||||||
|
|
||||||
- (void)returnToRefererViewDidTapInsideCloseButton:(BFAppLinkReturnToRefererView *)view {
|
|
||||||
[self closeViewAnimated:YES explicitlyClosed:YES];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)returnToRefererViewDidTapInsideLink:(BFAppLinkReturnToRefererView *)view
|
|
||||||
link:(BFAppLink *)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:kBFViewAnimationDuration delay:0.0 options:options animations:^{
|
|
||||||
_view.frame = CGRectMake(0.0, 0.0, CGRectGetWidth(_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:kBFViewAnimationDuration delay:0.0 options:options animations:^{
|
|
||||||
[_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 (_navigationController) {
|
|
||||||
[self updateNavigationBarY:_view.statusBarHeight];
|
|
||||||
}
|
|
||||||
|
|
||||||
CGRect frame = _view.frame;
|
|
||||||
frame.size.height = 0.0;
|
|
||||||
_view.frame = frame;
|
|
||||||
};
|
|
||||||
|
|
||||||
if (animated) {
|
|
||||||
[UIView animateWithDuration:kBFViewAnimationDuration animations:^{
|
|
||||||
closer();
|
|
||||||
} completion:^(BOOL finished) {
|
|
||||||
if (explicitlyClosed) {
|
|
||||||
_view.closed = YES;
|
|
||||||
}
|
|
||||||
}];
|
|
||||||
} else {
|
|
||||||
closer();
|
|
||||||
if (explicitlyClosed) {
|
|
||||||
_view.closed = YES;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)openRefererAppLink:(BFAppLink *)refererAppLink {
|
|
||||||
if (refererAppLink) {
|
|
||||||
id<BFAppLinkReturnToRefererControllerDelegate> delegate = _delegate;
|
|
||||||
if ([delegate respondsToSelector:@selector(returnToRefererController:willNavigateToAppLink:)]) {
|
|
||||||
[delegate returnToRefererController:self willNavigateToAppLink:refererAppLink];
|
|
||||||
}
|
|
||||||
|
|
||||||
NSError *error = nil;
|
|
||||||
BFAppLinkNavigationType type = [BFAppLinkNavigation navigateToAppLink:refererAppLink error:&error];
|
|
||||||
|
|
||||||
if ([delegate respondsToSelector:@selector(returnToRefererController:didNavigateToAppLink:type:)]) {
|
|
||||||
[delegate returnToRefererController:self didNavigateToAppLink:refererAppLink type:type];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
|
||||||
@ -1,78 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2014, Facebook, Inc.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* This source code is licensed under the BSD-style license found in the
|
|
||||||
* LICENSE file in the root directory of this source tree. An additional grant
|
|
||||||
* of patent rights can be found in the PATENTS file in the same directory.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#import <Foundation/Foundation.h>
|
|
||||||
#import <UIKit/UIKit.h>
|
|
||||||
|
|
||||||
#import <Bolts/BFAppLinkNavigation.h>
|
|
||||||
|
|
||||||
@class BFAppLinkReturnToRefererView;
|
|
||||||
@class BFURL;
|
|
||||||
|
|
||||||
typedef NS_ENUM(NSUInteger, BFIncludeStatusBarInSize) {
|
|
||||||
BFIncludeStatusBarInSizeNever,
|
|
||||||
BFIncludeStatusBarInSizeIOS7AndLater,
|
|
||||||
BFIncludeStatusBarInSizeAlways,
|
|
||||||
};
|
|
||||||
|
|
||||||
/*!
|
|
||||||
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 BFAppLinkReturnToRefererViewDelegate <NSObject>
|
|
||||||
|
|
||||||
/*!
|
|
||||||
Called when the user has tapped inside the close button.
|
|
||||||
*/
|
|
||||||
- (void)returnToRefererViewDidTapInsideCloseButton:(BFAppLinkReturnToRefererView *)view;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
Called when the user has tapped inside the App Link portion of the view.
|
|
||||||
*/
|
|
||||||
- (void)returnToRefererViewDidTapInsideLink:(BFAppLinkReturnToRefererView *)view
|
|
||||||
link:(BFAppLink *)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 BFAppLinkReturnToRefererView : UIView
|
|
||||||
|
|
||||||
/*!
|
|
||||||
The delegate that will be notified when the user navigates back to the referer.
|
|
||||||
*/
|
|
||||||
@property (nonatomic, weak) id<BFAppLinkReturnToRefererViewDelegate> delegate;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
The color of the text label and close button.
|
|
||||||
*/
|
|
||||||
@property (nonatomic, strong) UIColor *textColor;
|
|
||||||
|
|
||||||
@property (nonatomic, strong) BFAppLink *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) BFIncludeStatusBarInSize includeStatusBarInSize;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
Indicates whether the user has closed the view by clicking the close button.
|
|
||||||
*/
|
|
||||||
@property (nonatomic, assign) BOOL closed;
|
|
||||||
|
|
||||||
@end
|
|
||||||
@ -1,268 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2014, Facebook, Inc.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* This source code is licensed under the BSD-style license found in the
|
|
||||||
* LICENSE file in the root directory of this source tree. An additional grant
|
|
||||||
* of patent rights can be found in the PATENTS file in the same directory.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#import "BFAppLinkReturnToRefererView.h"
|
|
||||||
|
|
||||||
#import "BFAppLink.h"
|
|
||||||
#import "BFAppLinkTarget.h"
|
|
||||||
|
|
||||||
static const CGFloat BFMarginX = 8.5f;
|
|
||||||
static const CGFloat BFMarginY = 8.5f;
|
|
||||||
|
|
||||||
static NSString *const BFRefererAppLink = @"referer_app_link";
|
|
||||||
static NSString *const BFRefererAppName = @"app_name";
|
|
||||||
static NSString *const BFRefererUrl = @"url";
|
|
||||||
static const CGFloat BFCloseButtonWidth = 12.0;
|
|
||||||
static const CGFloat BFCloseButtonHeight = 12.0;
|
|
||||||
|
|
||||||
@interface BFAppLinkReturnToRefererView ()
|
|
||||||
|
|
||||||
@property (nonatomic, strong) UILabel *labelView;
|
|
||||||
@property (nonatomic, strong) UIButton *closeButton;
|
|
||||||
@property (nonatomic, strong) UITapGestureRecognizer *insideTapGestureRecognizer;
|
|
||||||
|
|
||||||
@end
|
|
||||||
|
|
||||||
@implementation BFAppLinkReturnToRefererView {
|
|
||||||
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 = BFIncludeStatusBarInSizeIOS7AndLater;
|
|
||||||
|
|
||||||
// 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];
|
|
||||||
#ifdef __IPHONE_6_0
|
|
||||||
_labelView.textAlignment = NSTextAlignmentCenter;
|
|
||||||
#else
|
|
||||||
_labelView.textAlignment = UITextAlignmentCenter;
|
|
||||||
#endif
|
|
||||||
_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 * BFMarginY + 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(BFMarginX,
|
|
||||||
CGRectGetMaxY(bounds) - labelSize.height - 1.5f * BFMarginY,
|
|
||||||
CGRectGetMaxX(bounds) - BFCloseButtonWidth - 3 * BFMarginX,
|
|
||||||
labelSize.height + BFMarginY);
|
|
||||||
|
|
||||||
_closeButton.frame = CGRectMake(CGRectGetMaxX(bounds) - BFCloseButtonWidth - 2 * BFMarginX,
|
|
||||||
_labelView.center.y - BFCloseButtonHeight / 2.0f - BFMarginY,
|
|
||||||
BFCloseButtonWidth + 2 * BFMarginX,
|
|
||||||
BFCloseButtonHeight + 2 * BFMarginY);
|
|
||||||
}
|
|
||||||
|
|
||||||
- (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 * BFMarginY + self.statusBarHeight);
|
|
||||||
}
|
|
||||||
return size;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (CGFloat)statusBarHeight {
|
|
||||||
UIApplication *application = [UIApplication sharedApplication];
|
|
||||||
|
|
||||||
BOOL include;
|
|
||||||
switch (_includeStatusBarInSize) {
|
|
||||||
case BFIncludeStatusBarInSizeAlways:
|
|
||||||
include = YES;
|
|
||||||
break;
|
|
||||||
case BFIncludeStatusBarInSizeIOS7AndLater: {
|
|
||||||
float systemVersion = [[[UIDevice currentDevice] systemVersion] floatValue];
|
|
||||||
include = (systemVersion >= 7.0);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case BFIncludeStatusBarInSizeNever:
|
|
||||||
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:(BFIncludeStatusBarInSize)includeStatusBarInSize {
|
|
||||||
_includeStatusBarInSize = includeStatusBarInSize;
|
|
||||||
[self setNeedsLayout];
|
|
||||||
[self invalidateIntrinsicContentSize];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)setTextColor:(UIColor *)textColor {
|
|
||||||
_textColor = textColor;
|
|
||||||
[self updateColors];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)setRefererAppLink:(BFAppLink *)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(BFCloseButtonWidth, BFCloseButtonHeight), 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, BFCloseButtonWidth - inset, BFCloseButtonHeight - inset);
|
|
||||||
CGContextStrokePath(context);
|
|
||||||
|
|
||||||
CGContextMoveToPoint(context, BFCloseButtonWidth - inset, inset);
|
|
||||||
CGContextAddLineToPoint(context, inset, BFCloseButtonHeight - 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 setHidden:_explicitlyHidden || _closed || !self.hasRefererData];
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
|
||||||
33
Example/Pods/Bolts/Bolts/iOS/BFAppLinkTarget.h
generated
33
Example/Pods/Bolts/Bolts/iOS/BFAppLinkTarget.h
generated
@ -1,33 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2014, Facebook, Inc.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* This source code is licensed under the BSD-style license found in the
|
|
||||||
* LICENSE file in the root directory of this source tree. An additional grant
|
|
||||||
* of patent rights can be found in the PATENTS file in the same directory.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#import <Foundation/Foundation.h>
|
|
||||||
|
|
||||||
/*!
|
|
||||||
Represents a target defined in App Link metadata, consisting of at least
|
|
||||||
a URL, and optionally an App Store ID and name.
|
|
||||||
*/
|
|
||||||
@interface BFAppLinkTarget : NSObject
|
|
||||||
|
|
||||||
/*! Creates a BFAppLinkTarget with the given app site and target URL. */
|
|
||||||
+ (instancetype)appLinkTargetWithURL:(NSURL *)url
|
|
||||||
appStoreId:(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) NSString *appStoreId;
|
|
||||||
|
|
||||||
/*! The name of the app */
|
|
||||||
@property (nonatomic, copy, readonly) NSString *appName;
|
|
||||||
|
|
||||||
@end
|
|
||||||
33
Example/Pods/Bolts/Bolts/iOS/BFAppLinkTarget.m
generated
33
Example/Pods/Bolts/Bolts/iOS/BFAppLinkTarget.m
generated
@ -1,33 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2014, Facebook, Inc.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* This source code is licensed under the BSD-style license found in the
|
|
||||||
* LICENSE file in the root directory of this source tree. An additional grant
|
|
||||||
* of patent rights can be found in the PATENTS file in the same directory.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#import "BFAppLinkTarget.h"
|
|
||||||
|
|
||||||
@interface BFAppLinkTarget ()
|
|
||||||
|
|
||||||
@property (nonatomic, strong, readwrite) NSURL *URL;
|
|
||||||
@property (nonatomic, copy, readwrite) NSString *appStoreId;
|
|
||||||
@property (nonatomic, copy, readwrite) NSString *appName;
|
|
||||||
|
|
||||||
@end
|
|
||||||
|
|
||||||
@implementation BFAppLinkTarget
|
|
||||||
|
|
||||||
+ (instancetype)appLinkTargetWithURL:(NSURL *)url
|
|
||||||
appStoreId:(NSString *)appStoreId
|
|
||||||
appName:(NSString *)appName {
|
|
||||||
BFAppLinkTarget *target = [[self alloc] init];
|
|
||||||
target.URL = url;
|
|
||||||
target.appStoreId = appStoreId;
|
|
||||||
target.appName = appName;
|
|
||||||
return target;
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
|
||||||
45
Example/Pods/Bolts/Bolts/iOS/BFMeasurementEvent.h
generated
45
Example/Pods/Bolts/Bolts/iOS/BFMeasurementEvent.h
generated
@ -1,45 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2014, Facebook, Inc.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* This source code is licensed under the BSD-style license found in the
|
|
||||||
* LICENSE file in the root directory of this source tree. An additional grant
|
|
||||||
* of patent rights can be found in the PATENTS file in the same directory.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#import <Foundation/Foundation.h>
|
|
||||||
|
|
||||||
/*! The name of the notification posted by BFMeasurementEvent */
|
|
||||||
FOUNDATION_EXPORT NSString *const BFMeasurementEventNotificationName;
|
|
||||||
|
|
||||||
/*! Defines keys in the userInfo object for the notification named BFMeasurementEventNotificationName */
|
|
||||||
/*! The string field for the name of the event */
|
|
||||||
FOUNDATION_EXPORT NSString *const BFMeasurementEventNameKey;
|
|
||||||
/*! The dictionary field for the arguments of the event */
|
|
||||||
FOUNDATION_EXPORT NSString *const BFMeasurementEventArgsKey;
|
|
||||||
|
|
||||||
/*! Bolts Events raised by BFMeasurementEvent for Applink */
|
|
||||||
/*!
|
|
||||||
The name of the event posted when [BFURL URLWithURL:] is called successfully. This represents the successful parsing of an app link URL.
|
|
||||||
*/
|
|
||||||
FOUNDATION_EXPORT NSString *const BFAppLinkParseEventName;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
The name of the event posted when [BFURL URLWithInboundURL:] is called successfully.
|
|
||||||
This represents parsing an inbound app link URL from a different application
|
|
||||||
*/
|
|
||||||
FOUNDATION_EXPORT NSString *const BFAppLinkNavigateInEventName;
|
|
||||||
|
|
||||||
/*! The event raised when the user navigates from your app to other apps */
|
|
||||||
FOUNDATION_EXPORT NSString *const BFAppLinkNavigateOutEventName;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
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 BFAppLinkNavigateBackToReferrerEventName;
|
|
||||||
|
|
||||||
@interface BFMeasurementEvent : NSObject
|
|
||||||
|
|
||||||
@end
|
|
||||||
62
Example/Pods/Bolts/Bolts/iOS/BFMeasurementEvent.m
generated
62
Example/Pods/Bolts/Bolts/iOS/BFMeasurementEvent.m
generated
@ -1,62 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2014, Facebook, Inc.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* This source code is licensed under the BSD-style license found in the
|
|
||||||
* LICENSE file in the root directory of this source tree. An additional grant
|
|
||||||
* of patent rights can be found in the PATENTS file in the same directory.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#import "BFMeasurementEvent_Internal.h"
|
|
||||||
|
|
||||||
NSString *const BFMeasurementEventNotificationName = @"com.parse.bolts.measurement_event";
|
|
||||||
|
|
||||||
NSString *const BFMeasurementEventNameKey = @"event_name";
|
|
||||||
NSString *const BFMeasurementEventArgsKey = @"event_args";
|
|
||||||
|
|
||||||
/* app Link Event raised by this BFURL */
|
|
||||||
NSString *const BFAppLinkParseEventName = @"al_link_parse";
|
|
||||||
NSString *const BFAppLinkNavigateInEventName = @"al_nav_in";
|
|
||||||
|
|
||||||
/*! AppLink events raised in this class */
|
|
||||||
NSString *const BFAppLinkNavigateOutEventName = @"al_nav_out";
|
|
||||||
NSString *const BFAppLinkNavigateBackToReferrerEventName = @"al_ref_back_out";
|
|
||||||
|
|
||||||
__attribute__((noinline)) void warnOnMissingEventName() {
|
|
||||||
NSLog(@"Warning: Missing event name when logging bolts measurement event. \n"
|
|
||||||
" Ignoring this event in logging.");
|
|
||||||
}
|
|
||||||
|
|
||||||
@implementation BFMeasurementEvent {
|
|
||||||
NSString *_name;
|
|
||||||
NSDictionary *_args;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)postNotification {
|
|
||||||
if (!_name) {
|
|
||||||
warnOnMissingEventName();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
|
|
||||||
NSDictionary *userInfo = @{BFMeasurementEventNameKey : _name,
|
|
||||||
BFMeasurementEventArgsKey : _args};
|
|
||||||
|
|
||||||
[center postNotificationName:BFMeasurementEventNotificationName
|
|
||||||
object:self
|
|
||||||
userInfo:userInfo];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (instancetype)initEventWithName:(NSString *)name args:(NSDictionary *)args {
|
|
||||||
if ((self = [super init])) {
|
|
||||||
_name = name;
|
|
||||||
_args = args ? args : @{};
|
|
||||||
}
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
+ (void)postNotificationForEventName:(NSString *)name args:(NSDictionary *)args {
|
|
||||||
[[[self alloc] initEventWithName:name args:args] postNotification];
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
|
||||||
75
Example/Pods/Bolts/Bolts/iOS/BFURL.h
generated
75
Example/Pods/Bolts/Bolts/iOS/BFURL.h
generated
@ -1,75 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2014, Facebook, Inc.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* This source code is licensed under the BSD-style license found in the
|
|
||||||
* LICENSE file in the root directory of this source tree. An additional grant
|
|
||||||
* of patent rights can be found in the PATENTS file in the same directory.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#import <Foundation/Foundation.h>
|
|
||||||
|
|
||||||
@class BFAppLink;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
Provides a set of utilities for working with NSURLs, such as parsing of query parameters
|
|
||||||
and handling for App Link requests.
|
|
||||||
*/
|
|
||||||
@interface BFURL : NSObject
|
|
||||||
|
|
||||||
/*!
|
|
||||||
Creates a link target from a raw URL.
|
|
||||||
On success, this posts the BFAppLinkParseEventName measurement event. If you are constructing the BFURL within your application delegate's
|
|
||||||
application:openURL:sourceApplication:annotation:, you should instead use URLWithInboundURL:sourceApplication:
|
|
||||||
to support better BFMeasurementEvent notifications
|
|
||||||
@param url The instance of `NSURL` to create BFURL from.
|
|
||||||
*/
|
|
||||||
+ (BFURL *)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 BFAppLinkNavigateInEventName measurement event.
|
|
||||||
@param url The instance of `NSURL` to create BFURL 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:
|
|
||||||
*/
|
|
||||||
+ (BFURL *)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 *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 *appLinkData;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
If this link target is an App Link, this is the data found in extras.
|
|
||||||
*/
|
|
||||||
@property (nonatomic, strong, readonly) NSDictionary *appLinkExtras;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
The App Link indicating how to navigate back to the referer app, if any.
|
|
||||||
*/
|
|
||||||
@property (nonatomic, strong, readonly) BFAppLink *appLinkReferer;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
The URL that was used to create this BFURL.
|
|
||||||
*/
|
|
||||||
@property (nonatomic, strong, readonly) NSURL *inputURL;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
The query parameters of the inputURL, parsed into an NSDictionary.
|
|
||||||
*/
|
|
||||||
@property (nonatomic, strong, readonly) NSDictionary *inputQueryParameters;
|
|
||||||
|
|
||||||
@end
|
|
||||||
142
Example/Pods/Bolts/Bolts/iOS/BFURL.m
generated
142
Example/Pods/Bolts/Bolts/iOS/BFURL.m
generated
@ -1,142 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2014, Facebook, Inc.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* This source code is licensed under the BSD-style license found in the
|
|
||||||
* LICENSE file in the root directory of this source tree. An additional grant
|
|
||||||
* of patent rights can be found in the PATENTS file in the same directory.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#import "BFURL_Internal.h"
|
|
||||||
#import "BFAppLink_Internal.h"
|
|
||||||
#import "BFAppLinkTarget.h"
|
|
||||||
#import "BFMeasurementEvent_Internal.h"
|
|
||||||
|
|
||||||
@implementation BFURL
|
|
||||||
|
|
||||||
- (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 *baseQuery = [BFURL queryParametersForURL:url];
|
|
||||||
_inputQueryParameters = baseQuery;
|
|
||||||
_targetQueryParameters = baseQuery;
|
|
||||||
|
|
||||||
// Check for applink_data
|
|
||||||
NSString *appLinkDataString = baseQuery[BFAppLinkDataParameterName];
|
|
||||||
if (appLinkDataString) {
|
|
||||||
// Try to parse the JSON
|
|
||||||
NSError *error = nil;
|
|
||||||
NSDictionary *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[BFAppLinkVersionKeyName] ?: @"1.0";
|
|
||||||
NSString *target = applinkData[BFAppLinkTargetKeyName];
|
|
||||||
if ([version isKindOfClass:[NSString class]] &&
|
|
||||||
[version isEqual:BFAppLinkVersion]) {
|
|
||||||
// There's applink data! The target should actually be the applink target.
|
|
||||||
_appLinkData = applinkData;
|
|
||||||
id applinkExtras = applinkData[BFAppLinkExtrasKeyName];
|
|
||||||
if (applinkExtras && [applinkExtras isKindOfClass:[NSDictionary class]]) {
|
|
||||||
_appLinkExtras = applinkExtras;
|
|
||||||
}
|
|
||||||
_targetURL = ([target isKindOfClass:[NSString class]] ? [NSURL URLWithString:target] : url);
|
|
||||||
_targetQueryParameters = [BFURL queryParametersForURL:_targetURL];
|
|
||||||
|
|
||||||
NSDictionary *refererAppLink = _appLinkData[BFAppLinkRefererAppLink];
|
|
||||||
NSString *refererURLString = refererAppLink[BFAppLinkRefererUrl];
|
|
||||||
NSString *refererAppName = refererAppLink[BFAppLinkRefererAppName];
|
|
||||||
|
|
||||||
if (refererURLString && refererAppName) {
|
|
||||||
BFAppLinkTarget *appLinkTarget = [BFAppLinkTarget appLinkTargetWithURL:[NSURL URLWithString:refererURLString]
|
|
||||||
appStoreId:nil
|
|
||||||
appName:refererAppName];
|
|
||||||
_appLinkReferer = [BFAppLink 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 *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;
|
|
||||||
[BFMeasurementEvent postNotificationForEventName:BFAppLinkParseEventName args:logData];
|
|
||||||
if (forOpenURLEvent) {
|
|
||||||
[BFMeasurementEvent postNotificationForEventName:BFAppLinkNavigateInEventName args:logData];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
+ (BFURL *)URLWithURL:(NSURL *)url {
|
|
||||||
return [[BFURL alloc] initWithURL:url forOpenInboundURL:NO sourceApplication:nil forRenderBackToReferrerBar:NO];
|
|
||||||
}
|
|
||||||
|
|
||||||
+ (BFURL *)URLWithInboundURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication {
|
|
||||||
return [[BFURL alloc] initWithURL:url forOpenInboundURL:YES sourceApplication:sourceApplication forRenderBackToReferrerBar:NO];
|
|
||||||
}
|
|
||||||
|
|
||||||
+ (BFURL *)URLForRenderBackToReferrerBarURL:(NSURL *)url {
|
|
||||||
return [[BFURL alloc] initWithURL:url forOpenInboundURL:NO sourceApplication:nil forRenderBackToReferrerBar:YES];
|
|
||||||
}
|
|
||||||
|
|
||||||
+ (NSString *)decodeURLString:(NSString *)string {
|
|
||||||
return (NSString *)CFBridgingRelease(CFURLCreateStringByReplacingPercentEscapes(NULL,
|
|
||||||
(CFStringRef)string,
|
|
||||||
CFSTR("")));
|
|
||||||
}
|
|
||||||
|
|
||||||
+ (NSDictionary *)queryParametersForURL:(NSURL *)url {
|
|
||||||
NSMutableDictionary *parameters = [NSMutableDictionary dictionary];
|
|
||||||
NSString *query = url.query;
|
|
||||||
if ([query isEqualToString:@""]) {
|
|
||||||
return @{};
|
|
||||||
}
|
|
||||||
NSArray *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
|
|
||||||
@ -1,26 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2014, Facebook, Inc.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* This source code is licensed under the BSD-style license found in the
|
|
||||||
* LICENSE file in the root directory of this source tree. An additional grant
|
|
||||||
* of patent rights can be found in the PATENTS file in the same directory.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#import <Foundation/Foundation.h>
|
|
||||||
|
|
||||||
#import <Bolts/BFAppLinkResolving.h>
|
|
||||||
|
|
||||||
/*!
|
|
||||||
A reference implementation for an App Link resolver that uses a hidden UIWebView
|
|
||||||
to parse the HTML containing App Link metadata.
|
|
||||||
*/
|
|
||||||
@interface BFWebViewAppLinkResolver : NSObject <BFAppLinkResolving>
|
|
||||||
|
|
||||||
/*!
|
|
||||||
Gets the instance of a BFWebViewAppLinkResolver.
|
|
||||||
*/
|
|
||||||
+ (instancetype)sharedInstance;
|
|
||||||
|
|
||||||
@end
|
|
||||||
296
Example/Pods/Bolts/Bolts/iOS/BFWebViewAppLinkResolver.m
generated
296
Example/Pods/Bolts/Bolts/iOS/BFWebViewAppLinkResolver.m
generated
@ -1,296 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2014, Facebook, Inc.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* This source code is licensed under the BSD-style license found in the
|
|
||||||
* LICENSE file in the root directory of this source tree. An additional grant
|
|
||||||
* of patent rights can be found in the PATENTS file in the same directory.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#import <UIKit/UIKit.h>
|
|
||||||
|
|
||||||
#import "BFWebViewAppLinkResolver.h"
|
|
||||||
#import "BFAppLink.h"
|
|
||||||
#import "BFAppLinkTarget.h"
|
|
||||||
#import "BFTask.h"
|
|
||||||
#import "BFTaskCompletionSource.h"
|
|
||||||
#import "BFExecutor.h"
|
|
||||||
|
|
||||||
// Defines JavaScript to extract app link tags from HTML content
|
|
||||||
static NSString *const BFWebViewAppLinkResolverTagExtractionJavaScript = @""
|
|
||||||
"(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 BFWebViewAppLinkResolverIOSURLKey = @"url";
|
|
||||||
static NSString *const BFWebViewAppLinkResolverIOSAppStoreIdKey = @"app_store_id";
|
|
||||||
static NSString *const BFWebViewAppLinkResolverIOSAppNameKey = @"app_name";
|
|
||||||
static NSString *const BFWebViewAppLinkResolverDictionaryValueKey = @"_value";
|
|
||||||
static NSString *const BFWebViewAppLinkResolverPreferHeader = @"Prefer-Html-Meta-Tags";
|
|
||||||
static NSString *const BFWebViewAppLinkResolverMetaTagPrefix = @"al";
|
|
||||||
static NSString *const BFWebViewAppLinkResolverWebKey = @"web";
|
|
||||||
static NSString *const BFWebViewAppLinkResolverIOSKey = @"ios";
|
|
||||||
static NSString *const BFWebViewAppLinkResolverIPhoneKey = @"iphone";
|
|
||||||
static NSString *const BFWebViewAppLinkResolverIPadKey = @"ipad";
|
|
||||||
static NSString *const BFWebViewAppLinkResolverWebURLKey = @"url";
|
|
||||||
static NSString *const BFWebViewAppLinkResolverShouldFallbackKey = @"should_fallback";
|
|
||||||
|
|
||||||
@interface BFWebViewAppLinkResolverWebViewDelegate : 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 BFWebViewAppLinkResolverWebViewDelegate
|
|
||||||
|
|
||||||
- (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 BFWebViewAppLinkResolver
|
|
||||||
|
|
||||||
+ (instancetype)sharedInstance {
|
|
||||||
static id instance;
|
|
||||||
static dispatch_once_t onceToken;
|
|
||||||
dispatch_once(&onceToken, ^{
|
|
||||||
instance = [[self alloc] init];
|
|
||||||
});
|
|
||||||
return instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (BFTask *)followRedirects:(NSURL *)url {
|
|
||||||
// This task will be resolved with either the redirect NSURL
|
|
||||||
// or a dictionary with the response data to be returned.
|
|
||||||
BFTaskCompletionSource *tcs = [BFTaskCompletionSource taskCompletionSource];
|
|
||||||
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
|
|
||||||
[request setValue:BFWebViewAppLinkResolverMetaTagPrefix forHTTPHeaderField:BFWebViewAppLinkResolverPreferHeader];
|
|
||||||
|
|
||||||
void (^completion)(NSURLResponse *response, NSData *data, NSError *error) = ^(NSURLResponse *response, NSData *data, NSError *error) {
|
|
||||||
if (error) {
|
|
||||||
[tcs setError: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];
|
|
||||||
[tcs setResult:redirectURL];
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[tcs setResult:@{ @"response" : response, @"data" : data }];
|
|
||||||
};
|
|
||||||
|
|
||||||
#if __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_7_0 || __MAC_OS_X_VERSION_MIN_REQUIRED >= __MAC_10_9
|
|
||||||
NSURLSession *session = [NSURLSession sharedSession];
|
|
||||||
[[session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
|
|
||||||
completion(response, data, error);
|
|
||||||
}] resume];
|
|
||||||
#else
|
|
||||||
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:completion];
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return [tcs.task continueWithSuccessBlock:^id(BFTask *task) {
|
|
||||||
// If we redirected, just keep recursing.
|
|
||||||
if ([task.result isKindOfClass:[NSURL class]]) {
|
|
||||||
return [self followRedirects:task.result];
|
|
||||||
}
|
|
||||||
return task;
|
|
||||||
}];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (BFTask *)appLinkFromURLInBackground:(NSURL *)url NS_EXTENSION_UNAVAILABLE_IOS("") {
|
|
||||||
return [[self followRedirects:url] continueWithExecutor:[BFExecutor mainThreadExecutor]
|
|
||||||
withSuccessBlock:^id(BFTask *task) {
|
|
||||||
NSData *responseData = task.result[@"data"];
|
|
||||||
NSHTTPURLResponse *response = task.result[@"response"];
|
|
||||||
BFTaskCompletionSource *tcs = [BFTaskCompletionSource taskCompletionSource];
|
|
||||||
|
|
||||||
UIWebView *webView = [[UIWebView alloc] init];
|
|
||||||
BFWebViewAppLinkResolverWebViewDelegate *listener = [[BFWebViewAppLinkResolverWebViewDelegate alloc] init];
|
|
||||||
__block BFWebViewAppLinkResolverWebViewDelegate *retainedListener = listener;
|
|
||||||
listener.didFinishLoad = ^(UIWebView *view) {
|
|
||||||
if (retainedListener) {
|
|
||||||
NSDictionary *ogData = [self getALDataFromLoadedPage:view];
|
|
||||||
[view removeFromSuperview];
|
|
||||||
view.delegate = nil;
|
|
||||||
retainedListener = nil;
|
|
||||||
[tcs setResult:[self appLinkFromALData:ogData destination:url]];
|
|
||||||
}
|
|
||||||
};
|
|
||||||
listener.didFailLoadWithError = ^(UIWebView* view, NSError *error) {
|
|
||||||
if (retainedListener) {
|
|
||||||
[view removeFromSuperview];
|
|
||||||
view.delegate = nil;
|
|
||||||
retainedListener = nil;
|
|
||||||
[tcs setError:error];
|
|
||||||
}
|
|
||||||
};
|
|
||||||
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];
|
|
||||||
|
|
||||||
return tcs.task;
|
|
||||||
}];
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
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 *)parseALData:(NSArray *)dataArray {
|
|
||||||
NSMutableDictionary *al = [NSMutableDictionary dictionary];
|
|
||||||
for (NSDictionary *tag in dataArray) {
|
|
||||||
NSString *name = tag[@"property"];
|
|
||||||
if (![name isKindOfClass:[NSString class]]) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
NSArray *nameComponents = [name componentsSeparatedByString:@":"];
|
|
||||||
if (![nameComponents[0] isEqualToString:BFWebViewAppLinkResolverMetaTagPrefix]) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
NSMutableDictionary *root = al;
|
|
||||||
for (NSUInteger i = 1; i < nameComponents.count; i++) {
|
|
||||||
NSMutableArray *children = root[nameComponents[i]];
|
|
||||||
if (!children) {
|
|
||||||
children = [NSMutableArray array];
|
|
||||||
root[nameComponents[i]] = children;
|
|
||||||
}
|
|
||||||
NSMutableDictionary *child = children.lastObject;
|
|
||||||
if (!child || i == nameComponents.count - 1) {
|
|
||||||
child = [NSMutableDictionary dictionary];
|
|
||||||
[children addObject:child];
|
|
||||||
}
|
|
||||||
root = child;
|
|
||||||
}
|
|
||||||
if (tag[@"content"]) {
|
|
||||||
root[BFWebViewAppLinkResolverDictionaryValueKey] = tag[@"content"];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return al;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (NSDictionary *)getALDataFromLoadedPage:(UIWebView *)webView {
|
|
||||||
// Run some JavaScript in the webview to fetch the meta tags.
|
|
||||||
NSString *jsonString = [webView stringByEvaluatingJavaScriptFromString:BFWebViewAppLinkResolverTagExtractionJavaScript];
|
|
||||||
NSError *error = nil;
|
|
||||||
NSArray *arr = [NSJSONSerialization JSONObjectWithData:[jsonString dataUsingEncoding:NSUTF8StringEncoding]
|
|
||||||
options:0
|
|
||||||
error:&error];
|
|
||||||
return [self parseALData:arr];
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Converts app link data into a BFAppLink containing the targets relevant for this platform.
|
|
||||||
*/
|
|
||||||
- (BFAppLink *)appLinkFromALData:(NSDictionary *)appLinkDict destination:(NSURL *)destination {
|
|
||||||
NSMutableArray *linkTargets = [NSMutableArray array];
|
|
||||||
|
|
||||||
NSArray *platformData = nil;
|
|
||||||
|
|
||||||
const UIUserInterfaceIdiom idiom = UI_USER_INTERFACE_IDIOM();
|
|
||||||
if (idiom == UIUserInterfaceIdiomPad) {
|
|
||||||
platformData = @[ appLinkDict[BFWebViewAppLinkResolverIPadKey] ?: @{},
|
|
||||||
appLinkDict[BFWebViewAppLinkResolverIOSKey] ?: @{} ];
|
|
||||||
} else if (idiom == UIUserInterfaceIdiomPhone) {
|
|
||||||
platformData = @[ appLinkDict[BFWebViewAppLinkResolverIPhoneKey] ?: @{},
|
|
||||||
appLinkDict[BFWebViewAppLinkResolverIOSKey] ?: @{} ];
|
|
||||||
} else {
|
|
||||||
// Future-proofing. Other User Interface idioms should only hit ios.
|
|
||||||
platformData = @[ appLinkDict[BFWebViewAppLinkResolverIOSKey] ?: @{} ];
|
|
||||||
}
|
|
||||||
|
|
||||||
for (NSArray *platformObjects in platformData) {
|
|
||||||
for (NSDictionary *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 *urls = platformDict[BFWebViewAppLinkResolverIOSURLKey];
|
|
||||||
NSArray *appStoreIds = platformDict[BFWebViewAppLinkResolverIOSAppStoreIdKey];
|
|
||||||
NSArray *appNames = platformDict[BFWebViewAppLinkResolverIOSAppNameKey];
|
|
||||||
|
|
||||||
NSUInteger maxCount = MAX(urls.count, MAX(appStoreIds.count, appNames.count));
|
|
||||||
|
|
||||||
for (NSUInteger i = 0; i < maxCount; i++) {
|
|
||||||
NSString *urlString = urls[i][BFWebViewAppLinkResolverDictionaryValueKey];
|
|
||||||
NSURL *url = urlString ? [NSURL URLWithString:urlString] : nil;
|
|
||||||
NSString *appStoreId = appStoreIds[i][BFWebViewAppLinkResolverDictionaryValueKey];
|
|
||||||
NSString *appName = appNames[i][BFWebViewAppLinkResolverDictionaryValueKey];
|
|
||||||
BFAppLinkTarget *target = [BFAppLinkTarget appLinkTargetWithURL:url
|
|
||||||
appStoreId:appStoreId
|
|
||||||
appName:appName];
|
|
||||||
[linkTargets addObject:target];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
NSDictionary *webDict = appLinkDict[BFWebViewAppLinkResolverWebKey][0];
|
|
||||||
NSString *webUrlString = webDict[BFWebViewAppLinkResolverWebURLKey][0][BFWebViewAppLinkResolverDictionaryValueKey];
|
|
||||||
NSString *shouldFallbackString = webDict[BFWebViewAppLinkResolverShouldFallbackKey][0][BFWebViewAppLinkResolverDictionaryValueKey];
|
|
||||||
|
|
||||||
NSURL *webUrl = destination;
|
|
||||||
|
|
||||||
if (shouldFallbackString &&
|
|
||||||
[@[ @"no", @"false", @"0" ] containsObject:[shouldFallbackString lowercaseString]]) {
|
|
||||||
webUrl = nil;
|
|
||||||
}
|
|
||||||
if (webUrl && webUrlString) {
|
|
||||||
webUrl = [NSURL URLWithString:webUrlString];
|
|
||||||
}
|
|
||||||
|
|
||||||
return [BFAppLink appLinkWithSourceURL:destination
|
|
||||||
targets:linkTargets
|
|
||||||
webURL:webUrl];
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
|
||||||
@ -1,17 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2014, Facebook, Inc.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* This source code is licensed under the BSD-style license found in the
|
|
||||||
* LICENSE file in the root directory of this source tree. An additional grant
|
|
||||||
* of patent rights can be found in the PATENTS file in the same directory.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#import <Bolts/BFAppLinkReturnToRefererView.h>
|
|
||||||
|
|
||||||
@interface BFAppLinkReturnToRefererView (Internal)
|
|
||||||
|
|
||||||
- (CGFloat)statusBarHeight;
|
|
||||||
|
|
||||||
@end
|
|
||||||
@ -1,32 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2014, Facebook, Inc.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* This source code is licensed under the BSD-style license found in the
|
|
||||||
* LICENSE file in the root directory of this source tree. An additional grant
|
|
||||||
* of patent rights can be found in the PATENTS file in the same directory.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#import <Bolts/BFAppLink.h>
|
|
||||||
|
|
||||||
FOUNDATION_EXPORT NSString *const BFAppLinkDataParameterName;
|
|
||||||
FOUNDATION_EXPORT NSString *const BFAppLinkTargetKeyName;
|
|
||||||
FOUNDATION_EXPORT NSString *const BFAppLinkUserAgentKeyName;
|
|
||||||
FOUNDATION_EXPORT NSString *const BFAppLinkExtrasKeyName;
|
|
||||||
FOUNDATION_EXPORT NSString *const BFAppLinkVersionKeyName;
|
|
||||||
FOUNDATION_EXPORT NSString *const BFAppLinkRefererAppLink;
|
|
||||||
FOUNDATION_EXPORT NSString *const BFAppLinkRefererAppName;
|
|
||||||
FOUNDATION_EXPORT NSString *const BFAppLinkRefererUrl;
|
|
||||||
|
|
||||||
@interface BFAppLink (Internal)
|
|
||||||
|
|
||||||
+ (instancetype)appLinkWithSourceURL:(NSURL *)sourceURL
|
|
||||||
targets:(NSArray *)targets
|
|
||||||
webURL:(NSURL *)webURL
|
|
||||||
isBackToReferrer:(BOOL)isBackToReferrer;
|
|
||||||
|
|
||||||
/*! return if this AppLink is to go back to referrer. */
|
|
||||||
@property (nonatomic, assign, readonly, getter=isBackToReferrer) BOOL backToReferrer;
|
|
||||||
|
|
||||||
@end
|
|
||||||
@ -1,19 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2014, Facebook, Inc.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* This source code is licensed under the BSD-style license found in the
|
|
||||||
* LICENSE file in the root directory of this source tree. An additional grant
|
|
||||||
* of patent rights can be found in the PATENTS file in the same directory.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#import <Bolts/BFMeasurementEvent.h>
|
|
||||||
/*!
|
|
||||||
Provides methods for posting notifications from the Bolts framework
|
|
||||||
*/
|
|
||||||
@interface BFMeasurementEvent (Internal)
|
|
||||||
|
|
||||||
+ (void)postNotificationForEventName:(NSString *)name args:(NSDictionary *)args;
|
|
||||||
|
|
||||||
@end
|
|
||||||
@ -1,15 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2014, Facebook, Inc.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* This source code is licensed under the BSD-style license found in the
|
|
||||||
* LICENSE file in the root directory of this source tree. An additional grant
|
|
||||||
* of patent rights can be found in the PATENTS file in the same directory.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#import <Bolts/BFURL.h>
|
|
||||||
|
|
||||||
@interface BFURL (Internal)
|
|
||||||
+ (BFURL *)URLForRenderBackToReferrerBarURL:(NSURL *)url;
|
|
||||||
@end
|
|
||||||
30
Example/Pods/Bolts/LICENSE
generated
30
Example/Pods/Bolts/LICENSE
generated
@ -1,30 +0,0 @@
|
|||||||
BSD License
|
|
||||||
|
|
||||||
For Bolts software
|
|
||||||
|
|
||||||
Copyright (c) 2013-present, Facebook, Inc. All rights reserved.
|
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without modification,
|
|
||||||
are permitted provided that the following conditions are met:
|
|
||||||
|
|
||||||
* Redistributions of source code must retain the above copyright notice, this
|
|
||||||
list of conditions and the following disclaimer.
|
|
||||||
|
|
||||||
* Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
this list of conditions and the following disclaimer in the documentation
|
|
||||||
and/or other materials provided with the distribution.
|
|
||||||
|
|
||||||
* Neither the name Facebook nor the names of its contributors may be used to
|
|
||||||
endorse or promote products derived from this software without specific
|
|
||||||
prior written permission.
|
|
||||||
|
|
||||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
||||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
|
||||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
|
||||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
683
Example/Pods/Bolts/README.md
generated
683
Example/Pods/Bolts/README.md
generated
@ -1,683 +0,0 @@
|
|||||||
Bolts
|
|
||||||
============
|
|
||||||
[](https://travis-ci.org/BoltsFramework/Bolts-ObjC)
|
|
||||||
[](https://codecov.io/github/BoltsFramework/Bolts-ObjC?branch=master)
|
|
||||||
[](https://cocoapods.org/pods/Bolts)
|
|
||||||
[](https://github.com/BoltsFramework/Bolts-ObjC/blob/master/LICENSE)
|
|
||||||
[](https://www.versioneye.com/objective-c/bolts/references)
|
|
||||||
|
|
||||||
[](https://cocoapods.org/pods/Bolts)
|
|
||||||
[](https://github.com/Carthage/Carthage)
|
|
||||||
|
|
||||||
Bolts is a collection of low-level libraries designed to make developing mobile
|
|
||||||
apps easier. Bolts was designed by Parse and Facebook for our own internal use,
|
|
||||||
and we have decided to open source these libraries to make them available to
|
|
||||||
others. Using these libraries does not require using any Parse services. Nor
|
|
||||||
do they require having a Parse or Facebook developer account.
|
|
||||||
|
|
||||||
Bolts includes:
|
|
||||||
|
|
||||||
* "Tasks", which make organization of complex asynchronous code more manageable. A task is kind of like a JavaScript Promise, but available for iOS and Android.
|
|
||||||
* An implementation of the [App Links protocol](http://applinks.org/), helping you link to content in other apps and handle incoming deep-links.
|
|
||||||
|
|
||||||
For more information, see the [Bolts iOS API Reference](http://boltsframework.github.io/docs/ios/).
|
|
||||||
|
|
||||||
# Tasks
|
|
||||||
|
|
||||||
To build a truly responsive iOS application, you must keep long-running operations off of the UI thread, and be careful to avoid blocking anything the UI thread might be waiting on. This means you will need to execute various operations in the background. To make this easier, we've added a class called `BFTask`. A task represents the result of an asynchronous operation. Typically, a `BFTask` is returned from an asynchronous function and gives the ability to continue processing the result of the task. When a task is returned from a function, it's already begun doing its job. A task is not tied to a particular threading model: it represents the work being done, not where it is executing. Tasks have many advantages over other methods of asynchronous programming, such as callbacks. `BFTask` is not a replacement for `NSOperation` or GCD. In fact, they play well together. But tasks do fill in some gaps that those technologies don't address.
|
|
||||||
* `BFTask` takes care of managing dependencies for you. Unlike using `NSOperation` for dependency management, you don't have to declare all dependencies before starting a `BFTask`. For example, imagine you need to save a set of objects and each one may or may not require saving child objects. With an `NSOperation`, you would normally have to create operations for each of the child saves ahead of time. But you don't always know before you start the work whether that's going to be necessary. That can make managing dependencies with `NSOperation` very painful. Even in the best case, you have to create your dependencies before the operations that depend on them, which results in code that appears in a different order than it executes. With `BFTask`, you can decide during your operation's work whether there will be subtasks and return the other task in just those cases.
|
|
||||||
* `BFTasks` release their dependencies. `NSOperation` strongly retains its dependencies, so if you have a queue of ordered operations and sequence them using dependencies, you have a leak, because every operation gets retained forever. `BFTasks` release their callbacks as soon as they are run, so everything cleans up after itself. This can reduce memory use, and simplify memory management.
|
|
||||||
* `BFTasks` keep track of the state of finished tasks: It tracks whether there was a returned value, the task was cancelled, or if an error occurred. It also has convenience methods for propagating errors. With `NSOperation`, you have to build all of this stuff yourself.
|
|
||||||
* `BFTasks` don't depend on any particular threading model. So it's easy to have some tasks perform their work with an operation queue, while others perform work using blocks with GCD. These tasks can depend on each other seamlessly.
|
|
||||||
* Performing several tasks in a row will not create nested "pyramid" code as you would get when using only callbacks.
|
|
||||||
* `BFTasks` are fully composable, allowing you to perform branching, parallelism, and complex error handling, without the spaghetti code of having many named callbacks.
|
|
||||||
* You can arrange task-based code in the order that it executes, rather than having to split your logic across scattered callback functions.
|
|
||||||
|
|
||||||
For the examples in this doc, assume there are async versions of some common Parse methods, called `saveAsync:` and `findAsync:` which return a `Task`. In a later section, we'll show how to define these functions yourself.
|
|
||||||
|
|
||||||
## The `continueWithBlock` Method
|
|
||||||
|
|
||||||
Every `BFTask` has a method named `continueWithBlock:` which takes a continuation block. A continuation is a block that will be executed when the task is complete. You can then inspect the task to check if it was successful and to get its result.
|
|
||||||
|
|
||||||
```objective-c
|
|
||||||
// Objective-C
|
|
||||||
[[self saveAsync:obj] continueWithBlock:^id(BFTask *task) {
|
|
||||||
if (task.isCancelled) {
|
|
||||||
// the save was cancelled.
|
|
||||||
} else if (task.error) {
|
|
||||||
// the save failed.
|
|
||||||
} else {
|
|
||||||
// the object was saved successfully.
|
|
||||||
PFObject *object = task.result;
|
|
||||||
}
|
|
||||||
return nil;
|
|
||||||
}];
|
|
||||||
```
|
|
||||||
|
|
||||||
```swift
|
|
||||||
// Swift
|
|
||||||
self.saveAsync(obj).continueWithBlock {
|
|
||||||
(task: BFTask!) -> BFTask in
|
|
||||||
if task.isCancelled() {
|
|
||||||
// the save was cancelled.
|
|
||||||
} else if task.error != nil {
|
|
||||||
// the save failed.
|
|
||||||
} else {
|
|
||||||
// the object was saved successfully.
|
|
||||||
var object = task.result() as PFObject
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
BFTasks use Objective-C blocks, so the syntax should be pretty straightforward. Let's look closer at the types involved with an example.
|
|
||||||
|
|
||||||
```objective-c
|
|
||||||
// Objective-C
|
|
||||||
/**
|
|
||||||
* Gets an NSString asynchronously.
|
|
||||||
*/
|
|
||||||
- (BFTask *)getStringAsync {
|
|
||||||
// Let's suppose getNumberAsync returns a BFTask whose result is an NSNumber.
|
|
||||||
return [[self getNumberAsync] continueWithBlock:^id(BFTask *task) {
|
|
||||||
// This continuation block takes the NSNumber BFTask as input,
|
|
||||||
// and provides an NSString as output.
|
|
||||||
|
|
||||||
NSNumber *number = task.result;
|
|
||||||
return [NSString stringWithFormat:@"%@", number];
|
|
||||||
)];
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
```swift
|
|
||||||
// Swift
|
|
||||||
/**
|
|
||||||
* Gets an NSString asynchronously.
|
|
||||||
*/
|
|
||||||
func getStringAsync() -> BFTask {
|
|
||||||
//Let's suppose getNumberAsync returns a BFTask whose result is an NSNumber.
|
|
||||||
return self.getNumberAsync().continueWithBlock {
|
|
||||||
(task: BFTask!) -> NSString in
|
|
||||||
// This continuation block takes the NSNumber BFTask as input,
|
|
||||||
// and provides an NSString as output.
|
|
||||||
|
|
||||||
let number = task.result() as NSNumber
|
|
||||||
return NSString(format:"%@", number)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
In many cases, you only want to do more work if the previous task was successful, and propagate any errors or cancellations to be dealt with later. To do this, use the `continueWithSuccessBlock:` method instead of `continueWithBlock:`.
|
|
||||||
|
|
||||||
```objective-c
|
|
||||||
// Objective-C
|
|
||||||
[[self saveAsync:obj] continueWithSuccessBlock:^id(BFTask *task) {
|
|
||||||
// the object was saved successfully.
|
|
||||||
return nil;
|
|
||||||
}];
|
|
||||||
```
|
|
||||||
|
|
||||||
```swift
|
|
||||||
// Swift
|
|
||||||
self.saveAsync(obj).continueWithSuccessBlock {
|
|
||||||
(task: BFTask!) -> AnyObject! in
|
|
||||||
// the object was saved successfully.
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Chaining Tasks Together
|
|
||||||
|
|
||||||
BFTasks are a little bit magical, in that they let you chain them without nesting. If you return a BFTask from `continueWithBlock:`, then the task returned by `continueWithBlock:` will not be considered finished until the new task returned from the new continuation block. This lets you perform multiple actions without incurring the pyramid code you would get with callbacks. Likewise, you can return a `BFTask` from `continueWithSuccessBlock:`. So, return a `BFTask` to do more asynchronous work.
|
|
||||||
|
|
||||||
```objective-c
|
|
||||||
// Objective-C
|
|
||||||
PFQuery *query = [PFQuery queryWithClassName:@"Student"];
|
|
||||||
[query orderByDescending:@"gpa"];
|
|
||||||
[[[[[self findAsync:query] continueWithSuccessBlock:^id(BFTask *task) {
|
|
||||||
NSArray *students = task.result;
|
|
||||||
PFObject *valedictorian = [students objectAtIndex:0];
|
|
||||||
[valedictorian setObject:@YES forKey:@"valedictorian"];
|
|
||||||
return [self saveAsync:valedictorian];
|
|
||||||
}] continueWithSuccessBlock:^id(BFTask *task) {
|
|
||||||
PFObject *valedictorian = task.result;
|
|
||||||
return [self findAsync:query];
|
|
||||||
}] continueWithSuccessBlock:^id(BFTask *task) {
|
|
||||||
NSArray *students = task.result;
|
|
||||||
PFObject *salutatorian = [students objectAtIndex:1];
|
|
||||||
[salutatorian setObject:@YES forKey:@"salutatorian"];
|
|
||||||
return [self saveAsync:salutatorian];
|
|
||||||
}] continueWithSuccessBlock:^id(BFTask *task) {
|
|
||||||
// Everything is done!
|
|
||||||
return nil;
|
|
||||||
}];
|
|
||||||
```
|
|
||||||
|
|
||||||
```swift
|
|
||||||
// Swift
|
|
||||||
var query = PFQuery(className:"Student")
|
|
||||||
query.orderByDescending("gpa")
|
|
||||||
findAsync(query).continueWithSuccessBlock {
|
|
||||||
(task: BFTask!) -> BFTask in
|
|
||||||
let students = task.result() as NSArray
|
|
||||||
var valedictorian = students.objectAtIndex(0) as PFObject
|
|
||||||
valedictorian["valedictorian"] = true
|
|
||||||
return self.saveAsync(valedictorian)
|
|
||||||
}.continueWithSuccessBlock {
|
|
||||||
(task: BFTask!) -> BFTask in
|
|
||||||
var valedictorian = task.result() as PFObject
|
|
||||||
return self.findAsync(query)
|
|
||||||
}.continueWithSuccessBlock {
|
|
||||||
(task: BFTask!) -> BFTask in
|
|
||||||
let students = task.result() as NSArray
|
|
||||||
var salutatorian = students.objectAtIndex(1) as PFObject
|
|
||||||
salutatorian["salutatorian"] = true
|
|
||||||
return self.saveAsync(salutatorian)
|
|
||||||
}.continueWithSuccessBlock {
|
|
||||||
(task: BFTask!) -> AnyObject! in
|
|
||||||
// Everything is done!
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Error Handling
|
|
||||||
|
|
||||||
By carefully choosing whether to call `continueWithBlock:` or `continueWithSuccessBlock:`, you can control how errors are propagated in your application. Using `continueWithBlock:` lets you handle errors by transforming them or dealing with them. You can think of failed tasks kind of like throwing an exception. In fact, if you throw an exception inside a continuation, the resulting task will be faulted with that exception.
|
|
||||||
|
|
||||||
```objective-c
|
|
||||||
// Objective-C
|
|
||||||
PFQuery *query = [PFQuery queryWithClassName:@"Student"];
|
|
||||||
[query orderByDescending:@"gpa"];
|
|
||||||
[[[[[self findAsync:query] continueWithSuccessBlock:^id(BFTask *task) {
|
|
||||||
NSArray *students = task.result;
|
|
||||||
PFObject *valedictorian = [students objectAtIndex:0];
|
|
||||||
[valedictorian setObject:@YES forKey:@"valedictorian"];
|
|
||||||
// Force this callback to fail.
|
|
||||||
return [BFTask taskWithError:[NSError errorWithDomain:@"example.com"
|
|
||||||
code:-1
|
|
||||||
userInfo:nil]];
|
|
||||||
}] continueWithSuccessBlock:^id(BFTask *task) {
|
|
||||||
// Now this continuation will be skipped.
|
|
||||||
PFQuery *valedictorian = task.result;
|
|
||||||
return [self findAsync:query];
|
|
||||||
}] continueWithBlock:^id(BFTask *task) {
|
|
||||||
if (task.error) {
|
|
||||||
// This error handler WILL be called.
|
|
||||||
// The error will be the NSError returned above.
|
|
||||||
// Let's handle the error by returning a new value.
|
|
||||||
// The task will be completed with nil as its value.
|
|
||||||
return nil;
|
|
||||||
}
|
|
||||||
// This will also be skipped.
|
|
||||||
NSArray *students = task.result;
|
|
||||||
PFObject *salutatorian = [students objectAtIndex:1];
|
|
||||||
[salutatorian setObject:@YES forKey:@"salutatorian"];
|
|
||||||
return [self saveAsync:salutatorian];
|
|
||||||
}] continueWithSuccessBlock:^id(BFTask *task) {
|
|
||||||
// Everything is done! This gets called.
|
|
||||||
// The task's result is nil.
|
|
||||||
return nil;
|
|
||||||
}];
|
|
||||||
```
|
|
||||||
|
|
||||||
```swift
|
|
||||||
// Swift
|
|
||||||
var query = PFQuery(className:"Student")
|
|
||||||
query.orderByDescending("gpa")
|
|
||||||
findAsync(query).continueWithSuccessBlock {
|
|
||||||
(task: BFTask!) -> BFTask in
|
|
||||||
let students = task.result() as NSArray
|
|
||||||
var valedictorian = students.objectAtIndex(0) as PFObject
|
|
||||||
valedictorian["valedictorian"] = true
|
|
||||||
//Force this callback to fail.
|
|
||||||
return BFTask(error:NSError(domain:"example.com",
|
|
||||||
code:-1, userInfo: nil))
|
|
||||||
}.continueWithSuccessBlock {
|
|
||||||
(task: BFTask!) -> AnyObject! in
|
|
||||||
//Now this continuation will be skipped.
|
|
||||||
var valedictorian = task.result() as PFObject
|
|
||||||
return self.findAsync(query)
|
|
||||||
}.continueWithBlock {
|
|
||||||
(task: BFTask!) -> AnyObject! in
|
|
||||||
if task.error != nil {
|
|
||||||
// This error handler WILL be called.
|
|
||||||
// The error will be the NSError returned above.
|
|
||||||
// Let's handle the error by returning a new value.
|
|
||||||
// The task will be completed with nil as its value.
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
// This will also be skipped.
|
|
||||||
let students = task.result() as NSArray
|
|
||||||
var salutatorian = students.objectAtIndex(1) as PFObject
|
|
||||||
salutatorian["salutatorian"] = true
|
|
||||||
return self.saveAsync(salutatorian)
|
|
||||||
}.continueWithSuccessBlock {
|
|
||||||
(task: BFTask!) -> AnyObject! in
|
|
||||||
// Everything is done! This gets called.
|
|
||||||
// The tasks result is nil.
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
It's often convenient to have a long chain of success callbacks with only one error handler at the end.
|
|
||||||
|
|
||||||
## Creating Tasks
|
|
||||||
|
|
||||||
When you're getting started, you can just use the tasks returned from methods like `findAsync:` or `saveAsync:`. However, for more advanced scenarios, you may want to make your own tasks. To do that, you create a `BFTaskCompletionSource`. This object will let you create a new `BFTask`, and control whether it gets marked as finished or cancelled. After you create a `BFTaskCompletionSource`, you'll need to call `setResult:`, `setError:`, or `cancel` to trigger its continuations.
|
|
||||||
|
|
||||||
```objective-c
|
|
||||||
// Objective-C
|
|
||||||
- (BFTask *)successAsync {
|
|
||||||
BFTaskCompletionSource *successful = [BFTaskCompletionSource taskCompletionSource];
|
|
||||||
[successful setResult:@"The good result."];
|
|
||||||
return successful.task;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (BFTask *)failAsync {
|
|
||||||
BFTaskCompletionSource *failed = [BFTaskCompletionSource taskCompletionSource];
|
|
||||||
[failed setError:[NSError errorWithDomain:@"example.com" code:-1 userInfo:nil]];
|
|
||||||
return failed.task;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
```swift
|
|
||||||
// Swift
|
|
||||||
func successAsync() -> BFTask {
|
|
||||||
var successful = BFTaskCompletionSource()
|
|
||||||
successful.setResult("The good result.")
|
|
||||||
return successful.task
|
|
||||||
}
|
|
||||||
|
|
||||||
func failAsync() -> BFTask {
|
|
||||||
var failed = BFTaskCompletionSource()
|
|
||||||
failed.setError(NSError(domain:"example.com", code:-1, userInfo:nil))
|
|
||||||
return failed.task
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
If you know the result of a task at the time it is created, there are some convenience methods you can use.
|
|
||||||
|
|
||||||
```objective-c
|
|
||||||
// Objective-C
|
|
||||||
BFTask *successful = [BFTask taskWithResult:@"The good result."];
|
|
||||||
|
|
||||||
BFTask *failed = [BFTask taskWithError:anError];
|
|
||||||
```
|
|
||||||
|
|
||||||
```swift
|
|
||||||
// Swift
|
|
||||||
let successful = BFTask(result:"The good result")
|
|
||||||
|
|
||||||
let failed = BFTask(error:anError)
|
|
||||||
```
|
|
||||||
|
|
||||||
## Creating Async Methods
|
|
||||||
|
|
||||||
With these tools, it's easy to make your own asynchronous functions that return tasks. For example, you can make a task-based version of `fetchAsync:` easily.
|
|
||||||
|
|
||||||
```objective-c
|
|
||||||
// Objective-C
|
|
||||||
- (BFTask *) fetchAsync:(PFObject *)object {
|
|
||||||
BFTaskCompletionSource *task = [BFTaskCompletionSource taskCompletionSource];
|
|
||||||
[object fetchInBackgroundWithBlock:^(PFObject *object, NSError *error) {
|
|
||||||
if (!error) {
|
|
||||||
[task setResult:object];
|
|
||||||
} else {
|
|
||||||
[task setError:error];
|
|
||||||
}
|
|
||||||
}];
|
|
||||||
return task.task;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
```swift
|
|
||||||
// Swift
|
|
||||||
func fetchAsync(object: PFObject) -> BFTask {
|
|
||||||
var task = BFTaskCompletionSource()
|
|
||||||
object.fetchInBackgroundWithBlock {
|
|
||||||
(object: PFObject?, error: NSError?) -> Void in
|
|
||||||
if error == nil {
|
|
||||||
task.setResult(object)
|
|
||||||
} else {
|
|
||||||
task.setError(error)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return task.task
|
|
||||||
}
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
It's similarly easy to create `saveAsync:`, `findAsync:` or `deleteAsync:`.
|
|
||||||
|
|
||||||
## Tasks in Series
|
|
||||||
|
|
||||||
`BFTasks` are convenient when you want to do a series of tasks in a row, each one waiting for the previous to finish. For example, imagine you want to delete all of the comments on your blog.
|
|
||||||
|
|
||||||
```objective-c
|
|
||||||
// Objective-C
|
|
||||||
PFQuery *query = [PFQuery queryWithClassName:@"Comments"];
|
|
||||||
[query whereKey:@"post" equalTo:@123];
|
|
||||||
|
|
||||||
[[[self findAsync:query] continueWithBlock:^id(BFTask *task) {
|
|
||||||
NSArray *results = task.result;
|
|
||||||
|
|
||||||
// Create a trivial completed task as a base case.
|
|
||||||
BFTask *task = [BFTask taskWithResult:nil];
|
|
||||||
for (PFObject *result in results) {
|
|
||||||
// For each item, extend the task with a function to delete the item.
|
|
||||||
task = [task continueWithBlock:^id(BFTask *task) {
|
|
||||||
// Return a task that will be marked as completed when the delete is finished.
|
|
||||||
return [self deleteAsync:result];
|
|
||||||
}];
|
|
||||||
}
|
|
||||||
return task;
|
|
||||||
}] continueWithBlock:^id(BFTask *task) {
|
|
||||||
// Every comment was deleted.
|
|
||||||
return nil;
|
|
||||||
}];
|
|
||||||
```
|
|
||||||
|
|
||||||
```swift
|
|
||||||
// Swift
|
|
||||||
var query = PFQuery(className:"Comments")
|
|
||||||
query.whereKey("post", equalTo:123)
|
|
||||||
findAsync(query).continueWithBlock {
|
|
||||||
(task: BFTask!) -> BFTask in
|
|
||||||
let results = task.result() as NSArray
|
|
||||||
|
|
||||||
// Create a trivial completed task as a base case.
|
|
||||||
let task = BFTask(result:nil)
|
|
||||||
for result : PFObject in results {
|
|
||||||
// For each item, extend the task with a function to delete the item.
|
|
||||||
task = task.continueWithBlock {
|
|
||||||
(task: BFTask!) -> BFTask in
|
|
||||||
return self.deleteAsync(result)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return task
|
|
||||||
}.continueWithBlock {
|
|
||||||
(task: BFTask!) -> AnyObject! in
|
|
||||||
// Every comment was deleted.
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Tasks in Parallel
|
|
||||||
|
|
||||||
You can also perform several tasks in parallel, using the `taskForCompletionOfAllTasks:` method. You can start multiple operations at once, and use `taskForCompletionOfAllTasks:` to create a new task that will be marked as completed when all of its input tasks are completed. The new task will be successful only if all of the passed-in tasks succeed. Performing operations in parallel will be faster than doing them serially, but may consume more system resources and bandwidth.
|
|
||||||
|
|
||||||
```objective-c
|
|
||||||
// Objective-C
|
|
||||||
PFQuery *query = [PFQuery queryWithClassName:@"Comments"];
|
|
||||||
[query whereKey:@"post" equalTo:@123];
|
|
||||||
|
|
||||||
[[[self findAsync:query] continueWithBlock:^id(BFTask *results) {
|
|
||||||
// Collect one task for each delete into an array.
|
|
||||||
NSMutableArray *tasks = [NSMutableArray array];
|
|
||||||
for (PFObject *result in results) {
|
|
||||||
// Start this delete immediately and add its task to the list.
|
|
||||||
[tasks addObject:[self deleteAsync:result]];
|
|
||||||
}
|
|
||||||
// Return a new task that will be marked as completed when all of the deletes are
|
|
||||||
// finished.
|
|
||||||
return [BFTask taskForCompletionOfAllTasks:tasks];
|
|
||||||
}] continueWithBlock:^id(BFTask *task) {
|
|
||||||
// Every comment was deleted.
|
|
||||||
return nil;
|
|
||||||
}];
|
|
||||||
```
|
|
||||||
|
|
||||||
```swift
|
|
||||||
// Swift
|
|
||||||
var query = PFQuery(className:"Comments")
|
|
||||||
query.whereKey("post", equalTo:123)
|
|
||||||
|
|
||||||
findAsync(query).continueWithBlock {
|
|
||||||
(task: BFTask!) -> BFTask in
|
|
||||||
// Collect one task for each delete into an array.
|
|
||||||
var tasks = NSMutableArray.array()
|
|
||||||
var results = task.result() as NSArray
|
|
||||||
for result : PFObject! in results {
|
|
||||||
// Start this delete immediately and add its task to the list.
|
|
||||||
tasks.addObject(self.deleteAsync(result))
|
|
||||||
}
|
|
||||||
// Return a new task that will be marked as completed when all of the deletes
|
|
||||||
// are finished.
|
|
||||||
return BFTask(forCompletionOfAllTasks:tasks)
|
|
||||||
}.continueWithBlock {
|
|
||||||
(task: BFTask!) -> AnyObject! in
|
|
||||||
// Every comment was deleted.
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Task Executors
|
|
||||||
|
|
||||||
Both `continueWithBlock:` and `continueWithSuccessBlock:` methods have another form that takes an instance of `BFExecutor`. These are `continueWithExecutor:withBlock:` and `continueWithExecutor:withSuccessBlock:`. These methods allow you to control how the continuation is executed. The default executor will dispatch to GCD, but you can provide your own executor to schedule work onto a different thread. For example, if you want to continue with work on the UI thread:
|
|
||||||
|
|
||||||
```objective-c
|
|
||||||
// Create a BFExecutor that uses the main thread.
|
|
||||||
BFExecutor *myExecutor = [BFExecutor executorWithBlock:^void(void(^block)()) {
|
|
||||||
dispatch_async(dispatch_get_main_queue(), block);
|
|
||||||
}];
|
|
||||||
|
|
||||||
// And use the Main Thread Executor like this. The executor applies only to the new
|
|
||||||
// continuation being passed into continueWithBlock.
|
|
||||||
[[self fetchAsync:object] continueWithExecutor:myExecutor withBlock:^id(BFTask *task) {
|
|
||||||
myTextView.text = [object objectForKey:@"name"];
|
|
||||||
}];
|
|
||||||
```
|
|
||||||
|
|
||||||
For common cases, such as dispatching on the main thread, we have provided default implementations of `BFExecutor`. These include `defaultExecutor`, `immediateExecutor`, `mainThreadExecutor`, `executorWithDispatchQueue:`, and `executorWithOperationQueue:`. For example:
|
|
||||||
|
|
||||||
```objective-c
|
|
||||||
// Continue on the Main Thread, using a built-in executor.
|
|
||||||
[[self fetchAsync:object] continueWithExecutor:[BFExecutor mainThreadExecutor] withBlock:^id(BFTask *task) {
|
|
||||||
myTextView.text = [object objectForKey:@"name"];
|
|
||||||
}];
|
|
||||||
```
|
|
||||||
|
|
||||||
## Task Cancellation
|
|
||||||
|
|
||||||
It's generally bad design to keep track of the `BFTaskCompletionSource` for cancellation. A better model is to create a "cancellation token" at the top level, and pass that to each async function that you want to be part of the same "cancelable operation". Then, in your continuation blocks, you can check whether the cancellation token has been cancelled and bail out early by returning a `[BFTask cancelledTask]`. For example:
|
|
||||||
|
|
||||||
```objective-c
|
|
||||||
- (void)doSomethingComplicatedAsync:(MYCancellationToken *)cancellationToken {
|
|
||||||
[[self doSomethingAsync:cancellationToken] continueWithBlock:^{
|
|
||||||
if (cancellationToken.isCancelled) {
|
|
||||||
return [BFTask cancelledTask];
|
|
||||||
}
|
|
||||||
// Do something that takes a while.
|
|
||||||
return result;
|
|
||||||
}];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Somewhere else.
|
|
||||||
MYCancellationToken *cancellationToken = [[MYCancellationToken alloc] init];
|
|
||||||
[obj doSomethingComplicatedAsync:cancellationToken];
|
|
||||||
|
|
||||||
// When you get bored...
|
|
||||||
[cancellationToken cancel];
|
|
||||||
```
|
|
||||||
|
|
||||||
**Note:** The cancellation token implementation should be thread-safe.
|
|
||||||
We are likely to add some concept like this to Bolts at some point in the future.
|
|
||||||
|
|
||||||
# App Links
|
|
||||||
|
|
||||||
[App Links](http://applinks.org/) provide a cross-platform mechanism that allows a developer to define and publish a deep-linking scheme for their content, allowing other apps to link directly to an experience optimized for the device they are running on. Whether you are building an app that receives incoming links or one that may link out to other apps' content, Bolts provides tools to simplify implementation of the [App Links protocol](http://applinks.org/documentation).
|
|
||||||
|
|
||||||
## Handling an App Link
|
|
||||||
|
|
||||||
The most common case will be making your app receive App Links. In-linking will allow your users to quickly access the richest, most native-feeling presentation of linked content on their devices. Bolts makes it easy to handle an inbound App Link (as well as general inbound deep-links) by providing utilities for processing an incoming URL.
|
|
||||||
|
|
||||||
For example, you can use the `BFURL` utility class to parse an incoming URL in your `AppDelegate`:
|
|
||||||
|
|
||||||
```objective-c
|
|
||||||
- (BOOL)application:(UIApplication *)application
|
|
||||||
openURL:(NSURL *)url
|
|
||||||
sourceApplication:(NSString *)sourceApplication
|
|
||||||
annotation:(id)annotation {
|
|
||||||
BFURL *parsedUrl = [BFURL URLWithInboundURL:url sourceApplication:sourceApplication];
|
|
||||||
|
|
||||||
// Use the target URL from the App Link to locate content.
|
|
||||||
if ([parsedUrl.targetURL.pathComponents[1] isEqualToString:@"profiles"]) {
|
|
||||||
// Open a profile viewer.
|
|
||||||
}
|
|
||||||
|
|
||||||
// You can also check the query string easily.
|
|
||||||
NSString *query = parsedUrl.targetQueryParameters[@"query"];
|
|
||||||
|
|
||||||
// Apps that have existing deep-linking support and map their App Links to existing
|
|
||||||
// deep-linking functionality may instead want to perform these operations on the input URL.
|
|
||||||
// Use the target URL from the App Link to locate content.
|
|
||||||
if ([parsedUrl.inputURL.pathComponents[1] isEqualToString:@"profiles"]) {
|
|
||||||
// Open a profile viewer.
|
|
||||||
}
|
|
||||||
|
|
||||||
// You can also check the query string easily.
|
|
||||||
NSString *query = parsedUrl.inputQueryParameters[@"query"];
|
|
||||||
|
|
||||||
// Apps can easily check the Extras and App Link data from the App Link as well.
|
|
||||||
NSString *fbAccessToken = parsedUrl.appLinkExtras[@"fb_access_token"];
|
|
||||||
NSDictionary *refererData = parsedUrl.appLinkExtras[@"referer"];
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Navigating to a URL
|
|
||||||
|
|
||||||
Following an App Link allows your app to provide the best user experience (as defined by the receiving app) when a user navigates to a link. Bolts makes this process simple, automating the steps required to follow a link:
|
|
||||||
|
|
||||||
1. Resolve the App Link by getting the App Link metadata from the HTML at the URL specified.
|
|
||||||
2. Step through App Link targets relevant to the device being used, checking whether the app that can handle the target is present on the device.
|
|
||||||
3. If an app is present, build a URL with the appropriate al_applink_data specified and navigate to that URL.
|
|
||||||
4. Otherwise, open the browser with the original URL specified.
|
|
||||||
|
|
||||||
In the simplest case, it takes just one line of code to navigate to a URL that may have an App Link:
|
|
||||||
|
|
||||||
```objective-c
|
|
||||||
[BFAppLinkNavigation navigateToURLInBackground:url];
|
|
||||||
```
|
|
||||||
|
|
||||||
### Adding App and Navigation Data
|
|
||||||
|
|
||||||
Under most circumstances, the data that will need to be passed along to an app during a navigation will be contained in the URL itself, so that whether or not the app is actually installed on the device, users are taken to the correct content. Occasionally, however, apps will want to pass along data that is relevant for app-to-app navigation, or will want to augment the App Link protocol with information that might be used by the app to adjust how the app should behave (e.g. showing a link back to the referring app).
|
|
||||||
|
|
||||||
If you want to take advantage of these features, you can break apart the navigation process. First, you must have an App Link to which you wish to navigate:
|
|
||||||
|
|
||||||
```objective-c
|
|
||||||
[[BFAppLinkNavigation resolveAppLinkInBackground:url] continueWithSuccessBlock:^id(BFTask *task) {
|
|
||||||
BFAppLink *link = task.result;
|
|
||||||
}];
|
|
||||||
```
|
|
||||||
|
|
||||||
Then, you can build an App Link request with any additional data you would like and navigate:
|
|
||||||
|
|
||||||
```objective-c
|
|
||||||
BFAppLinkNavigation *navigation = [BFAppLinkNavigation navigationWithAppLink:link
|
|
||||||
extras:@{ @"access_token": @"t0kEn" }
|
|
||||||
appLinkData:@{ @"ref": @"12345" }];
|
|
||||||
NSError *error = nil;
|
|
||||||
[navigation navigate:&error];
|
|
||||||
```
|
|
||||||
|
|
||||||
### Resolving App Link Metadata
|
|
||||||
|
|
||||||
Bolts allows for custom App Link resolution, which may be used as a performance optimization (e.g. caching the metadata) or as a mechanism to allow developers to use a centralized index for obtaining App Link metadata. A custom App Link resolver just needs to be able to take a URL and return a `BFAppLink` containing the ordered list of `BFAppLinkTarget`s that are applicable for this device. Bolts provides one of these out of the box that performs this resolution on the device using a hidden UIWebView.
|
|
||||||
|
|
||||||
You can use any resolver that implements the `BFAppLinkResolving` protocol by using one of the overloads on `BFAppLinkNavigation`:
|
|
||||||
|
|
||||||
```objective-c
|
|
||||||
[BFAppLinkNavigation navigateToURLInBackground:url
|
|
||||||
resolver:resolver];
|
|
||||||
```
|
|
||||||
|
|
||||||
Alternatively, a you can swap out the default resolver to be used by the built-in APIs:
|
|
||||||
|
|
||||||
```objective-c
|
|
||||||
[BFAppLinkNavigation setDefaultResolver:resolver];
|
|
||||||
[BFAppLinkNavigation navigateToURLInBackground:url];
|
|
||||||
```
|
|
||||||
|
|
||||||
## App Link Return-to-Referer View
|
|
||||||
|
|
||||||
When an application is opened via an App Link, a banner allowing the user to "Touch to return to <calling app>" should be displayed. The `BFAppLinkReturnToRefererView` provides this functionality. It will take an incoming App Link and parse the referer information to display the appropriate calling app name.
|
|
||||||
|
|
||||||
```objective-c
|
|
||||||
- (void)viewDidLoad {
|
|
||||||
[super viewDidLoad];
|
|
||||||
|
|
||||||
// Perform other view initialization.
|
|
||||||
|
|
||||||
self.returnToRefererController = [[BFAppLinkReturnToRefererController alloc] init];
|
|
||||||
|
|
||||||
// self.returnToRefererView is a BFAppLinkReturnToRefererView.
|
|
||||||
// You may initialize the view either by loading it from a NIB or programmatically.
|
|
||||||
self.returnToRefererController.view = self.returnToRefererView;
|
|
||||||
|
|
||||||
// If you have a UINavigationController in the view, then the bar must be shown above it.
|
|
||||||
[self.returnToRefererController]
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
The following code assumes that the view controller has an `openedAppLinkURL` `NSURL` property that has already been populated with the URL used to open the app. You can then do something like this to show the view:
|
|
||||||
|
|
||||||
```objective-c
|
|
||||||
- (void)viewWillAppear {
|
|
||||||
[super viewWillAppear];
|
|
||||||
|
|
||||||
// Show only if you have a back AppLink.
|
|
||||||
[self.returnToRefererController showViewForRefererURL:self.openedAppLinkURL];
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
In a navigation-controller view hierarchy, the banner should be displayed above the navigation bar, and `BFAppLinkReturnToRefererController` provides an `initForDisplayAboveNavController` method to assist with this.
|
|
||||||
|
|
||||||
## Analytics
|
|
||||||
|
|
||||||
Bolts introduces Measurement Event. App Links posts three different Measurement Event notifications to the application, which can be caught and integrated with existing analytics components in your application.
|
|
||||||
|
|
||||||
* `al_nav_out` — Raised when your app switches out to an App Links URL.
|
|
||||||
* `al_nav_in` — Raised when your app opens an incoming App Links URL.
|
|
||||||
* `al_ref_back_out` — Raised when your app returns back the referrer app using the built-in top navigation back bar view.
|
|
||||||
|
|
||||||
### Listen for App Links Measurement Events
|
|
||||||
|
|
||||||
There are other analytics tools that are integrated with Bolts' App Links events, but you can also listen for these events yourself:
|
|
||||||
|
|
||||||
```objective-c
|
|
||||||
[[NSNotificationCenter defaultCenter] addObserverForName:BFMeasurementEventNotificationName object:nil queue:nil usingBlock:^(NSNotification *note) {
|
|
||||||
NSDictionary *event = note.userInfo;
|
|
||||||
NSDictionary *eventData = event[BFMeasurementEventArgsKey];
|
|
||||||
// Integrate to your logging/analytics component.
|
|
||||||
}];
|
|
||||||
```
|
|
||||||
|
|
||||||
### App Links Event Fields
|
|
||||||
|
|
||||||
App Links Measurement Events sends additional information from App Links Intents in flattened string key value pairs. Here are some of the useful fields for the three events.
|
|
||||||
|
|
||||||
* `al_nav_in`
|
|
||||||
* `inputURL`: the URL that opens the app.
|
|
||||||
* `inputURLScheme`: the scheme of `inputURL`.
|
|
||||||
* `refererURL`: the URL that the referrer app added into `al_applink_data`: `referer_app_link`.
|
|
||||||
* `refererAppName`: the app name that the referrer app added to `al_applink_data`: `referer_app_link`.
|
|
||||||
* `sourceApplication`: the bundle of referrer application.
|
|
||||||
* `targetURL`: the `target_url` field in `al_applink_data`.
|
|
||||||
* `version`: App Links API version.
|
|
||||||
|
|
||||||
* `al_nav_out` / `al_ref_back_out`
|
|
||||||
* `outputURL`: the URL used to open the other app (or browser). If there is an eligible app to open, this will be the custom scheme url/intent in `al_applink_data`.
|
|
||||||
* `outputURLScheme`: the scheme of `outputURL`.
|
|
||||||
* `sourceURL`: the URL of the page hosting App Links meta tags.
|
|
||||||
* `sourceURLHost`: the hostname of `sourceURL`.
|
|
||||||
* `success`: `“1”` to indicate success in opening the App Link in another app or browser; `“0”` to indicate failure to open the App Link.
|
|
||||||
* `type`: `“app”` for open in app, `“web”` for open in browser; `“fail”` when the success field is `“0”`.
|
|
||||||
* `version`: App Links API version.
|
|
||||||
|
|
||||||
# Installation
|
|
||||||
|
|
||||||
You can download the latest framework files from our [Releases page](https://github.com/BoltsFramework/Bolts-ObjC/releases).
|
|
||||||
|
|
||||||
Bolts is also available through [CocoaPods](https://cocoapods.org/). To install it simply add the following line to your Podfile:
|
|
||||||
|
|
||||||
pod 'Bolts'
|
|
||||||
@ -24,23 +24,28 @@
|
|||||||
|
|
||||||
#import <FBSDKCoreKit/FBSDKGraphRequestConnection.h>
|
#import <FBSDKCoreKit/FBSDKGraphRequestConnection.h>
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_BEGIN
|
||||||
|
|
||||||
@class FBSDKAccessToken;
|
@class FBSDKAccessToken;
|
||||||
@class FBSDKGraphRequest;
|
@class FBSDKGraphRequest;
|
||||||
|
|
||||||
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0
|
#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. */
|
/** NSNotificationCenter name indicating a result of a failed log flush attempt. The posted object will be an NSError instance. */
|
||||||
FOUNDATION_EXPORT NSNotificationName const FBSDKAppEventsLoggingResultNotification;
|
FOUNDATION_EXPORT NSNotificationName const FBSDKAppEventsLoggingResultNotification
|
||||||
|
NS_SWIFT_NAME(AppEventsLoggingResult);
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
/** NSNotificationCenter name indicating a result of a failed log flush attempt. The posted object will be an NSError instance. */
|
/** NSNotificationCenter name indicating a result of a failed log flush attempt. The posted object will be an NSError instance. */
|
||||||
FOUNDATION_EXPORT NSString *const FBSDKAppEventsLoggingResultNotification;
|
FOUNDATION_EXPORT NSString *const FBSDKAppEventsLoggingResultNotification
|
||||||
|
NS_SWIFT_NAME(AppEventsLoggingResultNotification);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/** optional plist key ("FacebookLoggingOverrideAppID") for setting `loggingOverrideAppID` */
|
/** optional plist key ("FacebookLoggingOverrideAppID") for setting `loggingOverrideAppID` */
|
||||||
FOUNDATION_EXPORT NSString *const FBSDKAppEventsOverrideAppIDBundleKey;
|
FOUNDATION_EXPORT NSString *const FBSDKAppEventsOverrideAppIDBundleKey
|
||||||
|
NS_SWIFT_NAME(AppEventsOverrideAppIDBundleKey);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
||||||
@ -59,8 +64,7 @@ typedef NS_ENUM(NSUInteger, FBSDKAppEventsFlushBehavior)
|
|||||||
events are persisted and re-established at activation, but they will only be written with an
|
events are persisted and re-established at activation, but they will only be written with an
|
||||||
explicit call to `flush`. */
|
explicit call to `flush`. */
|
||||||
FBSDKAppEventsFlushBehaviorExplicitOnly,
|
FBSDKAppEventsFlushBehaviorExplicitOnly,
|
||||||
|
} NS_SWIFT_NAME(AppEvents.FlushBehavior);
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
NS_ENUM(NSUInteger, FBSDKProductAvailability)
|
NS_ENUM(NSUInteger, FBSDKProductAvailability)
|
||||||
@ -88,7 +92,7 @@ typedef NS_ENUM(NSUInteger, FBSDKProductAvailability)
|
|||||||
* Discontinued
|
* Discontinued
|
||||||
*/
|
*/
|
||||||
FBSDKProductAvailabilityDiscontinued,
|
FBSDKProductAvailabilityDiscontinued,
|
||||||
};
|
} NS_SWIFT_NAME(AppEvents.ProductAvailability);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
NS_ENUM(NSUInteger, FBSDKProductCondition)
|
NS_ENUM(NSUInteger, FBSDKProductCondition)
|
||||||
@ -99,208 +103,266 @@ typedef NS_ENUM(NSUInteger, FBSDKProductCondition)
|
|||||||
FBSDKProductConditionNew = 0,
|
FBSDKProductConditionNew = 0,
|
||||||
FBSDKProductConditionRefurbished,
|
FBSDKProductConditionRefurbished,
|
||||||
FBSDKProductConditionUsed,
|
FBSDKProductConditionUsed,
|
||||||
};
|
} NS_SWIFT_NAME(AppEvents.ProductCondition);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@methodgroup Predefined event names for logging events common to many apps. Logging occurs through the `logEvent` family of methods on `FBSDKAppEvents`.
|
@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.
|
Common event parameters are provided in the `FBSDKAppEventsParameterNames*` constants.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/// typedef for FBSDKAppEventName
|
||||||
|
typedef NSString *const FBSDKAppEventName NS_TYPED_EXTENSIBLE_ENUM NS_SWIFT_NAME(AppEvents.Name);
|
||||||
|
|
||||||
/** Log this event when the user has achieved a level in the app. */
|
/** Log this event when the user has achieved a level in the app. */
|
||||||
FOUNDATION_EXPORT NSString *const FBSDKAppEventNameAchievedLevel;
|
FOUNDATION_EXPORT FBSDKAppEventName FBSDKAppEventNameAchievedLevel;
|
||||||
|
|
||||||
/** Log this event when the user has entered their payment info. */
|
/** Log this event when the user has entered their payment info. */
|
||||||
FOUNDATION_EXPORT NSString *const FBSDKAppEventNameAddedPaymentInfo;
|
FOUNDATION_EXPORT FBSDKAppEventName 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. */
|
/** 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;
|
FOUNDATION_EXPORT FBSDKAppEventName 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. */
|
/** 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;
|
FOUNDATION_EXPORT FBSDKAppEventName FBSDKAppEventNameAddedToWishlist;
|
||||||
|
|
||||||
/** Log this event when a user has completed registration with the app. */
|
/** Log this event when a user has completed registration with the app. */
|
||||||
FOUNDATION_EXPORT NSString *const FBSDKAppEventNameCompletedRegistration;
|
FOUNDATION_EXPORT FBSDKAppEventName FBSDKAppEventNameCompletedRegistration;
|
||||||
|
|
||||||
/** Log this event when the user has completed a tutorial in the app. */
|
/** Log this event when the user has completed a tutorial in the app. */
|
||||||
FOUNDATION_EXPORT NSString *const FBSDKAppEventNameCompletedTutorial;
|
FOUNDATION_EXPORT FBSDKAppEventName 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. */
|
/** 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;
|
FOUNDATION_EXPORT FBSDKAppEventName FBSDKAppEventNameInitiatedCheckout;
|
||||||
|
|
||||||
|
/** Log this event when the user has completed a transaction. The valueToSum passed to logEvent should be the total price of the transaction. */
|
||||||
|
FOUNDATION_EXPORT FBSDKAppEventName FBSDKAppEventNamePurchased;
|
||||||
|
|
||||||
/** Log this event when the user has rated an item in the app. The valueToSum passed to logEvent should be the numeric rating. */
|
/** 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;
|
FOUNDATION_EXPORT FBSDKAppEventName FBSDKAppEventNameRated;
|
||||||
|
|
||||||
/** Log this event when a user has performed a search within the app. */
|
/** Log this event when a user has performed a search within the app. */
|
||||||
FOUNDATION_EXPORT NSString *const FBSDKAppEventNameSearched;
|
FOUNDATION_EXPORT FBSDKAppEventName FBSDKAppEventNameSearched;
|
||||||
|
|
||||||
/** Log this event when the user has spent app credits. The valueToSum passed to logEvent should be the number of credits spent. */
|
/** 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;
|
FOUNDATION_EXPORT FBSDKAppEventName FBSDKAppEventNameSpentCredits;
|
||||||
|
|
||||||
/** Log this event when the user has unlocked an achievement in the app. */
|
/** Log this event when the user has unlocked an achievement in the app. */
|
||||||
FOUNDATION_EXPORT NSString *const FBSDKAppEventNameUnlockedAchievement;
|
FOUNDATION_EXPORT FBSDKAppEventName FBSDKAppEventNameUnlockedAchievement;
|
||||||
|
|
||||||
/** Log this event when a user has viewed a form of content in the app. */
|
/** Log this event when a user has viewed a form of content in the app. */
|
||||||
FOUNDATION_EXPORT NSString *const FBSDKAppEventNameViewedContent;
|
FOUNDATION_EXPORT FBSDKAppEventName FBSDKAppEventNameViewedContent;
|
||||||
|
|
||||||
/** A telephone/SMS, email, chat or other type of contact between a customer and your business. */
|
/** A telephone/SMS, email, chat or other type of contact between a customer and your business. */
|
||||||
FOUNDATION_EXPORT NSString *const FBSDKAppEventNameContact;
|
FOUNDATION_EXPORT FBSDKAppEventName FBSDKAppEventNameContact;
|
||||||
|
|
||||||
/** The customization of products through a configuration tool or other application your business owns. */
|
/** The customization of products through a configuration tool or other application your business owns. */
|
||||||
FOUNDATION_EXPORT NSString *const FBSDKAppEventNameCustomizeProduct;
|
FOUNDATION_EXPORT FBSDKAppEventName FBSDKAppEventNameCustomizeProduct;
|
||||||
|
|
||||||
/** The donation of funds to your organization or cause. */
|
/** The donation of funds to your organization or cause. */
|
||||||
FOUNDATION_EXPORT NSString *const FBSDKAppEventNameDonate;
|
FOUNDATION_EXPORT FBSDKAppEventName 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). */
|
/** 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;
|
FOUNDATION_EXPORT FBSDKAppEventName FBSDKAppEventNameFindLocation;
|
||||||
|
|
||||||
/** The booking of an appointment to visit one of your locations. */
|
/** The booking of an appointment to visit one of your locations. */
|
||||||
FOUNDATION_EXPORT NSString *const FBSDKAppEventNameSchedule;
|
FOUNDATION_EXPORT FBSDKAppEventName FBSDKAppEventNameSchedule;
|
||||||
|
|
||||||
|
/** The subsequent subscriptions after the start of a paid subscription for a product or service you offer. */
|
||||||
|
FOUNDATION_EXPORT FBSDKAppEventName FBSDKAppEventNameSubscriptionHeartbeat __attribute((deprecated("This attribute is no longer used.")));
|
||||||
|
|
||||||
/** The start of a free trial of a product or service you offer (example: trial subscription). */
|
/** The start of a free trial of a product or service you offer (example: trial subscription). */
|
||||||
FOUNDATION_EXPORT NSString *const FBSDKAppEventNameStartTrial;
|
FOUNDATION_EXPORT FBSDKAppEventName FBSDKAppEventNameStartTrial;
|
||||||
|
|
||||||
/** The submission of an application for a product, service or program you offer (example: credit card, educational program or job). */
|
/** 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;
|
FOUNDATION_EXPORT FBSDKAppEventName FBSDKAppEventNameSubmitApplication;
|
||||||
|
|
||||||
/** The start of a paid subscription for a product or service you offer. */
|
/** The start of a paid subscription for a product or service you offer. */
|
||||||
FOUNDATION_EXPORT NSString *const FBSDKAppEventNameSubscribe;
|
FOUNDATION_EXPORT FBSDKAppEventName FBSDKAppEventNameSubscribe;
|
||||||
|
|
||||||
/** Log this event when the user views an ad. */
|
/** Log this event when the user views an ad. */
|
||||||
FOUNDATION_EXPORT NSString *const FBSDKAppEventNameAdImpression;
|
FOUNDATION_EXPORT FBSDKAppEventName FBSDKAppEventNameAdImpression;
|
||||||
|
|
||||||
/** Log this event when the user clicks an ad. */
|
/** Log this event when the user clicks an ad. */
|
||||||
FOUNDATION_EXPORT NSString *const FBSDKAppEventNameAdClick;
|
FOUNDATION_EXPORT FBSDKAppEventName FBSDKAppEventNameAdClick;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@methodgroup Predefined event name parameters for common additional information to accompany events logged through the `logEvent` family
|
@methodgroup Predefined event name parameters for common additional information to accompany events logged through the `logEvent` family
|
||||||
of methods on `FBSDKAppEvents`. Common event names are provided in the `FBAppEventName*` constants.
|
of methods on `FBSDKAppEvents`. Common event names are provided in the `FBAppEventName*` constants.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/// typedef for FBSDKAppEventParameterName
|
||||||
|
typedef NSString *const FBSDKAppEventParameterName NS_TYPED_EXTENSIBLE_ENUM NS_SWIFT_NAME(AppEvents.ParameterName);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parameter key used to specify data for the one or more pieces of content being logged about.
|
* Parameter key used to specify data for the one or more pieces of content being logged about.
|
||||||
* Data should be a JSON encoded string.
|
* Data should be a JSON encoded string.
|
||||||
* Example:
|
* Example:
|
||||||
* "[{\"id\": \"1234\", \"quantity\": 2, \"item_price\": 5.99}, {\"id\": \"5678\", \"quantity\": 1, \"item_price\": 9.99}]"
|
* "[{\"id\": \"1234\", \"quantity\": 2, \"item_price\": 5.99}, {\"id\": \"5678\", \"quantity\": 1, \"item_price\": 9.99}]"
|
||||||
*/
|
*/
|
||||||
FOUNDATION_EXPORT NSString *const FBSDKAppEventParameterNameContent;
|
FOUNDATION_EXPORT FBSDKAppEventParameterName 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. */
|
/** 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;
|
FOUNDATION_EXPORT FBSDKAppEventParameterName 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. */
|
/** 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;
|
FOUNDATION_EXPORT FBSDKAppEventParameterName 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>. */
|
/** 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;
|
FOUNDATION_EXPORT FBSDKAppEventParameterName 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. */
|
/** 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;
|
FOUNDATION_EXPORT FBSDKAppEventParameterName FBSDKAppEventParameterNameDescription;
|
||||||
|
|
||||||
/** Parameter key used to specify the level achieved in a `FBAppEventNameAchieved` event. */
|
/** Parameter key used to specify the level achieved in a `FBAppEventNameAchieved` event. */
|
||||||
FOUNDATION_EXPORT NSString *const FBSDKAppEventParameterNameLevel;
|
FOUNDATION_EXPORT FBSDKAppEventParameterName FBSDKAppEventParameterNameLevel;
|
||||||
|
|
||||||
/** Parameter key used to specify the maximum rating available for the `FBAppEventNameRate` event. E.g., "5" or "10". */
|
/** Parameter key used to specify the maximum rating available for the `FBAppEventNameRate` event. E.g., "5" or "10". */
|
||||||
FOUNDATION_EXPORT NSString *const FBSDKAppEventParameterNameMaxRatingValue;
|
FOUNDATION_EXPORT FBSDKAppEventParameterName FBSDKAppEventParameterNameMaxRatingValue;
|
||||||
|
|
||||||
/** Parameter key used to specify how many items are being processed for an `FBAppEventNameInitiatedCheckout` or `FBAppEventNamePurchased` event. */
|
/** Parameter key used to specify how many items are being processed for an `FBAppEventNameInitiatedCheckout` or `FBAppEventNamePurchased` event. */
|
||||||
FOUNDATION_EXPORT NSString *const FBSDKAppEventParameterNameNumItems;
|
FOUNDATION_EXPORT FBSDKAppEventParameterName 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. */
|
/** 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;
|
FOUNDATION_EXPORT FBSDKAppEventParameterName FBSDKAppEventParameterNamePaymentInfoAvailable;
|
||||||
|
|
||||||
/** Parameter key used to specify method user has used to register for the app, e.g., "Facebook", "email", "Twitter", etc */
|
/** 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;
|
FOUNDATION_EXPORT FBSDKAppEventParameterName FBSDKAppEventParameterNameRegistrationMethod;
|
||||||
|
|
||||||
/** Parameter key used to specify the string provided by the user for a search operation. */
|
/** Parameter key used to specify the string provided by the user for a search operation. */
|
||||||
FOUNDATION_EXPORT NSString *const FBSDKAppEventParameterNameSearchString;
|
FOUNDATION_EXPORT FBSDKAppEventParameterName 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. */
|
/** 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;
|
FOUNDATION_EXPORT FBSDKAppEventParameterName FBSDKAppEventParameterNameSuccess;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@methodgroup Predefined event name parameters for common additional information to accompany events logged through the `logProductItem` method on `FBSDKAppEvents`.
|
@methodgroup Predefined event name parameters for common additional information to accompany events logged through the `logProductItem` method on `FBSDKAppEvents`.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/// typedef for FBSDKAppEventParameterProduct
|
||||||
|
typedef NSString *const FBSDKAppEventParameterProduct NS_TYPED_EXTENSIBLE_ENUM NS_SWIFT_NAME(AppEvents.ParameterProduct);
|
||||||
|
|
||||||
|
/** Parameter key used to specify the product item's category. */
|
||||||
|
FOUNDATION_EXPORT FBSDKAppEventParameterProduct FBSDKAppEventParameterProductCategory;
|
||||||
|
|
||||||
/** Parameter key used to specify the product item's custom label 0. */
|
/** Parameter key used to specify the product item's custom label 0. */
|
||||||
FOUNDATION_EXPORT NSString *const FBSDKAppEventParameterProductCustomLabel0;
|
FOUNDATION_EXPORT FBSDKAppEventParameterProduct FBSDKAppEventParameterProductCustomLabel0;
|
||||||
|
|
||||||
/** Parameter key used to specify the product item's custom label 1. */
|
/** Parameter key used to specify the product item's custom label 1. */
|
||||||
FOUNDATION_EXPORT NSString *const FBSDKAppEventParameterProductCustomLabel1;
|
FOUNDATION_EXPORT FBSDKAppEventParameterProduct FBSDKAppEventParameterProductCustomLabel1;
|
||||||
|
|
||||||
/** Parameter key used to specify the product item's custom label 2. */
|
/** Parameter key used to specify the product item's custom label 2. */
|
||||||
FOUNDATION_EXPORT NSString *const FBSDKAppEventParameterProductCustomLabel2;
|
FOUNDATION_EXPORT FBSDKAppEventParameterProduct FBSDKAppEventParameterProductCustomLabel2;
|
||||||
|
|
||||||
/** Parameter key used to specify the product item's custom label 3. */
|
/** Parameter key used to specify the product item's custom label 3. */
|
||||||
FOUNDATION_EXPORT NSString *const FBSDKAppEventParameterProductCustomLabel3;
|
FOUNDATION_EXPORT FBSDKAppEventParameterProduct FBSDKAppEventParameterProductCustomLabel3;
|
||||||
|
|
||||||
/** Parameter key used to specify the product item's custom label 4. */
|
/** Parameter key used to specify the product item's custom label 4. */
|
||||||
FOUNDATION_EXPORT NSString *const FBSDKAppEventParameterProductCustomLabel4;
|
FOUNDATION_EXPORT FBSDKAppEventParameterProduct FBSDKAppEventParameterProductCustomLabel4;
|
||||||
|
|
||||||
/** Parameter key used to specify the product item's AppLink app URL for iOS. */
|
/** Parameter key used to specify the product item's AppLink app URL for iOS. */
|
||||||
FOUNDATION_EXPORT NSString *const FBSDKAppEventParameterProductAppLinkIOSUrl;
|
FOUNDATION_EXPORT FBSDKAppEventParameterProduct FBSDKAppEventParameterProductAppLinkIOSUrl;
|
||||||
|
|
||||||
/** Parameter key used to specify the product item's AppLink app ID for iOS App Store. */
|
/** Parameter key used to specify the product item's AppLink app ID for iOS App Store. */
|
||||||
FOUNDATION_EXPORT NSString *const FBSDKAppEventParameterProductAppLinkIOSAppStoreID;
|
FOUNDATION_EXPORT FBSDKAppEventParameterProduct FBSDKAppEventParameterProductAppLinkIOSAppStoreID;
|
||||||
|
|
||||||
/** Parameter key used to specify the product item's AppLink app name for iOS. */
|
/** Parameter key used to specify the product item's AppLink app name for iOS. */
|
||||||
FOUNDATION_EXPORT NSString *const FBSDKAppEventParameterProductAppLinkIOSAppName;
|
FOUNDATION_EXPORT FBSDKAppEventParameterProduct FBSDKAppEventParameterProductAppLinkIOSAppName;
|
||||||
|
|
||||||
/** Parameter key used to specify the product item's AppLink app URL for iPhone. */
|
/** Parameter key used to specify the product item's AppLink app URL for iPhone. */
|
||||||
FOUNDATION_EXPORT NSString *const FBSDKAppEventParameterProductAppLinkIPhoneUrl;
|
FOUNDATION_EXPORT FBSDKAppEventParameterProduct FBSDKAppEventParameterProductAppLinkIPhoneUrl;
|
||||||
|
|
||||||
/** Parameter key used to specify the product item's AppLink app ID for iPhone App Store. */
|
/** Parameter key used to specify the product item's AppLink app ID for iPhone App Store. */
|
||||||
FOUNDATION_EXPORT NSString *const FBSDKAppEventParameterProductAppLinkIPhoneAppStoreID;
|
FOUNDATION_EXPORT FBSDKAppEventParameterProduct FBSDKAppEventParameterProductAppLinkIPhoneAppStoreID;
|
||||||
|
|
||||||
/** Parameter key used to specify the product item's AppLink app name for iPhone. */
|
/** Parameter key used to specify the product item's AppLink app name for iPhone. */
|
||||||
FOUNDATION_EXPORT NSString *const FBSDKAppEventParameterProductAppLinkIPhoneAppName;
|
FOUNDATION_EXPORT FBSDKAppEventParameterProduct FBSDKAppEventParameterProductAppLinkIPhoneAppName;
|
||||||
|
|
||||||
/** Parameter key used to specify the product item's AppLink app URL for iPad. */
|
/** Parameter key used to specify the product item's AppLink app URL for iPad. */
|
||||||
FOUNDATION_EXPORT NSString *const FBSDKAppEventParameterProductAppLinkIPadUrl;
|
FOUNDATION_EXPORT FBSDKAppEventParameterProduct FBSDKAppEventParameterProductAppLinkIPadUrl;
|
||||||
|
|
||||||
/** Parameter key used to specify the product item's AppLink app ID for iPad App Store. */
|
/** Parameter key used to specify the product item's AppLink app ID for iPad App Store. */
|
||||||
FOUNDATION_EXPORT NSString *const FBSDKAppEventParameterProductAppLinkIPadAppStoreID;
|
FOUNDATION_EXPORT FBSDKAppEventParameterProduct FBSDKAppEventParameterProductAppLinkIPadAppStoreID;
|
||||||
|
|
||||||
/** Parameter key used to specify the product item's AppLink app name for iPad. */
|
/** Parameter key used to specify the product item's AppLink app name for iPad. */
|
||||||
FOUNDATION_EXPORT NSString *const FBSDKAppEventParameterProductAppLinkIPadAppName;
|
FOUNDATION_EXPORT FBSDKAppEventParameterProduct FBSDKAppEventParameterProductAppLinkIPadAppName;
|
||||||
|
|
||||||
/** Parameter key used to specify the product item's AppLink app URL for Android. */
|
/** Parameter key used to specify the product item's AppLink app URL for Android. */
|
||||||
FOUNDATION_EXPORT NSString *const FBSDKAppEventParameterProductAppLinkAndroidUrl;
|
FOUNDATION_EXPORT FBSDKAppEventParameterProduct FBSDKAppEventParameterProductAppLinkAndroidUrl;
|
||||||
|
|
||||||
/** Parameter key used to specify the product item's AppLink fully-qualified package name for intent generation. */
|
/** Parameter key used to specify the product item's AppLink fully-qualified package name for intent generation. */
|
||||||
FOUNDATION_EXPORT NSString *const FBSDKAppEventParameterProductAppLinkAndroidPackage;
|
FOUNDATION_EXPORT FBSDKAppEventParameterProduct FBSDKAppEventParameterProductAppLinkAndroidPackage;
|
||||||
|
|
||||||
/** Parameter key used to specify the product item's AppLink app name for Android. */
|
/** Parameter key used to specify the product item's AppLink app name for Android. */
|
||||||
FOUNDATION_EXPORT NSString *const FBSDKAppEventParameterProductAppLinkAndroidAppName;
|
FOUNDATION_EXPORT FBSDKAppEventParameterProduct FBSDKAppEventParameterProductAppLinkAndroidAppName;
|
||||||
|
|
||||||
/** Parameter key used to specify the product item's AppLink app URL for Windows Phone. */
|
/** Parameter key used to specify the product item's AppLink app URL for Windows Phone. */
|
||||||
FOUNDATION_EXPORT NSString *const FBSDKAppEventParameterProductAppLinkWindowsPhoneUrl;
|
FOUNDATION_EXPORT FBSDKAppEventParameterProduct FBSDKAppEventParameterProductAppLinkWindowsPhoneUrl;
|
||||||
|
|
||||||
/** Parameter key used to specify the product item's AppLink app ID, as a GUID, for App Store. */
|
/** Parameter key used to specify the product item's AppLink app ID, as a GUID, for App Store. */
|
||||||
FOUNDATION_EXPORT NSString *const FBSDKAppEventParameterProductAppLinkWindowsPhoneAppID;
|
FOUNDATION_EXPORT FBSDKAppEventParameterProduct FBSDKAppEventParameterProductAppLinkWindowsPhoneAppID;
|
||||||
|
|
||||||
/** Parameter key used to specify the product item's AppLink app name for Windows Phone. */
|
/** Parameter key used to specify the product item's AppLink app name for Windows Phone. */
|
||||||
FOUNDATION_EXPORT NSString *const FBSDKAppEventParameterProductAppLinkWindowsPhoneAppName;
|
FOUNDATION_EXPORT FBSDKAppEventParameterProduct FBSDKAppEventParameterProductAppLinkWindowsPhoneAppName;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@methodgroup Predefined values to assign to event parameters that accompany events logged through the `logEvent` family
|
@methodgroup Predefined values to assign to event parameters that accompany events logged through the `logEvent` family
|
||||||
of methods on `FBSDKAppEvents`. Common event parameters are provided in the `FBSDKAppEventParameterName*` constants.
|
of methods on `FBSDKAppEvents`. Common event parameters are provided in the `FBSDKAppEventParameterName*` constants.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/// typedef for FBSDKAppEventParameterValue
|
||||||
|
typedef NSString *const FBSDKAppEventParameterValue NS_TYPED_EXTENSIBLE_ENUM NS_SWIFT_NAME(AppEvents.ParameterValue);
|
||||||
|
|
||||||
/** Yes-valued parameter value to be used with parameter keys that need a Yes/No value */
|
/** Yes-valued parameter value to be used with parameter keys that need a Yes/No value */
|
||||||
FOUNDATION_EXPORT NSString *const FBSDKAppEventParameterValueYes;
|
FOUNDATION_EXPORT FBSDKAppEventParameterValue FBSDKAppEventParameterValueYes;
|
||||||
|
|
||||||
/** No-valued parameter value to be used with parameter keys that need a Yes/No value */
|
/** No-valued parameter value to be used with parameter keys that need a Yes/No value */
|
||||||
FOUNDATION_EXPORT NSString *const FBSDKAppEventParameterValueNo;
|
FOUNDATION_EXPORT FBSDKAppEventParameterValue FBSDKAppEventParameterValueNo;
|
||||||
|
|
||||||
/** Parameter key used to specify the type of ad in an FBSDKAppEventNameAdImpression
|
/** Parameter key used to specify the type of ad in an FBSDKAppEventNameAdImpression
|
||||||
* or FBSDKAppEventNameAdClick event.
|
* or FBSDKAppEventNameAdClick event.
|
||||||
* E.g. "banner", "interstitial", "rewarded_video", "native" */
|
* E.g. "banner", "interstitial", "rewarded_video", "native" */
|
||||||
FOUNDATION_EXPORT NSString *const FBSDKAppEventParameterNameAdType;
|
FOUNDATION_EXPORT FBSDKAppEventParameterName FBSDKAppEventParameterNameAdType;
|
||||||
|
|
||||||
/** Parameter key used to specify the unique ID for all events within a subscription
|
/** Parameter key used to specify the unique ID for all events within a subscription
|
||||||
* in an FBSDKAppEventNameSubscribe or FBSDKAppEventNameStartTrial event. */
|
* in an FBSDKAppEventNameSubscribe or FBSDKAppEventNameStartTrial event. */
|
||||||
FOUNDATION_EXPORT NSString *const FBSDKAppEventParameterNameOrderID;
|
FOUNDATION_EXPORT FBSDKAppEventParameterName FBSDKAppEventParameterNameOrderID;
|
||||||
|
|
||||||
|
/*
|
||||||
|
@methodgroup Predefined values to assign to user data store
|
||||||
|
*/
|
||||||
|
|
||||||
|
/// typedef for FBSDKAppEventUserDataType
|
||||||
|
typedef NSString *const FBSDKAppEventUserDataType NS_TYPED_EXTENSIBLE_ENUM NS_SWIFT_NAME(AppEvents.UserDataType);
|
||||||
|
|
||||||
|
/** Parameter key used to specify user's email. */
|
||||||
|
FOUNDATION_EXPORT FBSDKAppEventUserDataType FBSDKAppEventEmail;
|
||||||
|
|
||||||
|
/** Parameter key used to specify user's first name. */
|
||||||
|
FOUNDATION_EXPORT FBSDKAppEventUserDataType FBSDKAppEventFirstName;
|
||||||
|
|
||||||
|
/** Parameter key used to specify user's last name. */
|
||||||
|
FOUNDATION_EXPORT FBSDKAppEventUserDataType FBSDKAppEventLastName;
|
||||||
|
|
||||||
|
/** Parameter key used to specify user's phone. */
|
||||||
|
FOUNDATION_EXPORT FBSDKAppEventUserDataType FBSDKAppEventPhone;
|
||||||
|
|
||||||
|
/** Parameter key used to specify user's date of birth. */
|
||||||
|
FOUNDATION_EXPORT FBSDKAppEventUserDataType FBSDKAppEventDateOfBirth;
|
||||||
|
|
||||||
|
/** Parameter key used to specify user's gender. */
|
||||||
|
FOUNDATION_EXPORT FBSDKAppEventUserDataType FBSDKAppEventGender;
|
||||||
|
|
||||||
|
/** Parameter key used to specify user's city. */
|
||||||
|
FOUNDATION_EXPORT FBSDKAppEventUserDataType FBSDKAppEventCity;
|
||||||
|
|
||||||
|
/** Parameter key used to specify user's state. */
|
||||||
|
FOUNDATION_EXPORT FBSDKAppEventUserDataType FBSDKAppEventState;
|
||||||
|
|
||||||
|
/** Parameter key used to specify user's zip. */
|
||||||
|
FOUNDATION_EXPORT FBSDKAppEventUserDataType FBSDKAppEventZip;
|
||||||
|
|
||||||
|
/** Parameter key used to specify user's country. */
|
||||||
|
FOUNDATION_EXPORT FBSDKAppEventUserDataType FBSDKAppEventCountry;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
||||||
@ -351,8 +413,45 @@ FOUNDATION_EXPORT NSString *const FBSDKAppEventParameterNameOrderID;
|
|||||||
+ The length of each parameter value can be no more than on the order of 100 characters.
|
+ The length of each parameter value can be no more than on the order of 100 characters.
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
NS_SWIFT_NAME(AppEvents)
|
||||||
@interface FBSDKAppEvents : NSObject
|
@interface FBSDKAppEvents : NSObject
|
||||||
|
|
||||||
|
- (instancetype)init NS_UNAVAILABLE;
|
||||||
|
+ (instancetype)new NS_UNAVAILABLE;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Control over event batching/flushing
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
|
||||||
|
The current event flushing behavior specifying when events are sent back to Facebook servers.
|
||||||
|
*/
|
||||||
|
@property (class, nonatomic, assign) FBSDKAppEventsFlushBehavior flushBehavior;
|
||||||
|
|
||||||
|
/**
|
||||||
|
Set the 'override' App ID for App Event logging.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
In some cases, apps want to use one Facebook App ID for login and social presence and another
|
||||||
|
for App Event logging. (An example is if multiple apps from the same company share an app ID for login, but
|
||||||
|
want distinct logging.) By default, this value is `nil`, and defers to the `FBSDKAppEventsOverrideAppIDBundleKey`
|
||||||
|
plist value. If that's not set, it defaults to `[FBSDKSettings appID]`.
|
||||||
|
|
||||||
|
This should be set before any other calls are made to `FBSDKAppEvents`. Thus, you should set it in your application
|
||||||
|
delegate's `application:didFinishLaunchingWithOptions:` delegate.
|
||||||
|
*/
|
||||||
|
@property (class, nonatomic, copy, nullable) NSString *loggingOverrideAppID;
|
||||||
|
|
||||||
|
/*
|
||||||
|
The custom user ID to associate with all app events.
|
||||||
|
|
||||||
|
The userID is persisted until it is cleared by passing nil.
|
||||||
|
*/
|
||||||
|
@property (class, nonatomic, copy, nullable) NSString *userID;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Basic event logging
|
* Basic event logging
|
||||||
*/
|
*/
|
||||||
@ -365,7 +464,7 @@ FOUNDATION_EXPORT NSString *const FBSDKAppEventParameterNameOrderID;
|
|||||||
are given in the `FBSDKAppEvents` documentation.
|
are given in the `FBSDKAppEvents` documentation.
|
||||||
|
|
||||||
*/
|
*/
|
||||||
+ (void)logEvent:(NSString *)eventName;
|
+ (void)logEvent:(FBSDKAppEventName)eventName;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
||||||
@ -377,7 +476,7 @@ FOUNDATION_EXPORT NSString *const FBSDKAppEventParameterNameOrderID;
|
|||||||
@param valueToSum Amount to be aggregated into all events of this eventName, and App Insights will report
|
@param valueToSum Amount to be aggregated into all events of this eventName, and App Insights will report
|
||||||
the cumulative and average value of this amount.
|
the cumulative and average value of this amount.
|
||||||
*/
|
*/
|
||||||
+ (void)logEvent:(NSString *)eventName
|
+ (void)logEvent:(FBSDKAppEventName)eventName
|
||||||
valueToSum:(double)valueToSum;
|
valueToSum:(double)valueToSum;
|
||||||
|
|
||||||
|
|
||||||
@ -394,8 +493,8 @@ FOUNDATION_EXPORT NSString *const FBSDKAppEventParameterNameOrderID;
|
|||||||
parameters and name construction are given in the `FBSDKAppEvents` documentation. Commonly used parameter names
|
parameters and name construction are given in the `FBSDKAppEvents` documentation. Commonly used parameter names
|
||||||
are provided in `FBSDKAppEventParameterName*` constants.
|
are provided in `FBSDKAppEventParameterName*` constants.
|
||||||
*/
|
*/
|
||||||
+ (void)logEvent:(NSString *)eventName
|
+ (void)logEvent:(FBSDKAppEventName)eventName
|
||||||
parameters:(NSDictionary *)parameters;
|
parameters:(NSDictionary<FBSDKAppEventParameterName, id> *)parameters;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
||||||
@ -414,9 +513,9 @@ FOUNDATION_EXPORT NSString *const FBSDKAppEventParameterNameOrderID;
|
|||||||
are provided in `FBSDKAppEventParameterName*` constants.
|
are provided in `FBSDKAppEventParameterName*` constants.
|
||||||
|
|
||||||
*/
|
*/
|
||||||
+ (void)logEvent:(NSString *)eventName
|
+ (void)logEvent:(FBSDKAppEventName)eventName
|
||||||
valueToSum:(double)valueToSum
|
valueToSum:(double)valueToSum
|
||||||
parameters:(NSDictionary *)parameters;
|
parameters:(NSDictionary<FBSDKAppEventParameterName, id> *)parameters;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -439,10 +538,10 @@ FOUNDATION_EXPORT NSString *const FBSDKAppEventParameterNameOrderID;
|
|||||||
|
|
||||||
@param accessToken The optional access token to log the event as.
|
@param accessToken The optional access token to log the event as.
|
||||||
*/
|
*/
|
||||||
+ (void)logEvent:(NSString *)eventName
|
+ (void)logEvent:(FBSDKAppEventName)eventName
|
||||||
valueToSum:(NSNumber *)valueToSum
|
valueToSum:(nullable NSNumber *)valueToSum
|
||||||
parameters:(NSDictionary *)parameters
|
parameters:(NSDictionary<FBSDKAppEventParameterName, id> *)parameters
|
||||||
accessToken:(FBSDKAccessToken *)accessToken;
|
accessToken:(nullable FBSDKAccessToken *)accessToken;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Purchase logging
|
* Purchase logging
|
||||||
@ -489,7 +588,7 @@ FOUNDATION_EXPORT NSString *const FBSDKAppEventParameterNameOrderID;
|
|||||||
*/
|
*/
|
||||||
+ (void)logPurchase:(double)purchaseAmount
|
+ (void)logPurchase:(double)purchaseAmount
|
||||||
currency:(NSString *)currency
|
currency:(NSString *)currency
|
||||||
parameters:(NSDictionary *)parameters;
|
parameters:(NSDictionary<NSString *, id> *)parameters;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
||||||
@ -516,8 +615,8 @@ FOUNDATION_EXPORT NSString *const FBSDKAppEventParameterNameOrderID;
|
|||||||
*/
|
*/
|
||||||
+ (void)logPurchase:(double)purchaseAmount
|
+ (void)logPurchase:(double)purchaseAmount
|
||||||
currency:(NSString *)currency
|
currency:(NSString *)currency
|
||||||
parameters:(NSDictionary *)parameters
|
parameters:(NSDictionary<NSString *, id> *)parameters
|
||||||
accessToken:(FBSDKAccessToken *)accessToken;
|
accessToken:(nullable FBSDKAccessToken *)accessToken;
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -574,10 +673,10 @@ FOUNDATION_EXPORT NSString *const FBSDKAppEventParameterNameOrderID;
|
|||||||
title:(NSString *)title
|
title:(NSString *)title
|
||||||
priceAmount:(double)priceAmount
|
priceAmount:(double)priceAmount
|
||||||
currency:(NSString *)currency
|
currency:(NSString *)currency
|
||||||
gtin:(NSString *)gtin
|
gtin:(nullable NSString *)gtin
|
||||||
mpn:(NSString *)mpn
|
mpn:(nullable NSString *)mpn
|
||||||
brand:(NSString *)brand
|
brand:(nullable NSString *)brand
|
||||||
parameters:(NSDictionary *)parameters;
|
parameters:(nullable NSDictionary<NSString *, id> *)parameters;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
||||||
@ -624,52 +723,8 @@ FOUNDATION_EXPORT NSString *const FBSDKAppEventParameterNameOrderID;
|
|||||||
|
|
||||||
@param deviceTokenString Device token string.
|
@param deviceTokenString Device token string.
|
||||||
*/
|
*/
|
||||||
+ (void)setPushNotificationsDeviceTokenString:(NSString *)deviceTokenString;
|
+ (void)setPushNotificationsDeviceTokenString:(NSString *)deviceTokenString
|
||||||
|
NS_SWIFT_NAME(setPushNotificationsDeviceToken(_:));
|
||||||
/*
|
|
||||||
* Control over event batching/flushing
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
|
|
||||||
Get the current event flushing behavior specifying when events are sent back to Facebook servers.
|
|
||||||
*/
|
|
||||||
+ (FBSDKAppEventsFlushBehavior)flushBehavior;
|
|
||||||
|
|
||||||
/**
|
|
||||||
|
|
||||||
Set the current event flushing behavior specifying when events are sent back to Facebook servers.
|
|
||||||
|
|
||||||
@param flushBehavior The desired `FBSDKAppEventsFlushBehavior` to be used.
|
|
||||||
*/
|
|
||||||
+ (void)setFlushBehavior:(FBSDKAppEventsFlushBehavior)flushBehavior;
|
|
||||||
|
|
||||||
/**
|
|
||||||
Set the 'override' App ID for App Event logging.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
In some cases, apps want to use one Facebook App ID for login and social presence and another
|
|
||||||
for App Event logging. (An example is if multiple apps from the same company share an app ID for login, but
|
|
||||||
want distinct logging.) By default, this value is `nil`, and defers to the `FBSDKAppEventsOverrideAppIDBundleKey`
|
|
||||||
plist value. If that's not set, it defaults to `[FBSDKSettings appID]`.
|
|
||||||
|
|
||||||
This should be set before any other calls are made to `FBSDKAppEvents`. Thus, you should set it in your application
|
|
||||||
delegate's `application:didFinishLaunchingWithOptions:` delegate.
|
|
||||||
|
|
||||||
@param appID The Facebook App ID to be used for App Event logging.
|
|
||||||
*/
|
|
||||||
+ (void)setLoggingOverrideAppID:(NSString *)appID;
|
|
||||||
|
|
||||||
/**
|
|
||||||
Get the 'override' App ID for App Event logging.
|
|
||||||
|
|
||||||
|
|
||||||
@see setLoggingOverrideAppID:
|
|
||||||
|
|
||||||
*/
|
|
||||||
+ (NSString *)loggingOverrideAppID;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Explicitly kick off flushing of events to Facebook. This is an asynchronous method, but it does initiate an immediate
|
Explicitly kick off flushing of events to Facebook. This is an asynchronous method, but it does initiate an immediate
|
||||||
@ -682,11 +737,6 @@ 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,
|
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.
|
and then use the resultant Custom Audience to target ads.
|
||||||
|
|
||||||
@param accessToken The access token to use to establish the user's identity for users logged into Facebook through this app.
|
|
||||||
If `nil`, then the `[FBSDKAccessToken currentAccessToken]` is used.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
The JSON in the request's response will include an "custom_audience_third_party_id" key/value pair, with the value being the ID retrieved.
|
The JSON in the request's response will include an "custom_audience_third_party_id" key/value pair, with the value being the ID retrieved.
|
||||||
This ID is an encrypted encoding of the Facebook user's ID and the invoking Facebook app ID.
|
This ID is an encrypted encoding of the Facebook user's ID and the invoking Facebook app ID.
|
||||||
Multiple calls with the same user will return different IDs, thus these IDs cannot be used to correlate behavior
|
Multiple calls with the same user will return different IDs, thus these IDs cannot be used to correlate behavior
|
||||||
@ -699,49 +749,17 @@ FOUNDATION_EXPORT NSString *const FBSDKAppEventParameterNameOrderID;
|
|||||||
|
|
||||||
This method returns `nil` if either the user has opted-out (via iOS) from Ad Tracking, the app itself has limited event usage
|
This method returns `nil` if either the user has opted-out (via iOS) from Ad Tracking, the app itself has limited event usage
|
||||||
via the `[FBSDKSettings limitEventAndDataUsage]` flag, or a specific Facebook user cannot be identified.
|
via the `[FBSDKSettings limitEventAndDataUsage]` flag, or a specific Facebook user cannot be identified.
|
||||||
*/
|
|
||||||
+ (FBSDKGraphRequest *)requestForCustomAudienceThirdPartyIDWithAccessToken:(FBSDKAccessToken *)accessToken;
|
|
||||||
|
|
||||||
/*
|
@param accessToken The access token to use to establish the user's identity for users logged into Facebook through this app.
|
||||||
Sets a custom user ID to associate with all app events.
|
If `nil`, then the `[FBSDKAccessToken currentAccessToken]` is used.
|
||||||
|
|
||||||
The userID is persisted until it is cleared by passing nil.
|
|
||||||
*/
|
*/
|
||||||
+ (void)setUserID:(NSString *)userID;
|
+ (nullable FBSDKGraphRequest *)requestForCustomAudienceThirdPartyIDWithAccessToken:(nullable FBSDKAccessToken *)accessToken;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Clears the custom user ID to associate with all app events.
|
Clears the custom user ID to associate with all app events.
|
||||||
*/
|
*/
|
||||||
+ (void)clearUserID;
|
+ (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
|
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.
|
and used to match Facebook user from this instance of an application.
|
||||||
@ -759,26 +777,45 @@ FOUNDATION_EXPORT NSString *const FBSDKAppEventParameterNameOrderID;
|
|||||||
@param zip user's zip
|
@param zip user's zip
|
||||||
@param country user's country
|
@param country user's country
|
||||||
*/
|
*/
|
||||||
+ (void)setUserEmail:(NSString *)email
|
+ (void)setUserEmail:(nullable NSString *)email
|
||||||
firstName:(NSString *)firstName
|
firstName:(nullable NSString *)firstName
|
||||||
lastName:(NSString *)lastName
|
lastName:(nullable NSString *)lastName
|
||||||
phone:(NSString *)phone
|
phone:(nullable NSString *)phone
|
||||||
dateOfBirth:(NSString *)dateOfBirth
|
dateOfBirth:(nullable NSString *)dateOfBirth
|
||||||
gender:(NSString *)gender
|
gender:(nullable NSString *)gender
|
||||||
city:(NSString *)city
|
city:(nullable NSString *)city
|
||||||
state:(NSString *)state
|
state:(nullable NSString *)state
|
||||||
zip:(NSString *)zip
|
zip:(nullable NSString *)zip
|
||||||
country:(NSString *)country;
|
country:(nullable NSString *)country
|
||||||
|
NS_SWIFT_NAME(setUser(email:firstName:lastName:phone:dateOfBirth:gender:city:state:zip:country:));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Returns the set user data else nil
|
Returns the set user data else nil
|
||||||
*/
|
*/
|
||||||
+ (NSString *)getUserData;
|
+ (nullable NSString *)getUserData;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Clears the current user data
|
Clears the current user data
|
||||||
*/
|
*/
|
||||||
+ (void)clearUserData;
|
+ (void)clearUserData;
|
||||||
|
|
||||||
|
/*
|
||||||
|
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 data data
|
||||||
|
@param type data type, e.g. FBSDKAppEventEmail, FBSDKAppEventPhone
|
||||||
|
*/
|
||||||
|
+ (void)setUserData:(nullable NSString *)data
|
||||||
|
forType:(FBSDKAppEventUserDataType)type;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Clears the current user data of certain type
|
||||||
|
*/
|
||||||
|
+ (void)clearUserDataForType:(FBSDKAppEventUserDataType)type;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Sends a request to update the properties for the current user, set by `setUserID:`
|
Sends a request to update the properties for the current user, set by `setUserID:`
|
||||||
|
|
||||||
@ -786,7 +823,7 @@ FOUNDATION_EXPORT NSString *const FBSDKAppEventParameterNameOrderID;
|
|||||||
@param properties the custom user properties
|
@param properties the custom user properties
|
||||||
@param handler the optional completion handler
|
@param handler the optional completion handler
|
||||||
*/
|
*/
|
||||||
+ (void)updateUserProperties:(NSDictionary *)properties handler:(FBSDKGraphRequestHandler)handler;
|
+ (void)updateUserProperties:(NSDictionary<NSString *, id> *)properties handler:(nullable FBSDKGraphRequestBlock)handler;
|
||||||
|
|
||||||
#if !TARGET_OS_TV
|
#if !TARGET_OS_TV
|
||||||
/*
|
/*
|
||||||
@ -820,3 +857,5 @@ FOUNDATION_EXPORT NSString *const FBSDKAppEventParameterNameOrderID;
|
|||||||
+ (void)sendEventBindingsToUnity;
|
+ (void)sendEventBindingsToUnity;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_END
|
||||||
@ -18,7 +18,7 @@
|
|||||||
|
|
||||||
#import "FBSDKAppEvents.h"
|
#import "FBSDKAppEvents.h"
|
||||||
#import "FBSDKAppEvents+Internal.h"
|
#import "FBSDKAppEvents+Internal.h"
|
||||||
|
#import "FBSDKApplicationDelegate+Internal.h"
|
||||||
#import <objc/runtime.h>
|
#import <objc/runtime.h>
|
||||||
|
|
||||||
#import <UIKit/UIApplication.h>
|
#import <UIKit/UIApplication.h>
|
||||||
@ -30,9 +30,11 @@
|
|||||||
#import "FBSDKConstants.h"
|
#import "FBSDKConstants.h"
|
||||||
#import "FBSDKDynamicFrameworkLoader.h"
|
#import "FBSDKDynamicFrameworkLoader.h"
|
||||||
#import "FBSDKError.h"
|
#import "FBSDKError.h"
|
||||||
|
#import "FBSDKFeatureManager.h"
|
||||||
#import "FBSDKGraphRequest+Internal.h"
|
#import "FBSDKGraphRequest+Internal.h"
|
||||||
#import "FBSDKInternalUtility.h"
|
#import "FBSDKInternalUtility.h"
|
||||||
#import "FBSDKLogger.h"
|
#import "FBSDKLogger.h"
|
||||||
|
#import "FBSDKRestrictiveDataFilterManager.h"
|
||||||
#import "FBSDKPaymentObserver.h"
|
#import "FBSDKPaymentObserver.h"
|
||||||
#import "FBSDKServerConfiguration.h"
|
#import "FBSDKServerConfiguration.h"
|
||||||
#import "FBSDKServerConfigurationManager.h"
|
#import "FBSDKServerConfigurationManager.h"
|
||||||
@ -51,162 +53,178 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
// General purpose
|
// General purpose
|
||||||
NSString *const FBSDKAppEventNameCompletedRegistration = @"fb_mobile_complete_registration";
|
FBSDKAppEventName FBSDKAppEventNameCompletedRegistration = @"fb_mobile_complete_registration";
|
||||||
NSString *const FBSDKAppEventNameViewedContent = @"fb_mobile_content_view";
|
FBSDKAppEventName FBSDKAppEventNameViewedContent = @"fb_mobile_content_view";
|
||||||
NSString *const FBSDKAppEventNameSearched = @"fb_mobile_search";
|
FBSDKAppEventName FBSDKAppEventNameSearched = @"fb_mobile_search";
|
||||||
NSString *const FBSDKAppEventNameRated = @"fb_mobile_rate";
|
FBSDKAppEventName FBSDKAppEventNameRated = @"fb_mobile_rate";
|
||||||
NSString *const FBSDKAppEventNameCompletedTutorial = @"fb_mobile_tutorial_completion";
|
FBSDKAppEventName FBSDKAppEventNameCompletedTutorial = @"fb_mobile_tutorial_completion";
|
||||||
NSString *const FBSDKAppEventNameContact = @"Contact";
|
FBSDKAppEventName FBSDKAppEventNameContact = @"Contact";
|
||||||
NSString *const FBSDKAppEventNameCustomizeProduct = @"CustomizeProduct";
|
FBSDKAppEventName FBSDKAppEventNameCustomizeProduct = @"CustomizeProduct";
|
||||||
NSString *const FBSDKAppEventNameDonate = @"Donate";
|
FBSDKAppEventName FBSDKAppEventNameDonate = @"Donate";
|
||||||
NSString *const FBSDKAppEventNameFindLocation = @"FindLocation";
|
FBSDKAppEventName FBSDKAppEventNameFindLocation = @"FindLocation";
|
||||||
NSString *const FBSDKAppEventNameSchedule = @"Schedule";
|
FBSDKAppEventName FBSDKAppEventNameSchedule = @"Schedule";
|
||||||
NSString *const FBSDKAppEventNameStartTrial = @"StartTrial";
|
FBSDKAppEventName FBSDKAppEventNameStartTrial = @"StartTrial";
|
||||||
NSString *const FBSDKAppEventNameSubmitApplication = @"SubmitApplication";
|
FBSDKAppEventName FBSDKAppEventNameSubmitApplication = @"SubmitApplication";
|
||||||
NSString *const FBSDKAppEventNameSubscribe = @"Subscribe";
|
FBSDKAppEventName FBSDKAppEventNameSubscribe = @"Subscribe";
|
||||||
NSString *const FBSDKAppEventNameAdImpression = @"AdImpression";
|
FBSDKAppEventName FBSDKAppEventNameSubscriptionHeartbeat = @"SubscriptionHeartbeat";
|
||||||
NSString *const FBSDKAppEventNameAdClick = @"AdClick";
|
FBSDKAppEventName FBSDKAppEventNameAdImpression = @"AdImpression";
|
||||||
|
FBSDKAppEventName FBSDKAppEventNameAdClick = @"AdClick";
|
||||||
|
|
||||||
// Ecommerce related
|
// Ecommerce related
|
||||||
NSString *const FBSDKAppEventNameAddedToCart = @"fb_mobile_add_to_cart";
|
FBSDKAppEventName FBSDKAppEventNameAddedToCart = @"fb_mobile_add_to_cart";
|
||||||
NSString *const FBSDKAppEventNameAddedToWishlist = @"fb_mobile_add_to_wishlist";
|
FBSDKAppEventName FBSDKAppEventNameAddedToWishlist = @"fb_mobile_add_to_wishlist";
|
||||||
NSString *const FBSDKAppEventNameInitiatedCheckout = @"fb_mobile_initiated_checkout";
|
FBSDKAppEventName FBSDKAppEventNameInitiatedCheckout = @"fb_mobile_initiated_checkout";
|
||||||
NSString *const FBSDKAppEventNameAddedPaymentInfo = @"fb_mobile_add_payment_info";
|
FBSDKAppEventName FBSDKAppEventNameAddedPaymentInfo = @"fb_mobile_add_payment_info";
|
||||||
NSString *const FBSDKAppEventNameProductCatalogUpdate = @"fb_mobile_catalog_update";
|
FBSDKAppEventName FBSDKAppEventNameProductCatalogUpdate = @"fb_mobile_catalog_update";
|
||||||
|
FBSDKAppEventName FBSDKAppEventNamePurchased = @"fb_mobile_purchase";
|
||||||
|
|
||||||
// Gaming related
|
// Gaming related
|
||||||
NSString *const FBSDKAppEventNameAchievedLevel = @"fb_mobile_level_achieved";
|
FBSDKAppEventName FBSDKAppEventNameAchievedLevel = @"fb_mobile_level_achieved";
|
||||||
NSString *const FBSDKAppEventNameUnlockedAchievement = @"fb_mobile_achievement_unlocked";
|
FBSDKAppEventName FBSDKAppEventNameUnlockedAchievement = @"fb_mobile_achievement_unlocked";
|
||||||
NSString *const FBSDKAppEventNameSpentCredits = @"fb_mobile_spent_credits";
|
FBSDKAppEventName FBSDKAppEventNameSpentCredits = @"fb_mobile_spent_credits";
|
||||||
|
|
||||||
//
|
//
|
||||||
// Public event parameter names
|
// Public event parameter names
|
||||||
//
|
//
|
||||||
|
|
||||||
NSString *const FBSDKAppEventParameterNameCurrency = @"fb_currency";
|
FBSDKAppEventParameterName FBSDKAppEventParameterNameCurrency = @"fb_currency";
|
||||||
NSString *const FBSDKAppEventParameterNameRegistrationMethod = @"fb_registration_method";
|
FBSDKAppEventParameterName FBSDKAppEventParameterNameRegistrationMethod = @"fb_registration_method";
|
||||||
NSString *const FBSDKAppEventParameterNameContentType = @"fb_content_type";
|
FBSDKAppEventParameterName FBSDKAppEventParameterNameContentType = @"fb_content_type";
|
||||||
NSString *const FBSDKAppEventParameterNameContent = @"fb_content";
|
FBSDKAppEventParameterName FBSDKAppEventParameterNameContent = @"fb_content";
|
||||||
NSString *const FBSDKAppEventParameterNameContentID = @"fb_content_id";
|
FBSDKAppEventParameterName FBSDKAppEventParameterNameContentID = @"fb_content_id";
|
||||||
NSString *const FBSDKAppEventParameterNameSearchString = @"fb_search_string";
|
FBSDKAppEventParameterName FBSDKAppEventParameterNameSearchString = @"fb_search_string";
|
||||||
NSString *const FBSDKAppEventParameterNameSuccess = @"fb_success";
|
FBSDKAppEventParameterName FBSDKAppEventParameterNameSuccess = @"fb_success";
|
||||||
NSString *const FBSDKAppEventParameterNameMaxRatingValue = @"fb_max_rating_value";
|
FBSDKAppEventParameterName FBSDKAppEventParameterNameMaxRatingValue = @"fb_max_rating_value";
|
||||||
NSString *const FBSDKAppEventParameterNamePaymentInfoAvailable = @"fb_payment_info_available";
|
FBSDKAppEventParameterName FBSDKAppEventParameterNamePaymentInfoAvailable = @"fb_payment_info_available";
|
||||||
NSString *const FBSDKAppEventParameterNameNumItems = @"fb_num_items";
|
FBSDKAppEventParameterName FBSDKAppEventParameterNameNumItems = @"fb_num_items";
|
||||||
NSString *const FBSDKAppEventParameterNameLevel = @"fb_level";
|
FBSDKAppEventParameterName FBSDKAppEventParameterNameLevel = @"fb_level";
|
||||||
NSString *const FBSDKAppEventParameterNameDescription = @"fb_description";
|
FBSDKAppEventParameterName FBSDKAppEventParameterNameDescription = @"fb_description";
|
||||||
NSString *const FBSDKAppEventParameterLaunchSource = @"fb_mobile_launch_source";
|
FBSDKAppEventParameterName FBSDKAppEventParameterLaunchSource = @"fb_mobile_launch_source";
|
||||||
NSString *const FBSDKAppEventParameterNameAdType = @"ad_type";
|
FBSDKAppEventParameterName FBSDKAppEventParameterNameAdType = @"ad_type";
|
||||||
NSString *const FBSDKAppEventParameterNameOrderID = @"fb_order_id";
|
FBSDKAppEventParameterName FBSDKAppEventParameterNameOrderID = @"fb_order_id";
|
||||||
|
|
||||||
//
|
//
|
||||||
// Public event parameter names for DPA Catalog
|
// Public event parameter names for DPA Catalog
|
||||||
//
|
//
|
||||||
|
|
||||||
NSString *const FBSDKAppEventParameterProductCustomLabel0 = @"fb_product_custom_label_0";
|
FBSDKAppEventParameterProduct FBSDKAppEventParameterProductCustomLabel0 = @"fb_product_custom_label_0";
|
||||||
NSString *const FBSDKAppEventParameterProductCustomLabel1 = @"fb_product_custom_label_1";
|
FBSDKAppEventParameterProduct FBSDKAppEventParameterProductCustomLabel1 = @"fb_product_custom_label_1";
|
||||||
NSString *const FBSDKAppEventParameterProductCustomLabel2 = @"fb_product_custom_label_2";
|
FBSDKAppEventParameterProduct FBSDKAppEventParameterProductCustomLabel2 = @"fb_product_custom_label_2";
|
||||||
NSString *const FBSDKAppEventParameterProductCustomLabel3 = @"fb_product_custom_label_3";
|
FBSDKAppEventParameterProduct FBSDKAppEventParameterProductCustomLabel3 = @"fb_product_custom_label_3";
|
||||||
NSString *const FBSDKAppEventParameterProductCustomLabel4 = @"fb_product_custom_label_4";
|
FBSDKAppEventParameterProduct FBSDKAppEventParameterProductCustomLabel4 = @"fb_product_custom_label_4";
|
||||||
NSString *const FBSDKAppEventParameterProductAppLinkIOSUrl = @"fb_product_applink_ios_url";
|
FBSDKAppEventParameterProduct FBSDKAppEventParameterProductCategory = @"fb_product_category";
|
||||||
NSString *const FBSDKAppEventParameterProductAppLinkIOSAppStoreID = @"fb_product_applink_ios_app_store_id";
|
FBSDKAppEventParameterProduct FBSDKAppEventParameterProductAppLinkIOSUrl = @"fb_product_applink_ios_url";
|
||||||
NSString *const FBSDKAppEventParameterProductAppLinkIOSAppName = @"fb_product_applink_ios_app_name";
|
FBSDKAppEventParameterProduct FBSDKAppEventParameterProductAppLinkIOSAppStoreID = @"fb_product_applink_ios_app_store_id";
|
||||||
NSString *const FBSDKAppEventParameterProductAppLinkIPhoneUrl = @"fb_product_applink_iphone_url";
|
FBSDKAppEventParameterProduct FBSDKAppEventParameterProductAppLinkIOSAppName = @"fb_product_applink_ios_app_name";
|
||||||
NSString *const FBSDKAppEventParameterProductAppLinkIPhoneAppStoreID = @"fb_product_applink_iphone_app_store_id";
|
FBSDKAppEventParameterProduct FBSDKAppEventParameterProductAppLinkIPhoneUrl = @"fb_product_applink_iphone_url";
|
||||||
NSString *const FBSDKAppEventParameterProductAppLinkIPhoneAppName = @"fb_product_applink_iphone_app_name";
|
FBSDKAppEventParameterProduct FBSDKAppEventParameterProductAppLinkIPhoneAppStoreID = @"fb_product_applink_iphone_app_store_id";
|
||||||
NSString *const FBSDKAppEventParameterProductAppLinkIPadUrl = @"fb_product_applink_ipad_url";
|
FBSDKAppEventParameterProduct FBSDKAppEventParameterProductAppLinkIPhoneAppName = @"fb_product_applink_iphone_app_name";
|
||||||
NSString *const FBSDKAppEventParameterProductAppLinkIPadAppStoreID = @"fb_product_applink_ipad_app_store_id";
|
FBSDKAppEventParameterProduct FBSDKAppEventParameterProductAppLinkIPadUrl = @"fb_product_applink_ipad_url";
|
||||||
NSString *const FBSDKAppEventParameterProductAppLinkIPadAppName = @"fb_product_applink_ipad_app_name";
|
FBSDKAppEventParameterProduct FBSDKAppEventParameterProductAppLinkIPadAppStoreID = @"fb_product_applink_ipad_app_store_id";
|
||||||
NSString *const FBSDKAppEventParameterProductAppLinkAndroidUrl = @"fb_product_applink_android_url";
|
FBSDKAppEventParameterProduct FBSDKAppEventParameterProductAppLinkIPadAppName = @"fb_product_applink_ipad_app_name";
|
||||||
NSString *const FBSDKAppEventParameterProductAppLinkAndroidPackage = @"fb_product_applink_android_package";
|
FBSDKAppEventParameterProduct FBSDKAppEventParameterProductAppLinkAndroidUrl = @"fb_product_applink_android_url";
|
||||||
NSString *const FBSDKAppEventParameterProductAppLinkAndroidAppName = @"fb_product_applink_android_app_name";
|
FBSDKAppEventParameterProduct FBSDKAppEventParameterProductAppLinkAndroidPackage = @"fb_product_applink_android_package";
|
||||||
NSString *const FBSDKAppEventParameterProductAppLinkWindowsPhoneUrl = @"fb_product_applink_windows_phone_url";
|
FBSDKAppEventParameterProduct FBSDKAppEventParameterProductAppLinkAndroidAppName = @"fb_product_applink_android_app_name";
|
||||||
NSString *const FBSDKAppEventParameterProductAppLinkWindowsPhoneAppID = @"fb_product_applink_windows_phone_app_id";
|
FBSDKAppEventParameterProduct FBSDKAppEventParameterProductAppLinkWindowsPhoneUrl = @"fb_product_applink_windows_phone_url";
|
||||||
NSString *const FBSDKAppEventParameterProductAppLinkWindowsPhoneAppName = @"fb_product_applink_windows_phone_app_name";
|
FBSDKAppEventParameterProduct FBSDKAppEventParameterProductAppLinkWindowsPhoneAppID = @"fb_product_applink_windows_phone_app_id";
|
||||||
|
FBSDKAppEventParameterProduct FBSDKAppEventParameterProductAppLinkWindowsPhoneAppName = @"fb_product_applink_windows_phone_app_name";
|
||||||
|
|
||||||
//
|
//
|
||||||
// Public event parameter values
|
// Public event parameter values
|
||||||
//
|
//
|
||||||
|
|
||||||
NSString *const FBSDKAppEventParameterValueNo = @"0";
|
FBSDKAppEventParameterValue FBSDKAppEventParameterValueNo = @"0";
|
||||||
NSString *const FBSDKAppEventParameterValueYes = @"1";
|
FBSDKAppEventParameterValue FBSDKAppEventParameterValueYes = @"1";
|
||||||
|
|
||||||
|
//
|
||||||
|
// Public event user data types
|
||||||
|
//
|
||||||
|
|
||||||
|
FBSDKAppEventUserDataType FBSDKAppEventEmail = @"em";
|
||||||
|
FBSDKAppEventUserDataType FBSDKAppEventFirstName = @"fn";
|
||||||
|
FBSDKAppEventUserDataType FBSDKAppEventLastName = @"ln";
|
||||||
|
FBSDKAppEventUserDataType FBSDKAppEventPhone = @"ph";
|
||||||
|
FBSDKAppEventUserDataType FBSDKAppEventDateOfBirth = @"dob";
|
||||||
|
FBSDKAppEventUserDataType FBSDKAppEventGender = @"ge";
|
||||||
|
FBSDKAppEventUserDataType FBSDKAppEventCity = @"ct";
|
||||||
|
FBSDKAppEventUserDataType FBSDKAppEventState = @"st";
|
||||||
|
FBSDKAppEventUserDataType FBSDKAppEventZip = @"zp";
|
||||||
|
FBSDKAppEventUserDataType FBSDKAppEventCountry = @"country";
|
||||||
|
|
||||||
//
|
//
|
||||||
// Event names internal to this file
|
// Event names internal to this file
|
||||||
//
|
//
|
||||||
NSString *const FBSDKAppEventNamePurchased = @"fb_mobile_purchase";
|
FBSDKAppEventName FBSDKAppEventNameLoginViewUsage = @"fb_login_view_usage";
|
||||||
|
FBSDKAppEventName FBSDKAppEventNameShareSheetLaunch = @"fb_share_sheet_launch";
|
||||||
|
FBSDKAppEventName FBSDKAppEventNameShareSheetDismiss = @"fb_share_sheet_dismiss";
|
||||||
|
FBSDKAppEventName FBSDKAppEventNameShareTrayDidLaunch = @"fb_share_tray_did_launch";
|
||||||
|
FBSDKAppEventName FBSDKAppEventNameShareTrayDidSelectActivity = @"fb_share_tray_did_select_activity";
|
||||||
|
FBSDKAppEventName FBSDKAppEventNamePermissionsUILaunch = @"fb_permissions_ui_launch";
|
||||||
|
FBSDKAppEventName FBSDKAppEventNamePermissionsUIDismiss = @"fb_permissions_ui_dismiss";
|
||||||
|
FBSDKAppEventName FBSDKAppEventNameFBDialogsPresentShareDialog = @"fb_dialogs_present_share";
|
||||||
|
FBSDKAppEventName FBSDKAppEventNameFBDialogsPresentShareDialogPhoto = @"fb_dialogs_present_share_photo";
|
||||||
|
FBSDKAppEventName FBSDKAppEventNameFBDialogsPresentShareDialogOG = @"fb_dialogs_present_share_og";
|
||||||
|
FBSDKAppEventName FBSDKAppEventNameFBDialogsPresentLikeDialogOG = @"fb_dialogs_present_like_og";
|
||||||
|
FBSDKAppEventName FBSDKAppEventNameFBDialogsPresentMessageDialog = @"fb_dialogs_present_message";
|
||||||
|
FBSDKAppEventName FBSDKAppEventNameFBDialogsPresentMessageDialogPhoto = @"fb_dialogs_present_message_photo";
|
||||||
|
FBSDKAppEventName FBSDKAppEventNameFBDialogsPresentMessageDialogOG = @"fb_dialogs_present_message_og";
|
||||||
|
|
||||||
NSString *const FBSDKAppEventNameLoginViewUsage = @"fb_login_view_usage";
|
FBSDKAppEventName FBSDKAppEventNameFBDialogsNativeLoginDialogStart = @"fb_dialogs_native_login_dialog_start";
|
||||||
NSString *const FBSDKAppEventNameShareSheetLaunch = @"fb_share_sheet_launch";
|
|
||||||
NSString *const FBSDKAppEventNameShareSheetDismiss = @"fb_share_sheet_dismiss";
|
|
||||||
NSString *const FBSDKAppEventNameShareTrayDidLaunch = @"fb_share_tray_did_launch";
|
|
||||||
NSString *const FBSDKAppEventNameShareTrayDidSelectActivity = @"fb_share_tray_did_select_activity";
|
|
||||||
NSString *const FBSDKAppEventNamePermissionsUILaunch = @"fb_permissions_ui_launch";
|
|
||||||
NSString *const FBSDKAppEventNamePermissionsUIDismiss = @"fb_permissions_ui_dismiss";
|
|
||||||
NSString *const FBSDKAppEventNameFBDialogsPresentShareDialog = @"fb_dialogs_present_share";
|
|
||||||
NSString *const FBSDKAppEventNameFBDialogsPresentShareDialogPhoto = @"fb_dialogs_present_share_photo";
|
|
||||||
NSString *const FBSDKAppEventNameFBDialogsPresentShareDialogOG = @"fb_dialogs_present_share_og";
|
|
||||||
NSString *const FBSDKAppEventNameFBDialogsPresentLikeDialogOG = @"fb_dialogs_present_like_og";
|
|
||||||
NSString *const FBSDKAppEventNameFBDialogsPresentMessageDialog = @"fb_dialogs_present_message";
|
|
||||||
NSString *const FBSDKAppEventNameFBDialogsPresentMessageDialogPhoto = @"fb_dialogs_present_message_photo";
|
|
||||||
NSString *const FBSDKAppEventNameFBDialogsPresentMessageDialogOG = @"fb_dialogs_present_message_og";
|
|
||||||
|
|
||||||
NSString *const FBSDKAppEventNameFBDialogsNativeLoginDialogStart = @"fb_dialogs_native_login_dialog_start";
|
|
||||||
NSString *const FBSDKAppEventsNativeLoginDialogStartTime = @"fb_native_login_dialog_start_time";
|
NSString *const FBSDKAppEventsNativeLoginDialogStartTime = @"fb_native_login_dialog_start_time";
|
||||||
|
|
||||||
NSString *const FBSDKAppEventNameFBDialogsNativeLoginDialogEnd = @"fb_dialogs_native_login_dialog_end";
|
FBSDKAppEventName FBSDKAppEventNameFBDialogsNativeLoginDialogEnd = @"fb_dialogs_native_login_dialog_end";
|
||||||
NSString *const FBSDKAppEventsNativeLoginDialogEndTime = @"fb_native_login_dialog_end_time";
|
NSString *const FBSDKAppEventsNativeLoginDialogEndTime = @"fb_native_login_dialog_end_time";
|
||||||
|
|
||||||
NSString *const FBSDKAppEventNameFBDialogsWebLoginCompleted = @"fb_dialogs_web_login_dialog_complete";
|
FBSDKAppEventName FBSDKAppEventNameFBDialogsWebLoginCompleted = @"fb_dialogs_web_login_dialog_complete";
|
||||||
NSString *const FBSDKAppEventsWebLoginE2E = @"fb_web_login_e2e";
|
NSString *const FBSDKAppEventsWebLoginE2E = @"fb_web_login_e2e";
|
||||||
|
|
||||||
NSString *const FBSDKAppEventNameFBSessionAuthStart = @"fb_mobile_login_start";
|
FBSDKAppEventName FBSDKAppEventNameFBSessionAuthStart = @"fb_mobile_login_start";
|
||||||
NSString *const FBSDKAppEventNameFBSessionAuthEnd = @"fb_mobile_login_complete";
|
FBSDKAppEventName FBSDKAppEventNameFBSessionAuthEnd = @"fb_mobile_login_complete";
|
||||||
NSString *const FBSDKAppEventNameFBSessionAuthMethodStart = @"fb_mobile_login_method_start";
|
FBSDKAppEventName FBSDKAppEventNameFBSessionAuthMethodStart = @"fb_mobile_login_method_start";
|
||||||
NSString *const FBSDKAppEventNameFBSessionAuthMethodEnd = @"fb_mobile_login_method_complete";
|
FBSDKAppEventName FBSDKAppEventNameFBSessionAuthMethodEnd = @"fb_mobile_login_method_complete";
|
||||||
|
|
||||||
NSString *const FBSDKAppEventNameFBSDKLikeButtonImpression = @"fb_like_button_impression";
|
FBSDKAppEventName FBSDKAppEventNameFBSDKLikeButtonImpression = @"fb_like_button_impression";
|
||||||
NSString *const FBSDKAppEventNameFBSDKLoginButtonImpression = @"fb_login_button_impression";
|
FBSDKAppEventName FBSDKAppEventNameFBSDKLoginButtonImpression = @"fb_login_button_impression";
|
||||||
NSString *const FBSDKAppEventNameFBSDKSendButtonImpression = @"fb_send_button_impression";
|
FBSDKAppEventName FBSDKAppEventNameFBSDKSendButtonImpression = @"fb_send_button_impression";
|
||||||
NSString *const FBSDKAppEventNameFBSDKShareButtonImpression = @"fb_share_button_impression";
|
FBSDKAppEventName FBSDKAppEventNameFBSDKShareButtonImpression = @"fb_share_button_impression";
|
||||||
NSString *const FBSDKAppEventNameFBSDKLiveStreamingButtonImpression = @"fb_live_streaming_button_impression";
|
FBSDKAppEventName FBSDKAppEventNameFBSDKLiveStreamingButtonImpression = @"fb_live_streaming_button_impression";
|
||||||
|
|
||||||
NSString *const FBSDKAppEventNameFBSDKSmartLoginService = @"fb_smart_login_service";
|
FBSDKAppEventName FBSDKAppEventNameFBSDKSmartLoginService = @"fb_smart_login_service";
|
||||||
|
|
||||||
NSString *const FBSDKAppEventNameFBSDKLikeButtonDidTap = @"fb_like_button_did_tap";
|
FBSDKAppEventName FBSDKAppEventNameFBSDKLikeButtonDidTap = @"fb_like_button_did_tap";
|
||||||
NSString *const FBSDKAppEventNameFBSDKLoginButtonDidTap = @"fb_login_button_did_tap";
|
FBSDKAppEventName FBSDKAppEventNameFBSDKLoginButtonDidTap = @"fb_login_button_did_tap";
|
||||||
NSString *const FBSDKAppEventNameFBSDKSendButtonDidTap = @"fb_send_button_did_tap";
|
FBSDKAppEventName FBSDKAppEventNameFBSDKSendButtonDidTap = @"fb_send_button_did_tap";
|
||||||
NSString *const FBSDKAppEventNameFBSDKShareButtonDidTap = @"fb_share_button_did_tap";
|
FBSDKAppEventName FBSDKAppEventNameFBSDKShareButtonDidTap = @"fb_share_button_did_tap";
|
||||||
NSString *const FBSDKAppEventNameFBSDKLiveStreamingButtonDidTap = @"fb_live_streaming_button_did_tap";
|
FBSDKAppEventName FBSDKAppEventNameFBSDKLiveStreamingButtonDidTap = @"fb_live_streaming_button_did_tap";
|
||||||
|
|
||||||
NSString *const FBSDKAppEventNameFBSDKLikeControlDidDisable = @"fb_like_control_did_disable";
|
FBSDKAppEventName FBSDKAppEventNameFBSDKLikeControlDidDisable = @"fb_like_control_did_disable";
|
||||||
NSString *const FBSDKAppEventNameFBSDKLikeControlDidLike = @"fb_like_control_did_like";
|
FBSDKAppEventName FBSDKAppEventNameFBSDKLikeControlDidLike = @"fb_like_control_did_like";
|
||||||
NSString *const FBSDKAppEventNameFBSDKLikeControlDidPresentDialog = @"fb_like_control_did_present_dialog";
|
FBSDKAppEventName FBSDKAppEventNameFBSDKLikeControlDidPresentDialog = @"fb_like_control_did_present_dialog";
|
||||||
NSString *const FBSDKAppEventNameFBSDKLikeControlDidTap = @"fb_like_control_did_tap";
|
FBSDKAppEventName FBSDKAppEventNameFBSDKLikeControlDidTap = @"fb_like_control_did_tap";
|
||||||
NSString *const FBSDKAppEventNameFBSDKLikeControlDidUnlike = @"fb_like_control_did_unlike";
|
FBSDKAppEventName FBSDKAppEventNameFBSDKLikeControlDidUnlike = @"fb_like_control_did_unlike";
|
||||||
NSString *const FBSDKAppEventNameFBSDKLikeControlError = @"fb_like_control_error";
|
FBSDKAppEventName FBSDKAppEventNameFBSDKLikeControlError = @"fb_like_control_error";
|
||||||
NSString *const FBSDKAppEventNameFBSDKLikeControlImpression = @"fb_like_control_impression";
|
FBSDKAppEventName FBSDKAppEventNameFBSDKLikeControlImpression = @"fb_like_control_impression";
|
||||||
NSString *const FBSDKAppEventNameFBSDKLikeControlNetworkUnavailable = @"fb_like_control_network_unavailable";
|
FBSDKAppEventName FBSDKAppEventNameFBSDKLikeControlNetworkUnavailable = @"fb_like_control_network_unavailable";
|
||||||
|
|
||||||
NSString *const FBSDLAppEventNameFBSDKEventShareDialogResult = @"fb_dialog_share_result";
|
FBSDKAppEventName FBSDKAppEventNameFBSDKEventShareDialogResult = @"fb_dialog_share_result";
|
||||||
NSString *const FBSDKAppEventNameFBSDKEventMessengerShareDialogResult = @"fb_messenger_dialog_share_result";
|
FBSDKAppEventName FBSDKAppEventNameFBSDKEventMessengerShareDialogResult = @"fb_messenger_dialog_share_result";
|
||||||
NSString *const FBSDKAppEventNameFBSDKEventAppInviteShareDialogResult = @"fb_app_invite_dialog_share_result";
|
FBSDKAppEventName FBSDKAppEventNameFBSDKEventAppInviteShareDialogResult = @"fb_app_invite_dialog_share_result";
|
||||||
|
|
||||||
NSString *const FBSDKAppEventNameFBSDKEventShareDialogShow = @"fb_dialog_share_show";
|
FBSDKAppEventName FBSDKAppEventNameFBSDKEventShareDialogShow = @"fb_dialog_share_show";
|
||||||
NSString *const FBSDKAppEventNameFBSDKEventMessengerShareDialogShow = @"fb_messenger_dialog_share_show";
|
FBSDKAppEventName FBSDKAppEventNameFBSDKEventMessengerShareDialogShow = @"fb_messenger_dialog_share_show";
|
||||||
NSString *const FBSDKAppEventNameFBSDKEventAppInviteShareDialogShow = @"fb_app_invite_share_show";
|
FBSDKAppEventName FBSDKAppEventNameFBSDKEventAppInviteShareDialogShow = @"fb_app_invite_share_show";
|
||||||
|
|
||||||
NSString *const FBSDKAppEventNameFBSessionFASLoginDialogResult = @"fb_mobile_login_fas_dialog_result";
|
FBSDKAppEventName FBSDKAppEventNameFBSessionFASLoginDialogResult = @"fb_mobile_login_fas_dialog_result";
|
||||||
|
|
||||||
NSString *const FBSDKAppEventNameFBSDKLiveStreamingStart = @"fb_sdk_live_streaming_start";
|
FBSDKAppEventName FBSDKAppEventNameFBSDKLiveStreamingStart = @"fb_sdk_live_streaming_start";
|
||||||
NSString *const FBSDKAppEventNameFBSDKLiveStreamingStop = @"fb_sdk_live_streaming_stop";
|
FBSDKAppEventName FBSDKAppEventNameFBSDKLiveStreamingStop = @"fb_sdk_live_streaming_stop";
|
||||||
NSString *const FBSDKAppEventNameFBSDKLiveStreamingPause = @"fb_sdk_live_streaming_pause";
|
FBSDKAppEventName FBSDKAppEventNameFBSDKLiveStreamingPause = @"fb_sdk_live_streaming_pause";
|
||||||
NSString *const FBSDKAppEventNameFBSDKLiveStreamingResume = @"fb_sdk_live_streaming_resume";
|
FBSDKAppEventName FBSDKAppEventNameFBSDKLiveStreamingResume = @"fb_sdk_live_streaming_resume";
|
||||||
NSString *const FBSDKAppEventNameFBSDKLiveStreamingError = @"fb_sdk_live_streaming_error";
|
FBSDKAppEventName FBSDKAppEventNameFBSDKLiveStreamingError = @"fb_sdk_live_streaming_error";
|
||||||
NSString *const FBSDKAppEventNameFBSDKLiveStreamingUpdateStatus = @"fb_sdk_live_streaming_update_status";
|
FBSDKAppEventName FBSDKAppEventNameFBSDKLiveStreamingUpdateStatus = @"fb_sdk_live_streaming_update_status";
|
||||||
NSString *const FBSDKAppEventNameFBSDKLiveStreamingVideoID = @"fb_sdk_live_streaming_video_id";
|
FBSDKAppEventName FBSDKAppEventNameFBSDKLiveStreamingVideoID = @"fb_sdk_live_streaming_video_id";
|
||||||
NSString *const FBSDKAppEventNameFBSDKLiveStreamingMic = @"fb_sdk_live_streaming_mic";
|
FBSDKAppEventName FBSDKAppEventNameFBSDKLiveStreamingMic = @"fb_sdk_live_streaming_mic";
|
||||||
NSString *const FBSDKAppEventNameFBSDKLiveStreamingCamera = @"fb_sdk_live_streaming_camera";
|
FBSDKAppEventName FBSDKAppEventNameFBSDKLiveStreamingCamera = @"fb_sdk_live_streaming_camera";
|
||||||
|
|
||||||
// Event Parameters internal to this file
|
// Event Parameters internal to this file
|
||||||
NSString *const FBSDKAppEventParameterDialogOutcome = @"fb_dialog_outcome";
|
NSString *const FBSDKAppEventParameterDialogOutcome = @"fb_dialog_outcome";
|
||||||
@ -220,6 +238,7 @@ NSString *const FBSDKAppEventParameterShareTrayResult = @"fb_share_t
|
|||||||
NSString *const FBSDKAppEventParameterLogTime = @"_logTime";
|
NSString *const FBSDKAppEventParameterLogTime = @"_logTime";
|
||||||
NSString *const FBSDKAppEventParameterEventName = @"_eventName";
|
NSString *const FBSDKAppEventParameterEventName = @"_eventName";
|
||||||
NSString *const FBSDKAppEventParameterImplicitlyLogged = @"_implicitlyLogged";
|
NSString *const FBSDKAppEventParameterImplicitlyLogged = @"_implicitlyLogged";
|
||||||
|
NSString *const FBSDKAppEventParameterInBackground = @"_inBackground";
|
||||||
|
|
||||||
NSString *const FBSDKAppEventParameterLiveStreamingPrevStatus = @"live_streaming_prev_status";
|
NSString *const FBSDKAppEventParameterLiveStreamingPrevStatus = @"live_streaming_prev_status";
|
||||||
NSString *const FBSDKAppEventParameterLiveStreamingStatus = @"live_streaming_status";
|
NSString *const FBSDKAppEventParameterLiveStreamingStatus = @"live_streaming_status";
|
||||||
@ -228,18 +247,18 @@ NSString *const FBSDKAppEventParameterLiveStreamingVideoID = @"live_stream
|
|||||||
NSString *const FBSDKAppEventParameterLiveStreamingMicEnabled = @"live_streaming_mic_enabled";
|
NSString *const FBSDKAppEventParameterLiveStreamingMicEnabled = @"live_streaming_mic_enabled";
|
||||||
NSString *const FBSDKAppEventParameterLiveStreamingCameraEnabled = @"live_streaming_camera_enabled";
|
NSString *const FBSDKAppEventParameterLiveStreamingCameraEnabled = @"live_streaming_camera_enabled";
|
||||||
|
|
||||||
NSString *const FBSDKAppEventParameterProductItemID = @"fb_product_item_id";
|
FBSDKAppEventParameterProduct FBSDKAppEventParameterProductItemID = @"fb_product_item_id";
|
||||||
NSString *const FBSDKAppEventParameterProductAvailability = @"fb_product_availability";
|
FBSDKAppEventParameterProduct FBSDKAppEventParameterProductAvailability = @"fb_product_availability";
|
||||||
NSString *const FBSDKAppEventParameterProductCondition = @"fb_product_condition";
|
FBSDKAppEventParameterProduct FBSDKAppEventParameterProductCondition = @"fb_product_condition";
|
||||||
NSString *const FBSDKAppEventParameterProductDescription = @"fb_product_description";
|
FBSDKAppEventParameterProduct FBSDKAppEventParameterProductDescription = @"fb_product_description";
|
||||||
NSString *const FBSDKAppEventParameterProductImageLink = @"fb_product_image_link";
|
FBSDKAppEventParameterProduct FBSDKAppEventParameterProductImageLink = @"fb_product_image_link";
|
||||||
NSString *const FBSDKAppEventParameterProductLink = @"fb_product_link";
|
FBSDKAppEventParameterProduct FBSDKAppEventParameterProductLink = @"fb_product_link";
|
||||||
NSString *const FBSDKAppEventParameterProductTitle = @"fb_product_title";
|
FBSDKAppEventParameterProduct FBSDKAppEventParameterProductTitle = @"fb_product_title";
|
||||||
NSString *const FBSDKAppEventParameterProductGTIN = @"fb_product_gtin";
|
FBSDKAppEventParameterProduct FBSDKAppEventParameterProductGTIN = @"fb_product_gtin";
|
||||||
NSString *const FBSDKAppEventParameterProductMPN = @"fb_product_mpn";
|
FBSDKAppEventParameterProduct FBSDKAppEventParameterProductMPN = @"fb_product_mpn";
|
||||||
NSString *const FBSDKAppEventParameterProductBrand = @"fb_product_brand";
|
FBSDKAppEventParameterProduct FBSDKAppEventParameterProductBrand = @"fb_product_brand";
|
||||||
NSString *const FBSDKAppEventParameterProductPriceAmount = @"fb_product_price_amount";
|
FBSDKAppEventParameterProduct FBSDKAppEventParameterProductPriceAmount = @"fb_product_price_amount";
|
||||||
NSString *const FBSDKAppEventParameterProductPriceCurrency = @"fb_product_price_currency";
|
FBSDKAppEventParameterProduct FBSDKAppEventParameterProductPriceCurrency = @"fb_product_price_currency";
|
||||||
|
|
||||||
// Event parameter values internal to this file
|
// Event parameter values internal to this file
|
||||||
NSString *const FBSDKAppEventsDialogOutcomeValue_Completed = @"Completed";
|
NSString *const FBSDKAppEventsDialogOutcomeValue_Completed = @"Completed";
|
||||||
@ -265,6 +284,8 @@ NSString *const FBSDKAppEventsDialogShareContentTypeMessengerMediaTemplate
|
|||||||
NSString *const FBSDKAppEventsDialogShareContentTypeMessengerOpenGraphMusicTemplate = @"OpenGraphMusicTemplate";
|
NSString *const FBSDKAppEventsDialogShareContentTypeMessengerOpenGraphMusicTemplate = @"OpenGraphMusicTemplate";
|
||||||
NSString *const FBSDKAppEventsDialogShareContentTypeUnknown = @"Unknown";
|
NSString *const FBSDKAppEventsDialogShareContentTypeUnknown = @"Unknown";
|
||||||
|
|
||||||
|
NSString *const FBSDKGateKeeperAppEventsKillSwitch = @"app_events_killswitch";
|
||||||
|
|
||||||
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0
|
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0
|
||||||
|
|
||||||
NSNotificationName const FBSDKAppEventsLoggingResultNotification = @"com.facebook.sdk:FBSDKAppEventsLoggingResultNotification";
|
NSNotificationName const FBSDKAppEventsLoggingResultNotification = @"com.facebook.sdk:FBSDKAppEventsLoggingResultNotification";
|
||||||
@ -283,8 +304,8 @@ NSString *const FBSDKAppEventsOverrideAppIDBundleKey = @"FacebookLoggingOverride
|
|||||||
// Activities Endpoint Parameter
|
// Activities Endpoint Parameter
|
||||||
static NSString *const FBSDKActivitesParameterPushDeviceToken = @"device_token";
|
static NSString *const FBSDKActivitesParameterPushDeviceToken = @"device_token";
|
||||||
// Event Names
|
// Event Names
|
||||||
static NSString *const FBSDKAppEventNamePushTokenObtained = @"fb_mobile_obtain_push_token";
|
static FBSDKAppEventName FBSDKAppEventNamePushTokenObtained = @"fb_mobile_obtain_push_token";
|
||||||
static NSString *const FBSDKAppEventNamePushOpened = @"fb_mobile_push_opened";
|
static FBSDKAppEventName FBSDKAppEventNamePushOpened = @"fb_mobile_push_opened";
|
||||||
// Event Parameter
|
// Event Parameter
|
||||||
static NSString *const FBSDKAppEventParameterPushCampaign = @"fb_push_campaign";
|
static NSString *const FBSDKAppEventParameterPushCampaign = @"fb_push_campaign";
|
||||||
static NSString *const FBSDKAppEventParameterPushAction = @"fb_push_action";
|
static NSString *const FBSDKAppEventParameterPushAction = @"fb_push_action";
|
||||||
@ -301,7 +322,6 @@ NSString *const FBSDKAppEventsWKWebViewMessagesEventKey = @"event";
|
|||||||
NSString *const FBSDKAppEventsWKWebViewMessagesParamsKey = @"params";
|
NSString *const FBSDKAppEventsWKWebViewMessagesParamsKey = @"params";
|
||||||
NSString *const FBSDKAPPEventsWKWebViewMessagesProtocolKey = @"fbmq-0.1";
|
NSString *const FBSDKAPPEventsWKWebViewMessagesProtocolKey = @"fbmq-0.1";
|
||||||
|
|
||||||
|
|
||||||
#define NUM_LOG_EVENTS_TO_TRY_TO_FLUSH_AFTER 100
|
#define NUM_LOG_EVENTS_TO_TRY_TO_FLUSH_AFTER 100
|
||||||
#define FLUSH_PERIOD_IN_SECONDS 15
|
#define FLUSH_PERIOD_IN_SECONDS 15
|
||||||
#define USER_ID_USER_DEFAULTS_KEY @"com.facebook.sdk.appevents.userid"
|
#define USER_ID_USER_DEFAULTS_KEY @"com.facebook.sdk.appevents.userid"
|
||||||
@ -309,11 +329,6 @@ NSString *const FBSDKAPPEventsWKWebViewMessagesProtocolKey = @"fbmq-0.1";
|
|||||||
#define FBUnityUtilityClassName "FBUnityUtility"
|
#define FBUnityUtilityClassName "FBUnityUtility"
|
||||||
#define FBUnityUtilityUpdateBindingsSelector @"triggerUpdateBindings:"
|
#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;
|
static NSString *g_overrideAppID = nil;
|
||||||
|
|
||||||
@interface FBSDKAppEvents ()
|
@interface FBSDKAppEvents ()
|
||||||
@ -346,16 +361,17 @@ static NSString *g_overrideAppID = nil;
|
|||||||
{
|
{
|
||||||
if (self == [FBSDKAppEvents class]) {
|
if (self == [FBSDKAppEvents class]) {
|
||||||
g_overrideAppID = [[[NSBundle mainBundle] objectForInfoDictionaryKey:FBSDKAppEventsOverrideAppIDBundleKey] copy];
|
g_overrideAppID = [[[NSBundle mainBundle] objectForInfoDictionaryKey:FBSDKAppEventsOverrideAppIDBundleKey] copy];
|
||||||
|
[FBSDKBasicUtility anonymousID];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (FBSDKAppEvents *)init
|
- (instancetype)init
|
||||||
{
|
{
|
||||||
self = [super init];
|
self = [super init];
|
||||||
if (self) {
|
if (self) {
|
||||||
_flushBehavior = FBSDKAppEventsFlushBehaviorAuto;
|
_flushBehavior = FBSDKAppEventsFlushBehaviorAuto;
|
||||||
|
|
||||||
typeof(self) __weak weakSelf = self;
|
__weak FBSDKAppEvents *weakSelf = self;
|
||||||
self.flushTimer = [FBSDKUtility startGCDTimerWithInterval:FLUSH_PERIOD_IN_SECONDS
|
self.flushTimer = [FBSDKUtility startGCDTimerWithInterval:FLUSH_PERIOD_IN_SECONDS
|
||||||
block:^{
|
block:^{
|
||||||
[weakSelf flushTimerFired:nil];
|
[weakSelf flushTimerFired:nil];
|
||||||
@ -397,21 +413,21 @@ static NSString *g_overrideAppID = nil;
|
|||||||
|
|
||||||
#pragma mark - Public Methods
|
#pragma mark - Public Methods
|
||||||
|
|
||||||
+ (void)logEvent:(NSString *)eventName
|
+ (void)logEvent:(FBSDKAppEventName)eventName
|
||||||
{
|
{
|
||||||
[FBSDKAppEvents logEvent:eventName
|
[FBSDKAppEvents logEvent:eventName
|
||||||
parameters:nil];
|
parameters:@{}];
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (void)logEvent:(NSString *)eventName
|
+ (void)logEvent:(FBSDKAppEventName)eventName
|
||||||
valueToSum:(double)valueToSum
|
valueToSum:(double)valueToSum
|
||||||
{
|
{
|
||||||
[FBSDKAppEvents logEvent:eventName
|
[FBSDKAppEvents logEvent:eventName
|
||||||
valueToSum:valueToSum
|
valueToSum:valueToSum
|
||||||
parameters:nil];
|
parameters:@{}];
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (void)logEvent:(NSString *)eventName
|
+ (void)logEvent:(FBSDKAppEventName)eventName
|
||||||
parameters:(NSDictionary *)parameters
|
parameters:(NSDictionary *)parameters
|
||||||
{
|
{
|
||||||
[FBSDKAppEvents logEvent:eventName
|
[FBSDKAppEvents logEvent:eventName
|
||||||
@ -420,7 +436,7 @@ static NSString *g_overrideAppID = nil;
|
|||||||
accessToken:nil];
|
accessToken:nil];
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (void)logEvent:(NSString *)eventName
|
+ (void)logEvent:(FBSDKAppEventName)eventName
|
||||||
valueToSum:(double)valueToSum
|
valueToSum:(double)valueToSum
|
||||||
parameters:(NSDictionary *)parameters
|
parameters:(NSDictionary *)parameters
|
||||||
{
|
{
|
||||||
@ -430,7 +446,7 @@ static NSString *g_overrideAppID = nil;
|
|||||||
accessToken:nil];
|
accessToken:nil];
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (void)logEvent:(NSString *)eventName
|
+ (void)logEvent:(FBSDKAppEventName)eventName
|
||||||
valueToSum:(NSNumber *)valueToSum
|
valueToSum:(NSNumber *)valueToSum
|
||||||
parameters:(NSDictionary *)parameters
|
parameters:(NSDictionary *)parameters
|
||||||
accessToken:(FBSDKAccessToken *)accessToken
|
accessToken:(FBSDKAccessToken *)accessToken
|
||||||
@ -447,7 +463,7 @@ static NSString *g_overrideAppID = nil;
|
|||||||
{
|
{
|
||||||
[FBSDKAppEvents logPurchase:purchaseAmount
|
[FBSDKAppEvents logPurchase:purchaseAmount
|
||||||
currency:currency
|
currency:currency
|
||||||
parameters:nil];
|
parameters:@{}];
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (void)logPurchase:(double)purchaseAmount
|
+ (void)logPurchase:(double)purchaseAmount
|
||||||
@ -494,7 +510,7 @@ static NSString *g_overrideAppID = nil;
|
|||||||
|
|
||||||
+ (void)logPushNotificationOpen:(NSDictionary *)payload
|
+ (void)logPushNotificationOpen:(NSDictionary *)payload
|
||||||
{
|
{
|
||||||
[self logPushNotificationOpen:payload action:nil];
|
[self logPushNotificationOpen:payload action:@""];
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (void)logPushNotificationOpen:(NSDictionary *)payload action:(NSString *)action
|
+ (void)logPushNotificationOpen:(NSDictionary *)payload action:(NSString *)action
|
||||||
@ -511,7 +527,7 @@ static NSString *g_overrideAppID = nil;
|
|||||||
}
|
}
|
||||||
|
|
||||||
NSMutableDictionary *parameters = [NSMutableDictionary dictionaryWithObject:campaign forKey:FBSDKAppEventParameterPushCampaign];
|
NSMutableDictionary *parameters = [NSMutableDictionary dictionaryWithObject:campaign forKey:FBSDKAppEventParameterPushCampaign];
|
||||||
if (action) {
|
if (action && action.length > 0) {
|
||||||
parameters[FBSDKAppEventParameterPushAction] = action;
|
parameters[FBSDKAppEventParameterPushAction] = action;
|
||||||
}
|
}
|
||||||
[self logEvent:FBSDKAppEventNamePushOpened parameters:parameters];
|
[self logEvent:FBSDKAppEventNamePushOpened parameters:parameters];
|
||||||
@ -532,7 +548,8 @@ static NSString *g_overrideAppID = nil;
|
|||||||
gtin:(NSString *)gtin
|
gtin:(NSString *)gtin
|
||||||
mpn:(NSString *)mpn
|
mpn:(NSString *)mpn
|
||||||
brand:(NSString *)brand
|
brand:(NSString *)brand
|
||||||
parameters:(NSDictionary *)parameters {
|
parameters:(NSDictionary *)parameters
|
||||||
|
{
|
||||||
if (itemID == nil) {
|
if (itemID == nil) {
|
||||||
[FBSDKLogger singleShotLogEntry:FBSDKLoggingBehaviorDeveloperErrors
|
[FBSDKLogger singleShotLogEntry:FBSDKLoggingBehaviorDeveloperErrors
|
||||||
logEntry:@"itemID cannot be null"];
|
logEntry:@"itemID cannot be null"];
|
||||||
@ -634,7 +651,6 @@ static NSString *g_overrideAppID = nil;
|
|||||||
// when appropriate, result in logging an "activated app" and "deactivated app" (for the
|
// when appropriate, result in logging an "activated app" and "deactivated app" (for the
|
||||||
// previous session) App Event.
|
// previous session) App Event.
|
||||||
[FBSDKTimeSpentData restore:YES];
|
[FBSDKTimeSpentData restore:YES];
|
||||||
[FBSDKUserDataStore initStore];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (void)setPushNotificationsDeviceToken:(NSData *)deviceToken
|
+ (void)setPushNotificationsDeviceToken:(NSData *)deviceToken
|
||||||
@ -713,75 +729,82 @@ static NSString *g_overrideAppID = nil;
|
|||||||
return [[self class] singleton]->_userID;
|
return [[self class] singleton]->_userID;
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (void)setUserData:(NSDictionary*)userData
|
+ (void)setUserEmail:(nullable NSString *)email
|
||||||
|
firstName:(nullable NSString *)firstName
|
||||||
|
lastName:(nullable NSString *)lastName
|
||||||
|
phone:(nullable NSString *)phone
|
||||||
|
dateOfBirth:(nullable NSString *)dateOfBirth
|
||||||
|
gender:(nullable NSString *)gender
|
||||||
|
city:(nullable NSString *)city
|
||||||
|
state:(nullable NSString *)state
|
||||||
|
zip:(nullable NSString *)zip
|
||||||
|
country:(nullable NSString *)country
|
||||||
{
|
{
|
||||||
[FBSDKUserDataStore setUserDataAndHash:userData];
|
[FBSDKUserDataStore setAndHashUserEmail:email
|
||||||
}
|
firstName:firstName
|
||||||
|
lastName:lastName
|
||||||
+ (void)setUserEmail:(NSString *)email
|
phone:phone
|
||||||
firstName:(NSString *)firstName
|
dateOfBirth:dateOfBirth
|
||||||
lastName:(NSString *)lastName
|
gender:gender
|
||||||
phone:(NSString *)phone
|
city:city
|
||||||
dateOfBirth:(NSString *)dateOfBirth
|
state:state
|
||||||
gender:(NSString *)gender
|
zip:zip
|
||||||
city:(NSString *)city
|
country:country];
|
||||||
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
|
+ (NSString*)getUserData
|
||||||
{
|
{
|
||||||
return [FBSDKUserDataStore getHashedUserData];
|
return [FBSDKUserDataStore getHashedData];
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (void)clearUserData
|
+ (void)clearUserData
|
||||||
{
|
{
|
||||||
[FBSDKUserDataStore setUserDataAndHash:nil
|
[FBSDKUserDataStore setAndHashUserEmail:nil
|
||||||
firstName:nil
|
firstName:nil
|
||||||
lastName:nil
|
lastName:nil
|
||||||
phone:nil
|
phone:nil
|
||||||
dateOfBirth:nil
|
dateOfBirth:nil
|
||||||
gender:nil
|
gender:nil
|
||||||
city:nil
|
city:nil
|
||||||
state:nil
|
state:nil
|
||||||
zip:nil
|
zip:nil
|
||||||
country:nil];
|
country:nil];
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (void)updateUserProperties:(NSDictionary *)properties handler:(FBSDKGraphRequestHandler)handler
|
+ (void)setUserData:(nullable NSString *)data
|
||||||
|
forType:(FBSDKAppEventUserDataType)type
|
||||||
|
{
|
||||||
|
[FBSDKUserDataStore setAndHashData:data forType:type];
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (void)clearUserDataForType:(FBSDKAppEventUserDataType)type
|
||||||
|
{
|
||||||
|
[FBSDKUserDataStore clearDataForType:type];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
+ (void)updateUserProperties:(NSDictionary<NSString *, id> *)properties handler:(FBSDKGraphRequestBlock)handler
|
||||||
{
|
{
|
||||||
NSString *userID = [[self class] userID];
|
NSString *userID = [[self class] userID];
|
||||||
|
|
||||||
if (userID.length == 0) {
|
if (userID.length == 0) {
|
||||||
[FBSDKLogger singleShotLogEntry:FBSDKLoggingBehaviorDeveloperErrors logEntry:@"Missing [FBSDKAppEvents userID] for [FBSDKAppEvents updateUserProperties:]"];
|
[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) {
|
if (handler) {
|
||||||
handler(nil, nil, error);
|
handler(nil, nil, error);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
NSMutableDictionary *dataDictionary = [NSMutableDictionary dictionaryWithCapacity:3];
|
NSMutableDictionary *dataDictionary = [NSMutableDictionary dictionaryWithCapacity:3];
|
||||||
dataDictionary[@"user_unique_id"] = [FBSDKAppEvents userID];
|
[FBSDKBasicUtility dictionary:dataDictionary setObject:[FBSDKAppEvents userID] forKey:@"user_unique_id"];
|
||||||
[FBSDKInternalUtility dictionary:dataDictionary setObject:[FBSDKAppEventsUtility advertiserID] forKey:@"advertiser_id"];
|
[FBSDKBasicUtility dictionary:dataDictionary setObject:[FBSDKAppEventsUtility advertiserID] forKey:@"advertiser_id"];
|
||||||
[FBSDKInternalUtility dictionary:dataDictionary setObject:properties forKey:@"custom_data"];
|
[FBSDKBasicUtility dictionary:dataDictionary setObject:properties forKey:@"custom_data"];
|
||||||
|
|
||||||
NSError *error;
|
NSError *error;
|
||||||
__block NSError *invalidObjectError;
|
__block NSError *invalidObjectError;
|
||||||
NSString *dataJSONString = [FBSDKInternalUtility JSONStringForObject:@[dataDictionary] error:&error invalidObjectHandler:^id(id object, BOOL *stop) {
|
NSString *dataJSONString = [FBSDKBasicUtility JSONStringForObject:@[dataDictionary] error:&error invalidObjectHandler:^id(id object, BOOL *stop) {
|
||||||
*stop = YES;
|
*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;
|
return nil;
|
||||||
}];
|
}];
|
||||||
if (!error) {
|
if (!error) {
|
||||||
@ -798,7 +821,7 @@ static NSString *g_overrideAppID = nil;
|
|||||||
FBSDKGraphRequest *request = [[FBSDKGraphRequest alloc] initWithGraphPath:[NSString stringWithFormat:@"%@/user_properties", [[self singleton] appID]]
|
FBSDKGraphRequest *request = [[FBSDKGraphRequest alloc] initWithGraphPath:[NSString stringWithFormat:@"%@/user_properties", [[self singleton] appID]]
|
||||||
parameters:params
|
parameters:params
|
||||||
tokenString:[FBSDKAccessToken currentAccessToken].tokenString
|
tokenString:[FBSDKAccessToken currentAccessToken].tokenString
|
||||||
HTTPMethod:@"POST"
|
HTTPMethod:FBSDKHTTPMethodPOST
|
||||||
flags:FBSDKGraphRequestFlagDisableErrorRecovery |
|
flags:FBSDKGraphRequestFlagDisableErrorRecovery |
|
||||||
FBSDKGraphRequestFlagDoNotInvalidateTokenOnError |
|
FBSDKGraphRequestFlagDoNotInvalidateTokenOnError |
|
||||||
FBSDKGraphRequestFlagSkipClientToken
|
FBSDKGraphRequestFlagSkipClientToken
|
||||||
@ -864,6 +887,74 @@ static NSString *g_overrideAppID = nil;
|
|||||||
|
|
||||||
#pragma mark - Internal Methods
|
#pragma mark - Internal Methods
|
||||||
|
|
||||||
|
+ (void)logInternalEvent:(FBSDKAppEventName)eventName
|
||||||
|
isImplicitlyLogged:(BOOL)isImplicitlyLogged;
|
||||||
|
{
|
||||||
|
[FBSDKAppEvents logInternalEvent:eventName
|
||||||
|
parameters:@{}
|
||||||
|
isImplicitlyLogged:isImplicitlyLogged];
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (void)logInternalEvent:(FBSDKAppEventName)eventName
|
||||||
|
valueToSum:(double)valueToSum
|
||||||
|
isImplicitlyLogged:(BOOL)isImplicitlyLogged
|
||||||
|
{
|
||||||
|
[FBSDKAppEvents logInternalEvent:eventName
|
||||||
|
valueToSum:valueToSum
|
||||||
|
parameters:@{}
|
||||||
|
isImplicitlyLogged:isImplicitlyLogged];
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (void)logInternalEvent:(FBSDKAppEventName)eventName
|
||||||
|
parameters:(NSDictionary *)parameters
|
||||||
|
isImplicitlyLogged:(BOOL)isImplicitlyLogged
|
||||||
|
{
|
||||||
|
[FBSDKAppEvents logInternalEvent:eventName
|
||||||
|
valueToSum:nil
|
||||||
|
parameters:parameters
|
||||||
|
isImplicitlyLogged:isImplicitlyLogged
|
||||||
|
accessToken:nil];
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (void)logInternalEvent:(FBSDKAppEventName)eventName
|
||||||
|
parameters:(NSDictionary *)parameters
|
||||||
|
isImplicitlyLogged:(BOOL)isImplicitlyLogged
|
||||||
|
accessToken:(FBSDKAccessToken *)accessToken
|
||||||
|
{
|
||||||
|
[FBSDKAppEvents logInternalEvent:eventName
|
||||||
|
valueToSum:nil
|
||||||
|
parameters:parameters
|
||||||
|
isImplicitlyLogged:isImplicitlyLogged
|
||||||
|
accessToken:accessToken];
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (void)logInternalEvent:(FBSDKAppEventName)eventName
|
||||||
|
valueToSum:(double)valueToSum
|
||||||
|
parameters:(NSDictionary *)parameters
|
||||||
|
isImplicitlyLogged:(BOOL)isImplicitlyLogged
|
||||||
|
{
|
||||||
|
[FBSDKAppEvents logInternalEvent:eventName
|
||||||
|
valueToSum:@(valueToSum)
|
||||||
|
parameters:parameters
|
||||||
|
isImplicitlyLogged:isImplicitlyLogged
|
||||||
|
accessToken:nil];
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (void)logInternalEvent:(NSString *)eventName
|
||||||
|
valueToSum:(NSNumber *)valueToSum
|
||||||
|
parameters:(NSDictionary *)parameters
|
||||||
|
isImplicitlyLogged:(BOOL)isImplicitlyLogged
|
||||||
|
accessToken:(FBSDKAccessToken *)accessToken
|
||||||
|
{
|
||||||
|
if ([FBSDKSettings isAutoLogAppEventsEnabled]) {
|
||||||
|
[[FBSDKAppEvents singleton] instanceLogEvent:eventName
|
||||||
|
valueToSum:valueToSum
|
||||||
|
parameters:parameters
|
||||||
|
isImplicitlyLogged:isImplicitlyLogged
|
||||||
|
accessToken:accessToken];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
+ (void)logImplicitEvent:(NSString *)eventName
|
+ (void)logImplicitEvent:(NSString *)eventName
|
||||||
valueToSum:(NSNumber *)valueToSum
|
valueToSum:(NSNumber *)valueToSum
|
||||||
parameters:(NSDictionary *)parameters
|
parameters:(NSDictionary *)parameters
|
||||||
@ -882,7 +973,7 @@ static NSString *g_overrideAppID = nil;
|
|||||||
static FBSDKAppEvents *shared = nil;
|
static FBSDKAppEvents *shared = nil;
|
||||||
|
|
||||||
dispatch_once(&pred, ^{
|
dispatch_once(&pred, ^{
|
||||||
shared = [[FBSDKAppEvents alloc] init];
|
shared = [[self alloc] init];
|
||||||
});
|
});
|
||||||
return shared;
|
return shared;
|
||||||
}
|
}
|
||||||
@ -931,7 +1022,7 @@ static NSString *g_overrideAppID = nil;
|
|||||||
FBSDKGraphRequest *request = [[FBSDKGraphRequest alloc] initWithGraphPath:path
|
FBSDKGraphRequest *request = [[FBSDKGraphRequest alloc] initWithGraphPath:path
|
||||||
parameters:params
|
parameters:params
|
||||||
tokenString:nil
|
tokenString:nil
|
||||||
HTTPMethod:@"POST"
|
HTTPMethod:FBSDKHTTPMethodPOST
|
||||||
flags:FBSDKGraphRequestFlagDoNotInvalidateTokenOnError | FBSDKGraphRequestFlagDisableErrorRecovery];
|
flags:FBSDKGraphRequestFlagDoNotInvalidateTokenOnError | FBSDKGraphRequestFlagDisableErrorRecovery];
|
||||||
[request startWithCompletionHandler:^(FBSDKGraphRequestConnection *connection, id result, NSError *error) {
|
[request startWithCompletionHandler:^(FBSDKGraphRequestConnection *connection, id result, NSError *error) {
|
||||||
if (!error) {
|
if (!error) {
|
||||||
@ -947,9 +1038,10 @@ static NSString *g_overrideAppID = nil;
|
|||||||
#if !TARGET_OS_TV
|
#if !TARGET_OS_TV
|
||||||
- (void)enableCodelessEvents {
|
- (void)enableCodelessEvents {
|
||||||
if (_serverConfiguration.isCodelessEventsEnabled) {
|
if (_serverConfiguration.isCodelessEventsEnabled) {
|
||||||
|
[FBSDKCodelessIndexer enable];
|
||||||
|
|
||||||
if (!_eventBindingManager) {
|
if (!_eventBindingManager) {
|
||||||
_eventBindingManager = [[FBSDKEventBindingManager alloc] init];
|
_eventBindingManager = [[FBSDKEventBindingManager alloc] init];
|
||||||
[_eventBindingManager start];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ([FBSDKInternalUtility isUnity]) {
|
if ([FBSDKInternalUtility isUnity]) {
|
||||||
@ -963,18 +1055,28 @@ static NSString *g_overrideAppID = nil;
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
// app events can use a server configuration up to 24 hours old to minimize network traffic.
|
// app events can use a server configuration up to 24 hours old to minimize network traffic.
|
||||||
- (void)fetchServerConfiguration:(void (^)(void))callback
|
- (void)fetchServerConfiguration:(FBSDKCodeBlock)callback
|
||||||
{
|
{
|
||||||
[FBSDKServerConfigurationManager loadServerConfigurationWithCompletionBlock:^(FBSDKServerConfiguration *serverConfiguration, NSError *error) {
|
[FBSDKServerConfigurationManager loadServerConfigurationWithCompletionBlock:^(FBSDKServerConfiguration *serverConfiguration, NSError *error) {
|
||||||
self->_serverConfiguration = serverConfiguration;
|
self->_serverConfiguration = serverConfiguration;
|
||||||
|
|
||||||
if (self->_serverConfiguration.implicitPurchaseLoggingEnabled) {
|
if (self->_serverConfiguration.implicitPurchaseLoggingEnabled && [FBSDKSettings isAutoLogAppEventsEnabled]) {
|
||||||
[FBSDKPaymentObserver startObservingTransactions];
|
[FBSDKPaymentObserver startObservingTransactions];
|
||||||
} else {
|
} else {
|
||||||
[FBSDKPaymentObserver stopObservingTransactions];
|
[FBSDKPaymentObserver stopObservingTransactions];
|
||||||
}
|
}
|
||||||
#if !TARGET_OS_TV
|
#if !TARGET_OS_TV
|
||||||
[self enableCodelessEvents];
|
[FBSDKFeatureManager checkFeature:FBSDKFeatureCodelessEvents completionBlock:^(BOOL enabled) {
|
||||||
|
if (enabled) {
|
||||||
|
[self enableCodelessEvents];
|
||||||
|
}
|
||||||
|
}];
|
||||||
|
[FBSDKFeatureManager checkFeature:FBSDKFeatureAAM completionBlock:^(BOOL enabled) {
|
||||||
|
if (enabled) {
|
||||||
|
// Enable AAM
|
||||||
|
[FBSDKMetadataIndexer enable];
|
||||||
|
}
|
||||||
|
}];
|
||||||
#endif
|
#endif
|
||||||
if (callback) {
|
if (callback) {
|
||||||
callback();
|
callback();
|
||||||
@ -982,12 +1084,21 @@ static NSString *g_overrideAppID = nil;
|
|||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)instanceLogEvent:(NSString *)eventName
|
- (void)instanceLogEvent:(FBSDKAppEventName)eventName
|
||||||
valueToSum:(NSNumber *)valueToSum
|
valueToSum:(NSNumber *)valueToSum
|
||||||
parameters:(NSDictionary *)parameters
|
parameters:(NSDictionary *)parameters
|
||||||
isImplicitlyLogged:(BOOL)isImplicitlyLogged
|
isImplicitlyLogged:(BOOL)isImplicitlyLogged
|
||||||
accessToken:(FBSDKAccessToken *)accessToken
|
accessToken:(FBSDKAccessToken *)accessToken
|
||||||
{
|
{
|
||||||
|
// Kill events if kill-switch is enabled
|
||||||
|
if ([FBSDKGateKeeperManager boolForKey:FBSDKGateKeeperAppEventsKillSwitch
|
||||||
|
defaultValue:NO]) {
|
||||||
|
[FBSDKLogger singleShotLogEntry:FBSDKLoggingBehaviorAppEvents
|
||||||
|
formatString:@"FBSDKAppEvents: KillSwitch is enabled and fail to log app event: %@",
|
||||||
|
eventName];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (isImplicitlyLogged && _serverConfiguration && !_serverConfiguration.isImplicitLoggingSupported) {
|
if (isImplicitlyLogged && _serverConfiguration && !_serverConfiguration.isImplicitLoggingSupported) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -995,12 +1106,7 @@ static NSString *g_overrideAppID = nil;
|
|||||||
if (!isImplicitlyLogged && !_explicitEventsLoggedYet) {
|
if (!isImplicitlyLogged && !_explicitEventsLoggedYet) {
|
||||||
_explicitEventsLoggedYet = YES;
|
_explicitEventsLoggedYet = YES;
|
||||||
}
|
}
|
||||||
|
__block BOOL failed = ![FBSDKAppEventsUtility validateIdentifier:eventName];
|
||||||
__block BOOL failed = NO;
|
|
||||||
|
|
||||||
if (![FBSDKAppEventsUtility validateIdentifier:eventName]) {
|
|
||||||
failed = YES;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make sure parameter dictionary is well formed. Log and exit if not.
|
// Make sure parameter dictionary is well formed. Log and exit if not.
|
||||||
[parameters enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
|
[parameters enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
|
||||||
@ -1022,32 +1128,43 @@ static NSString *g_overrideAppID = nil;
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
NSMutableDictionary *eventDictionary = [NSMutableDictionary dictionaryWithDictionary:parameters];
|
parameters = [FBSDKRestrictiveDataFilterManager processParameters:parameters
|
||||||
|
eventName:eventName];
|
||||||
|
|
||||||
|
NSMutableDictionary<NSString *, id> *eventDictionary = [NSMutableDictionary dictionaryWithDictionary:parameters];
|
||||||
eventDictionary[FBSDKAppEventParameterEventName] = eventName;
|
eventDictionary[FBSDKAppEventParameterEventName] = eventName;
|
||||||
if (!eventDictionary[FBSDKAppEventParameterLogTime]) {
|
if (!eventDictionary[FBSDKAppEventParameterLogTime]) {
|
||||||
eventDictionary[FBSDKAppEventParameterLogTime] = @([FBSDKAppEventsUtility unixTimeNow]);
|
eventDictionary[FBSDKAppEventParameterLogTime] = @([FBSDKAppEventsUtility unixTimeNow]);
|
||||||
}
|
}
|
||||||
[FBSDKInternalUtility dictionary:eventDictionary setObject:valueToSum forKey:@"_valueToSum"];
|
[FBSDKBasicUtility dictionary:eventDictionary setObject:valueToSum forKey:@"_valueToSum"];
|
||||||
if (isImplicitlyLogged) {
|
if (isImplicitlyLogged) {
|
||||||
eventDictionary[FBSDKAppEventParameterImplicitlyLogged] = @"1";
|
eventDictionary[FBSDKAppEventParameterImplicitlyLogged] = @"1";
|
||||||
}
|
}
|
||||||
|
|
||||||
NSString *currentViewControllerName;
|
NSString *currentViewControllerName;
|
||||||
|
UIApplicationState applicationState;
|
||||||
if ([NSThread isMainThread]) {
|
if ([NSThread isMainThread]) {
|
||||||
// We only collect the view controller when on the main thread, as the behavior off
|
// We only collect the view controller when on the main thread, as the behavior off
|
||||||
// the main thread is unpredictable. Besides, UI state for off-main-thread computations
|
// the main thread is unpredictable. Besides, UI state for off-main-thread computations
|
||||||
// isn't really relevant anyhow.
|
// isn't really relevant anyhow.
|
||||||
UIViewController *vc = [UIApplication sharedApplication].keyWindow.rootViewController.presentedViewController;
|
UIViewController *vc = [UIApplication sharedApplication].keyWindow.rootViewController;
|
||||||
|
vc = vc.presentedViewController ?: vc;
|
||||||
if (vc) {
|
if (vc) {
|
||||||
currentViewControllerName = [[vc class] description];
|
currentViewControllerName = [[vc class] description];
|
||||||
} else {
|
} else {
|
||||||
currentViewControllerName = @"no_ui";
|
currentViewControllerName = @"no_ui";
|
||||||
}
|
}
|
||||||
|
applicationState = [UIApplication sharedApplication].applicationState;
|
||||||
} else {
|
} else {
|
||||||
currentViewControllerName = @"off_thread";
|
currentViewControllerName = @"off_thread";
|
||||||
|
applicationState = [FBSDKApplicationDelegate applicationState];
|
||||||
}
|
}
|
||||||
eventDictionary[@"_ui"] = currentViewControllerName;
|
eventDictionary[@"_ui"] = currentViewControllerName;
|
||||||
|
|
||||||
|
if (applicationState == UIApplicationStateBackground) {
|
||||||
|
eventDictionary[FBSDKAppEventParameterInBackground] = @"1";
|
||||||
|
}
|
||||||
|
|
||||||
NSString *tokenString = [FBSDKAppEventsUtility tokenStringToUseFor:accessToken];
|
NSString *tokenString = [FBSDKAppEventsUtility tokenStringToUseFor:accessToken];
|
||||||
NSString *appID = [self appID];
|
NSString *appID = [self appID];
|
||||||
|
|
||||||
@ -1135,7 +1252,7 @@ static NSString *g_overrideAppID = nil;
|
|||||||
[FBSDKAppEventsUtility ensureOnMainThread:NSStringFromSelector(_cmd) className:NSStringFromClass([self class])];
|
[FBSDKAppEventsUtility ensureOnMainThread:NSStringFromSelector(_cmd) className:NSStringFromClass([self class])];
|
||||||
|
|
||||||
[self fetchServerConfiguration:^(void) {
|
[self fetchServerConfiguration:^(void) {
|
||||||
NSString *receipt_data = [appEventsState extractReceiptData];
|
NSString *receipt_data = appEventsState.extractReceiptData;
|
||||||
NSString *encodedEvents = [appEventsState JSONStringForEvents:self->_serverConfiguration.implicitLoggingEnabled];
|
NSString *encodedEvents = [appEventsState JSONStringForEvents:self->_serverConfiguration.implicitLoggingEnabled];
|
||||||
if (!encodedEvents) {
|
if (!encodedEvents) {
|
||||||
[FBSDKLogger singleShotLogEntry:FBSDKLoggingBehaviorAppEvents
|
[FBSDKLogger singleShotLogEntry:FBSDKLoggingBehaviorAppEvents
|
||||||
@ -1181,7 +1298,7 @@ static NSString *g_overrideAppID = nil;
|
|||||||
FBSDKGraphRequest *request = [[FBSDKGraphRequest alloc] initWithGraphPath:[NSString stringWithFormat:@"%@/activities", appEventsState.appID]
|
FBSDKGraphRequest *request = [[FBSDKGraphRequest alloc] initWithGraphPath:[NSString stringWithFormat:@"%@/activities", appEventsState.appID]
|
||||||
parameters:postParameters
|
parameters:postParameters
|
||||||
tokenString:appEventsState.tokenString
|
tokenString:appEventsState.tokenString
|
||||||
HTTPMethod:@"POST"
|
HTTPMethod:FBSDKHTTPMethodPOST
|
||||||
flags:FBSDKGraphRequestFlagDoNotInvalidateTokenOnError | FBSDKGraphRequestFlagDisableErrorRecovery];
|
flags:FBSDKGraphRequestFlagDoNotInvalidateTokenOnError | FBSDKGraphRequestFlagDisableErrorRecovery];
|
||||||
|
|
||||||
[request startWithCompletionHandler:^(FBSDKGraphRequestConnection *connection, id result, NSError *error) {
|
[request startWithCompletionHandler:^(FBSDKGraphRequestConnection *connection, id result, NSError *error) {
|
||||||
@ -1297,7 +1414,7 @@ static NSString *g_overrideAppID = nil;
|
|||||||
// 3) if we have a user session token, then no need to send attribution ID / advertiser ID back as the udid parameter
|
// 3) if we have a user session token, then no need to send attribution ID / advertiser ID back as the udid parameter
|
||||||
// 4) otherwise, send back the udid parameter.
|
// 4) otherwise, send back the udid parameter.
|
||||||
|
|
||||||
if ([FBSDKAppEventsUtility advertisingTrackingStatus] == FBSDKAdvertisingTrackingDisallowed || [FBSDKSettings limitEventAndDataUsage]) {
|
if ([FBSDKAppEventsUtility advertisingTrackingStatus] == FBSDKAdvertisingTrackingDisallowed || FBSDKSettings.shouldLimitEventAndDataUsage) {
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -18,10 +18,12 @@
|
|||||||
|
|
||||||
#import <Foundation/Foundation.h>
|
#import <Foundation/Foundation.h>
|
||||||
|
|
||||||
#import "FBSDKLikeControl.h"
|
NS_ASSUME_NONNULL_BEGIN
|
||||||
|
|
||||||
@interface FBSDKLikeControl ()
|
@interface FBSDKMetadataIndexer : NSObject
|
||||||
|
|
||||||
- (NSDictionary *)analyticsParameters;
|
+ (void)enable;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_END
|
||||||
323
Example/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/AppEvents/Internal/AAM/FBSDKMetadataIndexer.m
generated
Normal file
323
Example/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/AppEvents/Internal/AAM/FBSDKMetadataIndexer.m
generated
Normal file
@ -0,0 +1,323 @@
|
|||||||
|
// 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 "FBSDKMetadataIndexer.h"
|
||||||
|
|
||||||
|
#import <objc/runtime.h>
|
||||||
|
#import <sys/sysctl.h>
|
||||||
|
#import <sys/utsname.h>
|
||||||
|
|
||||||
|
#import <UIKit/UIKit.h>
|
||||||
|
|
||||||
|
#import <FBSDKCoreKit/FBSDKCoreKit+Internal.h>
|
||||||
|
|
||||||
|
static const int FBSDKMetadataIndexerMaxTextLength = 100;
|
||||||
|
static const int FBSDKMetadataIndexerMaxIndicatorLength = 100;
|
||||||
|
static const int FBSDKMetadataIndexerMaxValue = 5;
|
||||||
|
|
||||||
|
static NSString * const FIELD_K = @"k";
|
||||||
|
static NSString * const FIELD_V = @"v";
|
||||||
|
static NSString * const FIELD_K_DELIMITER = @",";
|
||||||
|
|
||||||
|
FBSDKAppEventUserDataType FBSDKAppEventRule1 = @"r1";
|
||||||
|
FBSDKAppEventUserDataType FBSDKAppEventRule2 = @"r2";
|
||||||
|
|
||||||
|
static NSArray<FBSDKAppEventUserDataType> *FBSDKMetadataIndexerKeys;
|
||||||
|
static NSMutableDictionary<NSString *, NSDictionary<NSString *, NSString *> *> *_rules;
|
||||||
|
static NSMutableDictionary<NSString *, NSMutableArray<NSString *> *> *_store;
|
||||||
|
static dispatch_queue_t serialQueue;
|
||||||
|
|
||||||
|
@implementation FBSDKMetadataIndexer
|
||||||
|
|
||||||
|
+ (void)initialize
|
||||||
|
{
|
||||||
|
FBSDKMetadataIndexerKeys = @[FBSDKAppEventRule1, FBSDKAppEventRule2];
|
||||||
|
serialQueue = dispatch_queue_create("com.facebook.appevents.MetadataIndexer", DISPATCH_QUEUE_SERIAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (void)enable
|
||||||
|
{
|
||||||
|
if (FBSDKAdvertisingTrackingAllowed != [FBSDKAppEventsUtility advertisingTrackingStatus]) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
[FBSDKServerConfigurationManager loadServerConfigurationWithCompletionBlock:^(FBSDKServerConfiguration *serverConfiguration, NSError *error) {
|
||||||
|
if (error) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
[FBSDKMetadataIndexer setupWithRules:serverConfiguration.AAMRules];
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (void)setupWithRules:(NSDictionary<NSString *, id> * _Nullable)rules
|
||||||
|
{
|
||||||
|
if (0 == rules.count) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
static dispatch_once_t onceToken;
|
||||||
|
dispatch_once(&onceToken, ^{
|
||||||
|
[FBSDKMetadataIndexer constructRules:rules];
|
||||||
|
[FBSDKMetadataIndexer initStore];
|
||||||
|
|
||||||
|
BOOL isEnabled = NO;
|
||||||
|
for (NSString *key in FBSDKMetadataIndexerKeys) {
|
||||||
|
BOOL isRuleEnabled = (nil != [_rules objectForKey:key]);
|
||||||
|
if (isRuleEnabled) {
|
||||||
|
isEnabled = YES;
|
||||||
|
}
|
||||||
|
if (!isRuleEnabled) {
|
||||||
|
[_store removeObjectForKey:key];
|
||||||
|
[FBSDKUserDataStore setHashData:nil forType:key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isEnabled) {
|
||||||
|
[FBSDKMetadataIndexer setupMetadataIndexing];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (void)initStore
|
||||||
|
{
|
||||||
|
_store = [[NSMutableDictionary alloc] init];
|
||||||
|
for (NSString *key in FBSDKMetadataIndexerKeys) {
|
||||||
|
NSString *data = [FBSDKUserDataStore getHashedDataForType:key];
|
||||||
|
if (data.length > 0) {
|
||||||
|
_store[key] = [NSMutableArray arrayWithArray:[data componentsSeparatedByString:FIELD_K_DELIMITER]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (NSString *key in FBSDKMetadataIndexerKeys) {
|
||||||
|
if (!_store[key]) {
|
||||||
|
_store[key] = [[NSMutableArray alloc] init];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (void)constructRules:(NSDictionary<NSString *, id> * _Nullable)rules
|
||||||
|
{
|
||||||
|
if (!_rules) {
|
||||||
|
_rules = [[NSMutableDictionary alloc] init];
|
||||||
|
}
|
||||||
|
|
||||||
|
for (NSString *key in rules) {
|
||||||
|
NSDictionary<NSString *, NSString *> *value = [FBSDKTypeUtility dictionaryValue:rules[key]];
|
||||||
|
if (value && value[FIELD_K].length > 0 && value[FIELD_V].length > 0) {
|
||||||
|
_rules[key] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (void)setupMetadataIndexing
|
||||||
|
{
|
||||||
|
void (^block)(UIView *) = ^(UIView *view) {
|
||||||
|
// Indexing when the view is removed from window and conforms to UITextInput, and skip UIFieldEditor, which is an internval view of UITextField
|
||||||
|
if (![view window] && ![NSStringFromClass([view class]) isEqualToString:@"UIFieldEditor"] && [view conformsToProtocol:@protocol(UITextInput)]) {
|
||||||
|
NSString *text = [FBSDKViewHierarchy getText:view];
|
||||||
|
NSString *placeholder = [FBSDKViewHierarchy getHint:view];
|
||||||
|
BOOL secureTextEntry = [self checkSecureTextEntry:view];
|
||||||
|
NSArray<NSString *> *labels = [self getLabelsOfView:view];
|
||||||
|
UIKeyboardType keyboardType = [self getKeyboardType:view];
|
||||||
|
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void) {
|
||||||
|
[self getMetadataWithText:[self normalizedValue:text]
|
||||||
|
placeholder:[self normalizeField:placeholder]
|
||||||
|
labels:labels
|
||||||
|
secureTextEntry:secureTextEntry
|
||||||
|
inputType:keyboardType];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
[FBSDKSwizzler swizzleSelector:@selector(didMoveToWindow) onClass:[UIView class] withBlock:block named:@"metadataIndexingUIView"];
|
||||||
|
|
||||||
|
// iOS 12: UITextField implements didMoveToWindow without calling parent implementation
|
||||||
|
if (@available(iOS 12, *)) {
|
||||||
|
[FBSDKSwizzler swizzleSelector:@selector(didMoveToWindow) onClass:[UITextField class] withBlock:block named:@"metadataIndexingUITextField"];
|
||||||
|
} else {
|
||||||
|
[FBSDKSwizzler swizzleSelector:@selector(didMoveToWindow) onClass:[UIControl class] withBlock:block named:@"metadataIndexingUIControl"];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (NSArray<UIView *> *)getSiblingViewsOfView:(UIView *)view
|
||||||
|
{
|
||||||
|
NSObject *parent = [FBSDKViewHierarchy getParent:view];
|
||||||
|
if (parent) {
|
||||||
|
NSArray<id> *views = [FBSDKViewHierarchy getChildren:parent];
|
||||||
|
if (views) {
|
||||||
|
NSMutableArray<id> *siblings = [NSMutableArray arrayWithArray:views];
|
||||||
|
[siblings removeObject:view];
|
||||||
|
return [siblings copy];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (NSArray<NSString *> *)getLabelsOfView:(UIView *)view
|
||||||
|
{
|
||||||
|
NSMutableArray<NSString *> *labels = [[NSMutableArray alloc] init];
|
||||||
|
|
||||||
|
NSString *placeholder = [self normalizeField:[FBSDKViewHierarchy getHint:view]];
|
||||||
|
if (placeholder) {
|
||||||
|
[labels addObject:placeholder];
|
||||||
|
}
|
||||||
|
|
||||||
|
NSArray<id> *siblingViews = [self getSiblingViewsOfView:view];
|
||||||
|
for (id sibling in siblingViews) {
|
||||||
|
if ([sibling isKindOfClass:[UILabel class]]) {
|
||||||
|
NSString *text = [self normalizeField:[FBSDKViewHierarchy getText:sibling]];
|
||||||
|
if (text) {
|
||||||
|
[labels addObject:text];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return [labels copy];
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (BOOL)checkSecureTextEntry:(UIView *)view
|
||||||
|
{
|
||||||
|
if ([view isKindOfClass:[UITextField class]]) {
|
||||||
|
return ((UITextField *)view).secureTextEntry;
|
||||||
|
}
|
||||||
|
if ([view isKindOfClass:[UITextView class]]) {
|
||||||
|
return ((UITextView *)view).secureTextEntry;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (UIKeyboardType)getKeyboardType:(UIView *)view
|
||||||
|
{
|
||||||
|
if ([view isKindOfClass:[UITextField class]]) {
|
||||||
|
return ((UITextField *)view).keyboardType;
|
||||||
|
}
|
||||||
|
if ([view isKindOfClass:[UITextView class]]) {
|
||||||
|
return ((UITextView *)view).keyboardType;
|
||||||
|
}
|
||||||
|
|
||||||
|
return UIKeyboardTypeDefault;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (void)getMetadataWithText:(NSString *)text
|
||||||
|
placeholder:(NSString *)placeholder
|
||||||
|
labels:(NSArray<NSString *> *)labels
|
||||||
|
secureTextEntry:(BOOL)secureTextEntry
|
||||||
|
inputType:(UIKeyboardType)inputType
|
||||||
|
{
|
||||||
|
if (secureTextEntry ||
|
||||||
|
[placeholder containsString:@"password"] ||
|
||||||
|
text.length == 0 ||
|
||||||
|
text.length > FBSDKMetadataIndexerMaxTextLength ||
|
||||||
|
placeholder.length >= FBSDKMetadataIndexerMaxIndicatorLength) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (NSString *key in _rules) {
|
||||||
|
NSDictionary<NSString *, NSString *> *rule = _rules[key];
|
||||||
|
BOOL isRuleKMatched = [self checkMetadataHint:placeholder matchRuleK:rule[FIELD_K]]
|
||||||
|
|| [self checkMetadataLabels:labels matchRuleK:rule[FIELD_K]];
|
||||||
|
BOOL isRuleVMatched = [self checkMetadataText:text matchRuleV:rule[FIELD_V]];
|
||||||
|
if (isRuleKMatched && isRuleVMatched) {
|
||||||
|
[FBSDKMetadataIndexer checkAndAppendData:text forKey:key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - Helper Methods
|
||||||
|
|
||||||
|
+ (void)checkAndAppendData:(NSString *)data
|
||||||
|
forKey:(NSString *)key
|
||||||
|
{
|
||||||
|
NSString *hashData = [FBSDKUtility SHA256Hash:data];
|
||||||
|
dispatch_async(serialQueue, ^{
|
||||||
|
if (hashData.length == 0 || [_store[key] containsObject:hashData]) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (_store[key].count >= FBSDKMetadataIndexerMaxValue) {
|
||||||
|
[_store[key] removeObjectAtIndex:0];
|
||||||
|
}
|
||||||
|
[_store[key] addObject:hashData];
|
||||||
|
[FBSDKUserDataStore setHashData:[_store[key] componentsJoinedByString:@","]
|
||||||
|
forType:key];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (BOOL)checkMetadataLabels:(NSArray<NSString *> *)labels
|
||||||
|
matchRuleK:(NSString *)ruleK
|
||||||
|
{
|
||||||
|
for (NSString *label in labels) {
|
||||||
|
if ([self checkMetadataHint:label matchRuleK:ruleK]) {
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (BOOL)checkMetadataHint:(NSString *)hint
|
||||||
|
matchRuleK:(NSString *)ruleK
|
||||||
|
{
|
||||||
|
if (hint.length > 0 && ruleK) {
|
||||||
|
NSArray<NSString *> *items = [ruleK componentsSeparatedByString:@","];
|
||||||
|
for (NSString *item in items) {
|
||||||
|
if ([hint containsString:item]) {
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (BOOL)checkMetadataText:(NSString *)text
|
||||||
|
matchRuleV:(NSString *)ruleV
|
||||||
|
{
|
||||||
|
if (text.length > 0 && ruleV) {
|
||||||
|
NSRegularExpression *regex = [[NSRegularExpression alloc] initWithPattern:ruleV
|
||||||
|
options:NSRegularExpressionCaseInsensitive
|
||||||
|
error:nil];
|
||||||
|
NSUInteger matches = [regex numberOfMatchesInString:text options:0 range:NSMakeRange(0, text.length)];
|
||||||
|
|
||||||
|
NSString *prunedText = [[text componentsSeparatedByCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@"+- ()."]] componentsJoinedByString:@""];
|
||||||
|
NSUInteger prunedMatches = [regex numberOfMatchesInString:prunedText options:0 range:NSMakeRange(0, prunedText.length)];
|
||||||
|
|
||||||
|
return matches > 0 || prunedMatches > 0;
|
||||||
|
}
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (NSString *)normalizeField:(NSString *)field
|
||||||
|
{
|
||||||
|
if (!field) {
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"[_-]|\\s"
|
||||||
|
options:NSRegularExpressionCaseInsensitive
|
||||||
|
error:nil];
|
||||||
|
return [regex stringByReplacingMatchesInString:field
|
||||||
|
options:0
|
||||||
|
range:NSMakeRange(0, field.length)
|
||||||
|
withTemplate:@""].lowercaseString;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (NSString *)normalizedValue:(NSString *)value
|
||||||
|
{
|
||||||
|
if (!value) {
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
return [value stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]].lowercaseString;
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
@ -18,10 +18,17 @@
|
|||||||
|
|
||||||
#import <Foundation/Foundation.h>
|
#import <Foundation/Foundation.h>
|
||||||
|
|
||||||
typedef void(^FBSDKCodelessSettingLoadBlock)(BOOL isCodelessSetupEnabled, NSError *error);
|
NS_ASSUME_NONNULL_BEGIN
|
||||||
|
|
||||||
|
typedef void(^FBSDKCodelessSettingLoadBlock)(BOOL isCodelessSetupEnabled, NSError *_Nullable error);
|
||||||
|
|
||||||
|
NS_SWIFT_NAME(CodelessIndexer)
|
||||||
@interface FBSDKCodelessIndexer : NSObject
|
@interface FBSDKCodelessIndexer : NSObject
|
||||||
|
|
||||||
+ (NSString *)extInfo;
|
@property (class, nonatomic, copy, readonly) NSString *extInfo;
|
||||||
|
|
||||||
|
+ (void)enable;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_END
|
||||||
@ -24,16 +24,16 @@
|
|||||||
|
|
||||||
#import <UIKit/UIKit.h>
|
#import <UIKit/UIKit.h>
|
||||||
|
|
||||||
|
#import <FBSDKCoreKit/FBSDKCoreKit+Internal.h>
|
||||||
#import <FBSDKCoreKit/FBSDKGraphRequest.h>
|
#import <FBSDKCoreKit/FBSDKGraphRequest.h>
|
||||||
#import <FBSDKCoreKit/FBSDKSettings.h>
|
#import <FBSDKCoreKit/FBSDKSettings.h>
|
||||||
|
|
||||||
#import "FBSDKCoreKit+Internal.h"
|
|
||||||
|
|
||||||
@implementation FBSDKCodelessIndexer
|
@implementation FBSDKCodelessIndexer
|
||||||
|
|
||||||
static BOOL _isCodelessIndexing;
|
static BOOL _isCodelessIndexing;
|
||||||
static BOOL _isCheckingSession;
|
static BOOL _isCheckingSession;
|
||||||
static BOOL _isCodelessIndexingEnabled;
|
static BOOL _isCodelessIndexingEnabled;
|
||||||
|
static BOOL _isGestureSet;
|
||||||
|
|
||||||
static NSMutableDictionary<NSString *, id> *_codelessSetting;
|
static NSMutableDictionary<NSString *, id> *_codelessSetting;
|
||||||
static const NSTimeInterval kTimeout = 4.0;
|
static const NSTimeInterval kTimeout = 4.0;
|
||||||
@ -42,8 +42,11 @@ static NSString *_deviceSessionID;
|
|||||||
static NSTimer *_appIndexingTimer;
|
static NSTimer *_appIndexingTimer;
|
||||||
static NSString *_lastTreeHash;
|
static NSString *_lastTreeHash;
|
||||||
|
|
||||||
+ (void)load
|
+ (void)enable
|
||||||
{
|
{
|
||||||
|
if (_isGestureSet) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
#if TARGET_OS_SIMULATOR
|
#if TARGET_OS_SIMULATOR
|
||||||
[self setupGesture];
|
[self setupGesture];
|
||||||
#else
|
#else
|
||||||
@ -138,6 +141,7 @@ static NSString *_lastTreeHash;
|
|||||||
|
|
||||||
+ (void)setupGesture
|
+ (void)setupGesture
|
||||||
{
|
{
|
||||||
|
_isGestureSet = YES;
|
||||||
[UIApplication sharedApplication].applicationSupportsShakeToEdit = YES;
|
[UIApplication sharedApplication].applicationSupportsShakeToEdit = YES;
|
||||||
Class class = [UIApplication class];
|
Class class = [UIApplication class];
|
||||||
|
|
||||||
@ -160,8 +164,8 @@ static NSString *_lastTreeHash;
|
|||||||
FBSDKGraphRequest *request = [[FBSDKGraphRequest alloc]
|
FBSDKGraphRequest *request = [[FBSDKGraphRequest alloc]
|
||||||
initWithGraphPath:[NSString stringWithFormat:@"%@/%@",
|
initWithGraphPath:[NSString stringWithFormat:@"%@/%@",
|
||||||
[FBSDKSettings appID], CODELESS_INDEXING_SESSION_ENDPOINT]
|
[FBSDKSettings appID], CODELESS_INDEXING_SESSION_ENDPOINT]
|
||||||
parameters: parameters
|
parameters:parameters
|
||||||
HTTPMethod:@"POST"];
|
HTTPMethod:FBSDKHTTPMethodPOST];
|
||||||
[request startWithCompletionHandler:^(FBSDKGraphRequestConnection *connection, id result, NSError *error) {
|
[request startWithCompletionHandler:^(FBSDKGraphRequestConnection *connection, id result, NSError *error) {
|
||||||
_isCheckingSession = NO;
|
_isCheckingSession = NO;
|
||||||
if ([result isKindOfClass:[NSDictionary class]]) {
|
if ([result isKindOfClass:[NSDictionary class]]) {
|
||||||
@ -213,13 +217,13 @@ static NSString *_lastTreeHash;
|
|||||||
localeString = [NSString stringWithFormat:@"%@_%@", languageCode, countryCode];
|
localeString = [NSString stringWithFormat:@"%@_%@", languageCode, countryCode];
|
||||||
}
|
}
|
||||||
|
|
||||||
NSString *extinfo = [FBSDKInternalUtility JSONStringForObject:@[machine,
|
NSString *extinfo = [FBSDKBasicUtility JSONStringForObject:@[machine,
|
||||||
advertiserID,
|
advertiserID,
|
||||||
debugStatus,
|
debugStatus,
|
||||||
isSimulator,
|
isSimulator,
|
||||||
localeString]
|
localeString]
|
||||||
error:NULL
|
error:NULL
|
||||||
invalidObjectHandler:NULL];
|
invalidObjectHandler:NULL];
|
||||||
|
|
||||||
return extinfo ?: @"";
|
return extinfo ?: @"";
|
||||||
}
|
}
|
||||||
@ -289,7 +293,7 @@ static NSString *_lastTreeHash;
|
|||||||
CODELESS_INDEXING_PLATFORM_KEY: @"iOS",
|
CODELESS_INDEXING_PLATFORM_KEY: @"iOS",
|
||||||
CODELESS_INDEXING_SESSION_ID_KEY: [self currentSessionDeviceID]
|
CODELESS_INDEXING_SESSION_ID_KEY: [self currentSessionDeviceID]
|
||||||
}
|
}
|
||||||
HTTPMethod:@"POST"];
|
HTTPMethod:FBSDKHTTPMethodPOST];
|
||||||
_isCodelessIndexing = YES;
|
_isCodelessIndexing = YES;
|
||||||
[request startWithCompletionHandler:^(FBSDKGraphRequestConnection *connection, id result, NSError *error) {
|
[request startWithCompletionHandler:^(FBSDKGraphRequestConnection *connection, id result, NSError *error) {
|
||||||
_isCodelessIndexing = NO;
|
_isCodelessIndexing = NO;
|
||||||
@ -18,6 +18,7 @@
|
|||||||
|
|
||||||
#import <Foundation/Foundation.h>
|
#import <Foundation/Foundation.h>
|
||||||
|
|
||||||
|
NS_SWIFT_NAME(CodelessParameterComponent)
|
||||||
@interface FBSDKCodelessParameterComponent : NSObject
|
@interface FBSDKCodelessParameterComponent : NSObject
|
||||||
|
|
||||||
@property (nonatomic, copy, readonly) NSString *name;
|
@property (nonatomic, copy, readonly) NSString *name;
|
||||||
@ -27,6 +27,7 @@ typedef NS_OPTIONS(int, FBSDKCodelessMatchBitmaskField)
|
|||||||
FBSDKCodelessMatchBitmaskFieldHint = 1 << 4
|
FBSDKCodelessMatchBitmaskFieldHint = 1 << 4
|
||||||
};
|
};
|
||||||
|
|
||||||
|
NS_SWIFT_NAME(CodelessPathComponent)
|
||||||
@interface FBSDKCodelessPathComponent : NSObject
|
@interface FBSDKCodelessPathComponent : NSObject
|
||||||
|
|
||||||
@property (nonatomic, copy, readonly) NSString *className;
|
@property (nonatomic, copy, readonly) NSString *className;
|
||||||
@ -20,6 +20,7 @@
|
|||||||
#import <Foundation/Foundation.h>
|
#import <Foundation/Foundation.h>
|
||||||
#import <UIKit/UIKit.h>
|
#import <UIKit/UIKit.h>
|
||||||
|
|
||||||
|
NS_SWIFT_NAME(EventBinding)
|
||||||
@interface FBSDKEventBinding : NSObject
|
@interface FBSDKEventBinding : NSObject
|
||||||
|
|
||||||
@property (nonatomic, copy, readonly) NSString *eventName;
|
@property (nonatomic, copy, readonly) NSString *eventName;
|
||||||
@ -19,6 +19,7 @@
|
|||||||
#import "FBSDKEventBinding.h"
|
#import "FBSDKEventBinding.h"
|
||||||
|
|
||||||
#import <FBSDKCoreKit/FBSDKAppEvents.h>
|
#import <FBSDKCoreKit/FBSDKAppEvents.h>
|
||||||
|
#import <FBSDKCoreKit/FBSDKUtility.h>
|
||||||
|
|
||||||
#import "FBSDKAppEventsUtility.h"
|
#import "FBSDKAppEventsUtility.h"
|
||||||
#import "FBSDKCodelessMacros.h"
|
#import "FBSDKCodelessMacros.h"
|
||||||
@ -175,7 +176,8 @@ pathComponent:(FBSDKCodelessPathComponent *)component
|
|||||||
if ((pathComponent.matchBitmask & FBSDKCodelessMatchBitmaskFieldText) > 0) {
|
if ((pathComponent.matchBitmask & FBSDKCodelessMatchBitmaskFieldText) > 0) {
|
||||||
NSString *text = viewPathComponent.text;
|
NSString *text = viewPathComponent.text;
|
||||||
BOOL match = ((text.length == 0 && pathComponent.text.length == 0)
|
BOOL match = ((text.length == 0 && pathComponent.text.length == 0)
|
||||||
|| [text isEqualToString:pathComponent.text]);
|
|| [text isEqualToString:pathComponent.text]
|
||||||
|
|| [[FBSDKUtility SHA256Hash:text] isEqualToString:pathComponent.text]);
|
||||||
if (!match) {
|
if (!match) {
|
||||||
return NO;
|
return NO;
|
||||||
}
|
}
|
||||||
@ -189,7 +191,8 @@ pathComponent:(FBSDKCodelessPathComponent *)component
|
|||||||
if ((pathComponent.matchBitmask & FBSDKCodelessMatchBitmaskFieldHint) > 0) {
|
if ((pathComponent.matchBitmask & FBSDKCodelessMatchBitmaskFieldHint) > 0) {
|
||||||
NSString *hint = viewPathComponent.hint;
|
NSString *hint = viewPathComponent.hint;
|
||||||
BOOL match = ((hint.length == 0 && pathComponent.hint.length == 0)
|
BOOL match = ((hint.length == 0 && pathComponent.hint.length == 0)
|
||||||
|| [hint isEqualToString:pathComponent.hint]);
|
|| [hint isEqualToString:pathComponent.hint]
|
||||||
|
|| [[FBSDKUtility SHA256Hash:hint] isEqualToString:pathComponent.hint]);
|
||||||
if (!match) {
|
if (!match) {
|
||||||
return NO;
|
return NO;
|
||||||
}
|
}
|
||||||
@ -18,10 +18,10 @@
|
|||||||
|
|
||||||
#import <Foundation/Foundation.h>
|
#import <Foundation/Foundation.h>
|
||||||
|
|
||||||
|
NS_SWIFT_NAME(EventBindingManager)
|
||||||
@interface FBSDKEventBindingManager : NSObject
|
@interface FBSDKEventBindingManager : NSObject
|
||||||
|
|
||||||
- (FBSDKEventBindingManager*)initWithJSON:(NSDictionary*)dict;
|
- (FBSDKEventBindingManager*)initWithJSON:(NSDictionary*)dict;
|
||||||
- (void)start;
|
|
||||||
- (void)updateBindings:(NSArray *)bindings;
|
- (void)updateBindings:(NSArray *)bindings;
|
||||||
+ (NSArray *)parseArray:(NSArray *)array;
|
+ (NSArray *)parseArray:(NSArray *)array;
|
||||||
|
|
||||||
@ -38,7 +38,11 @@
|
|||||||
#define ReactNativeClassRCTTouchHandler "RCTTouchHandler"
|
#define ReactNativeClassRCTTouchHandler "RCTTouchHandler"
|
||||||
|
|
||||||
static void fb_dispatch_on_main_thread(dispatch_block_t block) {
|
static void fb_dispatch_on_main_thread(dispatch_block_t block) {
|
||||||
dispatch_async(dispatch_get_main_queue(), block);
|
if ([NSThread isMainThread]) {
|
||||||
|
block();
|
||||||
|
} else {
|
||||||
|
dispatch_async(dispatch_get_main_queue(), block);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void fb_dispatch_on_default_thread(dispatch_block_t block) {
|
static void fb_dispatch_on_default_thread(dispatch_block_t block) {
|
||||||
@ -122,6 +126,11 @@ static void fb_dispatch_on_default_thread(dispatch_block_t block) {
|
|||||||
if (isStarted) {
|
if (isStarted) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (0 == eventBindings.count) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
isStarted = YES;
|
isStarted = YES;
|
||||||
|
|
||||||
void (^blockToWindow)(id view) = ^(id view) {
|
void (^blockToWindow)(id view) = ^(id view) {
|
||||||
@ -382,6 +391,10 @@ static void fb_dispatch_on_default_thread(dispatch_block_t block) {
|
|||||||
- (void)updateBindings:(NSArray *)bindings {
|
- (void)updateBindings:(NSArray *)bindings {
|
||||||
eventBindings = bindings;
|
eventBindings = bindings;
|
||||||
[reactBindings removeAllObjects];
|
[reactBindings removeAllObjects];
|
||||||
|
if (!isStarted) {
|
||||||
|
[self start];
|
||||||
|
}
|
||||||
|
|
||||||
fb_dispatch_on_main_thread(^{
|
fb_dispatch_on_main_thread(^{
|
||||||
[self rematchBindings];
|
[self rematchBindings];
|
||||||
});
|
});
|
||||||
@ -19,6 +19,7 @@
|
|||||||
#import <Foundation/Foundation.h>
|
#import <Foundation/Foundation.h>
|
||||||
#import <UIKit/UIKit.h>
|
#import <UIKit/UIKit.h>
|
||||||
|
|
||||||
|
NS_SWIFT_NAME(ViewHierarchy)
|
||||||
@interface FBSDKViewHierarchy : NSObject
|
@interface FBSDKViewHierarchy : NSObject
|
||||||
|
|
||||||
+ (NSObject *)getParent:(NSObject *)obj;
|
+ (NSObject *)getParent:(NSObject *)obj;
|
||||||
@ -22,32 +22,33 @@
|
|||||||
|
|
||||||
#import <QuartzCore/QuartzCore.h>
|
#import <QuartzCore/QuartzCore.h>
|
||||||
|
|
||||||
|
#import <FBSDKCoreKit/FBSDKCoreKit+Internal.h>
|
||||||
|
|
||||||
#import "FBSDKCodelessMacros.h"
|
#import "FBSDKCodelessMacros.h"
|
||||||
#import "FBSDKCodelessPathComponent.h"
|
#import "FBSDKCodelessPathComponent.h"
|
||||||
#import "FBSDKCoreKit+Internal.h"
|
|
||||||
|
|
||||||
#define MAX_VIEW_HIERARCHY_LEVEL 35
|
#define MAX_VIEW_HIERARCHY_LEVEL 35
|
||||||
|
|
||||||
typedef NS_ENUM(NSUInteger, FBCodelessClassBitmask) {
|
typedef NS_ENUM(NSUInteger, FBCodelessClassBitmask) {
|
||||||
/*! Indicates that the class is subclass of UIControl */
|
/** Indicates that the class is subclass of UIControl */
|
||||||
FBCodelessClassBitmaskUIControl = 1 << 3,
|
FBCodelessClassBitmaskUIControl = 1 << 3,
|
||||||
/*! Indicates that the class is subclass of UIControl */
|
/** Indicates that the class is subclass of UIControl */
|
||||||
FBCodelessClassBitmaskUIButton = 1 << 4,
|
FBCodelessClassBitmaskUIButton = 1 << 4,
|
||||||
/*! Indicates that the class is ReactNative Button */
|
/** Indicates that the class is ReactNative Button */
|
||||||
FBCodelessClassBitmaskReactNativeButton = 1 << 6,
|
FBCodelessClassBitmaskReactNativeButton = 1 << 6,
|
||||||
/*! Indicates that the class is UITableViewCell */
|
/** Indicates that the class is UITableViewCell */
|
||||||
FBCodelessClassBitmaskUITableViewCell = 1 << 7,
|
FBCodelessClassBitmaskUITableViewCell = 1 << 7,
|
||||||
/*! Indicates that the class is UICollectionViewCell */
|
/** Indicates that the class is UICollectionViewCell */
|
||||||
FBCodelessClassBitmaskUICollectionViewCell = 1 << 8,
|
FBCodelessClassBitmaskUICollectionViewCell = 1 << 8,
|
||||||
/*! Indicates that the class is UILabel */
|
/** Indicates that the class is UILabel */
|
||||||
FBCodelessClassBitmaskLabel = 1 << 10,
|
FBCodelessClassBitmaskLabel = 1 << 10,
|
||||||
/*! Indicates that the class is UITextView or UITextField*/
|
/** Indicates that the class is UITextView or UITextField*/
|
||||||
FBCodelessClassBitmaskInput = 1 << 11,
|
FBCodelessClassBitmaskInput = 1 << 11,
|
||||||
/*! Indicates that the class is UIPicker*/
|
/** Indicates that the class is UIPicker*/
|
||||||
FBCodelessClassBitmaskPicker = 1 << 12,
|
FBCodelessClassBitmaskPicker = 1 << 12,
|
||||||
/*! Indicates that the class is UISwitch*/
|
/** Indicates that the class is UISwitch*/
|
||||||
FBCodelessClassBitmaskSwitch = 1 << 13,
|
FBCodelessClassBitmaskSwitch = 1 << 13,
|
||||||
/*! Indicates that the class is UIViewController*/
|
/** Indicates that the class is UIViewController*/
|
||||||
FBCodelessClassBitmaskUIViewController = 1 << 17,
|
FBCodelessClassBitmaskUIViewController = 1 << 17,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -268,6 +269,11 @@ typedef NS_ENUM(NSUInteger, FBCodelessClassBitmask) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
+ (NSMutableDictionary<NSString *, id> *)getDetailAttributesOf:(NSObject *)obj
|
+ (NSMutableDictionary<NSString *, id> *)getDetailAttributesOf:(NSObject *)obj
|
||||||
|
{
|
||||||
|
return [self getDetailAttributesOf:obj WithHash:YES];
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (NSMutableDictionary<NSString *, id> *)getDetailAttributesOf:(NSObject *)obj WithHash:(BOOL)hash
|
||||||
{
|
{
|
||||||
if (!obj) {
|
if (!obj) {
|
||||||
return nil;
|
return nil;
|
||||||
@ -308,6 +314,12 @@ typedef NS_ENUM(NSUInteger, FBCodelessClassBitmask) {
|
|||||||
result[CODELESS_VIEW_TREE_TEXT_STYLE_KEY] = textStyle;
|
result[CODELESS_VIEW_TREE_TEXT_STYLE_KEY] = textStyle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (hash) {
|
||||||
|
// hash text and hint
|
||||||
|
result[CODELESS_VIEW_TREE_TEXT_KEY] = [FBSDKUtility SHA256Hash:result[CODELESS_VIEW_TREE_TEXT_KEY]];
|
||||||
|
result[CODELESS_VIEW_TREE_HINT_KEY] = [FBSDKUtility SHA256Hash:result[CODELESS_VIEW_TREE_HINT_KEY]];
|
||||||
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -357,9 +369,9 @@ typedef NS_ENUM(NSUInteger, FBCodelessClassBitmask) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (titles.count > 0) {
|
if (titles.count > 0) {
|
||||||
text = [FBSDKInternalUtility JSONStringForObject:titles
|
text = [FBSDKBasicUtility JSONStringForObject:titles
|
||||||
error:NULL
|
error:NULL
|
||||||
invalidObjectHandler:NULL];
|
invalidObjectHandler:NULL];
|
||||||
}
|
}
|
||||||
} else if ([obj isKindOfClass:[UIDatePicker class]]) {
|
} else if ([obj isKindOfClass:[UIDatePicker class]]) {
|
||||||
UIDatePicker *picker = (UIDatePicker *)obj;
|
UIDatePicker *picker = (UIDatePicker *)obj;
|
||||||
@ -24,8 +24,6 @@
|
|||||||
|
|
||||||
// Internally known event names
|
// Internally known event names
|
||||||
|
|
||||||
FOUNDATION_EXPORT NSString *const FBSDKAppEventNamePurchased;
|
|
||||||
|
|
||||||
/** Use to log that the share dialog was launched */
|
/** Use to log that the share dialog was launched */
|
||||||
FOUNDATION_EXPORT NSString *const FBSDKAppEventNameShareSheetLaunch;
|
FOUNDATION_EXPORT NSString *const FBSDKAppEventNameShareSheetLaunch;
|
||||||
|
|
||||||
@ -41,10 +39,10 @@ FOUNDATION_EXPORT NSString *const FBSDKAppEventNamePermissionsUIDismiss;
|
|||||||
/** Use to log that the login view was used */
|
/** Use to log that the login view was used */
|
||||||
FOUNDATION_EXPORT NSString *const FBSDKAppEventNameLoginViewUsage;
|
FOUNDATION_EXPORT NSString *const FBSDKAppEventNameLoginViewUsage;
|
||||||
|
|
||||||
/*! Use to log that the share tray launched. */
|
/** Use to log that the share tray launched. */
|
||||||
FOUNDATION_EXPORT NSString *const FBSDKAppEventNameShareTrayDidLaunch;
|
FOUNDATION_EXPORT NSString *const FBSDKAppEventNameShareTrayDidLaunch;
|
||||||
|
|
||||||
/*! Use to log that the person selected a sharing target. */
|
/** Use to log that the person selected a sharing target. */
|
||||||
FOUNDATION_EXPORT NSString *const FBSDKAppEventNameShareTrayDidSelectActivity;
|
FOUNDATION_EXPORT NSString *const FBSDKAppEventNameShareTrayDidSelectActivity;
|
||||||
|
|
||||||
// Internally known event parameters
|
// Internally known event parameters
|
||||||
@ -105,7 +103,7 @@ FOUNDATION_EXPORT NSString *const FBSDKAppEventNameFBSDKLiveStreamingMic;
|
|||||||
FOUNDATION_EXPORT NSString *const FBSDKAppEventNameFBSDKLiveStreamingCamera;
|
FOUNDATION_EXPORT NSString *const FBSDKAppEventNameFBSDKLiveStreamingCamera;
|
||||||
|
|
||||||
/** Use to log the results of a share dialog */
|
/** Use to log the results of a share dialog */
|
||||||
FOUNDATION_EXPORT NSString *const FBSDLAppEventNameFBSDKEventShareDialogResult;
|
FOUNDATION_EXPORT NSString *const FBSDKAppEventNameFBSDKEventShareDialogResult;
|
||||||
FOUNDATION_EXPORT NSString *const FBSDKAppEventNameFBSDKEventMessengerShareDialogResult;
|
FOUNDATION_EXPORT NSString *const FBSDKAppEventNameFBSDKEventMessengerShareDialogResult;
|
||||||
FOUNDATION_EXPORT NSString *const FBSDKAppEventNameFBSDKEventAppInviteShareDialogResult;
|
FOUNDATION_EXPORT NSString *const FBSDKAppEventNameFBSDKEventAppInviteShareDialogResult;
|
||||||
|
|
||||||
@ -118,11 +116,11 @@ FOUNDATION_EXPORT NSString *const FBSDKAppEventParameterDialogShareContentType;
|
|||||||
FOUNDATION_EXPORT NSString *const FBSDKAppEventParameterDialogShareContentUUID;
|
FOUNDATION_EXPORT NSString *const FBSDKAppEventParameterDialogShareContentUUID;
|
||||||
FOUNDATION_EXPORT NSString *const FBSDKAppEventParameterDialogShareContentPageID;
|
FOUNDATION_EXPORT NSString *const FBSDKAppEventParameterDialogShareContentPageID;
|
||||||
|
|
||||||
/*! Use to log parameters for share tray use */
|
/** Use to log parameters for share tray use */
|
||||||
FOUNDATION_EXPORT NSString *const FBSDKAppEventParameterShareTrayActivityName;
|
FOUNDATION_EXPORT NSString *const FBSDKAppEventParameterShareTrayActivityName;
|
||||||
FOUNDATION_EXPORT NSString *const FBSDKAppEventParameterShareTrayResult;
|
FOUNDATION_EXPORT NSString *const FBSDKAppEventParameterShareTrayResult;
|
||||||
|
|
||||||
/*! Use to log parameters for live streaming*/
|
/** Use to log parameters for live streaming*/
|
||||||
FOUNDATION_EXPORT NSString *const FBSDKAppEventParameterLiveStreamingPrevStatus;
|
FOUNDATION_EXPORT NSString *const FBSDKAppEventParameterLiveStreamingPrevStatus;
|
||||||
FOUNDATION_EXPORT NSString *const FBSDKAppEventParameterLiveStreamingStatus;
|
FOUNDATION_EXPORT NSString *const FBSDKAppEventParameterLiveStreamingStatus;
|
||||||
FOUNDATION_EXPORT NSString *const FBSDKAppEventParameterLiveStreamingError;
|
FOUNDATION_EXPORT NSString *const FBSDKAppEventParameterLiveStreamingError;
|
||||||
@ -199,12 +197,40 @@ FOUNDATION_EXPORT NSString *const FBSDKAppEventsWKWebViewMessagesPixelIDKey;
|
|||||||
|
|
||||||
@interface FBSDKAppEvents (Internal)
|
@interface FBSDKAppEvents (Internal)
|
||||||
|
|
||||||
|
@property (class, nonatomic, strong, readonly) FBSDKAppEvents *singleton;
|
||||||
|
|
||||||
|
+ (void)logInternalEvent:(FBSDKAppEventName)eventName
|
||||||
|
isImplicitlyLogged:(BOOL)isImplicitlyLogged;
|
||||||
|
|
||||||
|
+ (void)logInternalEvent:(FBSDKAppEventName)eventName
|
||||||
|
valueToSum:(double)valueToSum
|
||||||
|
isImplicitlyLogged:(BOOL)isImplicitlyLogged;
|
||||||
|
|
||||||
|
+ (void)logInternalEvent:(FBSDKAppEventName)eventName
|
||||||
|
parameters:(NSDictionary *)parameters
|
||||||
|
isImplicitlyLogged:(BOOL)isImplicitlyLogged;
|
||||||
|
|
||||||
|
+ (void)logInternalEvent:(FBSDKAppEventName)eventName
|
||||||
|
parameters:(NSDictionary *)parameters
|
||||||
|
isImplicitlyLogged:(BOOL)isImplicitlyLogged
|
||||||
|
accessToken:(FBSDKAccessToken *)accessToken;
|
||||||
|
|
||||||
|
+ (void)logInternalEvent:(FBSDKAppEventName)eventName
|
||||||
|
valueToSum:(double)valueToSum
|
||||||
|
parameters:(NSDictionary *)parameters
|
||||||
|
isImplicitlyLogged:(BOOL)isImplicitlyLogged;
|
||||||
|
|
||||||
|
+ (void)logInternalEvent:(NSString *)eventName
|
||||||
|
valueToSum:(NSNumber *)valueToSum
|
||||||
|
parameters:(NSDictionary *)parameters
|
||||||
|
isImplicitlyLogged:(BOOL)isImplicitlyLogged
|
||||||
|
accessToken:(FBSDKAccessToken *)accessToken;
|
||||||
|
|
||||||
+ (void)logImplicitEvent:(NSString *)eventName
|
+ (void)logImplicitEvent:(NSString *)eventName
|
||||||
valueToSum:(NSNumber *)valueToSum
|
valueToSum:(NSNumber *)valueToSum
|
||||||
parameters:(NSDictionary *)parameters
|
parameters:(NSDictionary *)parameters
|
||||||
accessToken:(FBSDKAccessToken *)accessToken;
|
accessToken:(FBSDKAccessToken *)accessToken;
|
||||||
|
|
||||||
+ (FBSDKAppEvents *)singleton;
|
|
||||||
- (void)flushForReason:(FBSDKAppEventsFlushReason)flushReason;
|
- (void)flushForReason:(FBSDKAppEventsFlushReason)flushReason;
|
||||||
- (void)registerNotifications;
|
- (void)registerNotifications;
|
||||||
|
|
||||||
@ -18,6 +18,7 @@
|
|||||||
|
|
||||||
#import <Foundation/Foundation.h>
|
#import <Foundation/Foundation.h>
|
||||||
|
|
||||||
|
NS_SWIFT_NAME(AppEventsDeviceInfo)
|
||||||
@interface FBSDKAppEventsDeviceInfo : NSObject
|
@interface FBSDKAppEventsDeviceInfo : NSObject
|
||||||
|
|
||||||
+ (void)extendDictionaryWithDeviceInfo:(NSMutableDictionary *)dictionary;
|
+ (void)extendDictionaryWithDeviceInfo:(NSMutableDictionary *)dictionary;
|
||||||
@ -25,6 +25,7 @@
|
|||||||
#import <CoreTelephony/CTCarrier.h>
|
#import <CoreTelephony/CTCarrier.h>
|
||||||
#import <CoreTelephony/CTTelephonyNetworkInfo.h>
|
#import <CoreTelephony/CTTelephonyNetworkInfo.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#import <Foundation/Foundation.h>
|
#import <Foundation/Foundation.h>
|
||||||
#import <UIKit/UIKit.h>
|
#import <UIKit/UIKit.h>
|
||||||
|
|
||||||
@ -228,7 +229,7 @@ static const u_int FB_GIGABYTE = 1024 * 1024 * 1024; // bytes
|
|||||||
_timeZoneName ?: @""
|
_timeZoneName ?: @""
|
||||||
];
|
];
|
||||||
|
|
||||||
return [FBSDKInternalUtility JSONStringForObject:arr error:NULL invalidObjectHandler:NULL];
|
return [FBSDKBasicUtility JSONStringForObject:arr error:NULL invalidObjectHandler:NULL];
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark - Helper Methods
|
#pragma mark - Helper Methods
|
||||||
@ -19,13 +19,14 @@
|
|||||||
#import <Foundation/Foundation.h>
|
#import <Foundation/Foundation.h>
|
||||||
|
|
||||||
// this type is not thread safe.
|
// this type is not thread safe.
|
||||||
|
NS_SWIFT_NAME(AppEventsState)
|
||||||
@interface FBSDKAppEventsState : NSObject<NSCopying, NSSecureCoding>
|
@interface FBSDKAppEventsState : NSObject<NSCopying, NSSecureCoding>
|
||||||
|
|
||||||
@property (nonatomic, readonly, copy) NSArray *events;
|
@property (nonatomic, readonly, copy) NSArray *events;
|
||||||
@property (nonatomic, readonly, assign) NSUInteger numSkipped;
|
@property (nonatomic, readonly, assign) NSUInteger numSkipped;
|
||||||
@property (nonatomic, readonly, copy) NSString *tokenString;
|
@property (nonatomic, readonly, copy) NSString *tokenString;
|
||||||
@property (nonatomic, readonly, copy) NSString *appID;
|
@property (nonatomic, readonly, copy) NSString *appID;
|
||||||
@property (nonatomic, readonly) BOOL areAllEventsImplicit;
|
@property (nonatomic, readonly, getter=areAllEventsImplicit) BOOL allEventsImplicit;
|
||||||
|
|
||||||
- (instancetype)init NS_UNAVAILABLE;
|
- (instancetype)init NS_UNAVAILABLE;
|
||||||
+ (instancetype)new NS_UNAVAILABLE;
|
+ (instancetype)new NS_UNAVAILABLE;
|
||||||
@ -18,7 +18,8 @@
|
|||||||
|
|
||||||
#import "FBSDKAppEventsState.h"
|
#import "FBSDKAppEventsState.h"
|
||||||
|
|
||||||
#import "FBSDKInternalUtility.h"
|
#import "FBSDKBasicUtility.h"
|
||||||
|
#import "FBSDKRestrictiveDataFilterManager.h"
|
||||||
|
|
||||||
#define FBSDK_APPEVENTSTATE_ISIMPLICIT_KEY @"isImplicit"
|
#define FBSDK_APPEVENTSTATE_ISIMPLICIT_KEY @"isImplicit"
|
||||||
|
|
||||||
@ -163,6 +164,8 @@
|
|||||||
|
|
||||||
- (NSString *)JSONStringForEvents:(BOOL)includeImplicitEvents
|
- (NSString *)JSONStringForEvents:(BOOL)includeImplicitEvents
|
||||||
{
|
{
|
||||||
|
[FBSDKRestrictiveDataFilterManager processEvents:_mutableEvents];
|
||||||
|
|
||||||
NSMutableArray *events = [[NSMutableArray alloc] initWithCapacity:_mutableEvents.count];
|
NSMutableArray *events = [[NSMutableArray alloc] initWithCapacity:_mutableEvents.count];
|
||||||
for (NSDictionary *eventAndImplicitFlag in _mutableEvents) {
|
for (NSDictionary *eventAndImplicitFlag in _mutableEvents) {
|
||||||
if (!includeImplicitEvents && [eventAndImplicitFlag[FBSDK_APPEVENTSTATE_ISIMPLICIT_KEY] boolValue]) {
|
if (!includeImplicitEvents && [eventAndImplicitFlag[FBSDK_APPEVENTSTATE_ISIMPLICIT_KEY] boolValue]) {
|
||||||
@ -175,7 +178,7 @@
|
|||||||
[events addObject:event];
|
[events addObject:event];
|
||||||
}
|
}
|
||||||
|
|
||||||
return [FBSDKInternalUtility JSONStringForObject:events error:NULL invalidObjectHandler:NULL];
|
return [FBSDKBasicUtility JSONStringForObject:events error:NULL invalidObjectHandler:NULL];
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
@ -20,6 +20,7 @@
|
|||||||
|
|
||||||
@class FBSDKAppEventsState;
|
@class FBSDKAppEventsState;
|
||||||
|
|
||||||
|
NS_SWIFT_NAME(AppEventsStateManager)
|
||||||
@interface FBSDKAppEventsStateManager : NSObject
|
@interface FBSDKAppEventsStateManager : NSObject
|
||||||
|
|
||||||
+ (void)clearPersistedAppEventsStates;
|
+ (void)clearPersistedAppEventsStates;
|
||||||
@ -22,6 +22,7 @@
|
|||||||
|
|
||||||
#import "FBSDKAppEventsState.h"
|
#import "FBSDKAppEventsState.h"
|
||||||
#import "FBSDKAppEventsUtility.h"
|
#import "FBSDKAppEventsUtility.h"
|
||||||
|
#import "FBSDKInternalUtility.h"
|
||||||
#import "FBSDKLogger.h"
|
#import "FBSDKLogger.h"
|
||||||
#import "FBSDKSettings.h"
|
#import "FBSDKSettings.h"
|
||||||
|
|
||||||
@ -73,6 +74,6 @@ static BOOL g_canSkipDiskCheck = NO;
|
|||||||
|
|
||||||
+ (NSString *)filePath
|
+ (NSString *)filePath
|
||||||
{
|
{
|
||||||
return [FBSDKAppEventsUtility persistenceFilePath:@"com-facebook-sdk-AppEventsPersistedEvents.json"];
|
return [FBSDKBasicUtility persistenceFilePath:@"com-facebook-sdk-AppEventsPersistedEvents.json"];
|
||||||
}
|
}
|
||||||
@end
|
@end
|
||||||
@ -25,7 +25,7 @@ typedef NS_ENUM(NSUInteger, FBSDKAdvertisingTrackingStatus)
|
|||||||
FBSDKAdvertisingTrackingAllowed,
|
FBSDKAdvertisingTrackingAllowed,
|
||||||
FBSDKAdvertisingTrackingDisallowed,
|
FBSDKAdvertisingTrackingDisallowed,
|
||||||
FBSDKAdvertisingTrackingUnspecified
|
FBSDKAdvertisingTrackingUnspecified
|
||||||
};
|
} NS_SWIFT_NAME(AppEventsUtility.AdvertisingTrackingStatus);
|
||||||
|
|
||||||
typedef NS_ENUM(NSUInteger, FBSDKAppEventsFlushReason)
|
typedef NS_ENUM(NSUInteger, FBSDKAppEventsFlushReason)
|
||||||
{
|
{
|
||||||
@ -35,30 +35,32 @@ typedef NS_ENUM(NSUInteger, FBSDKAppEventsFlushReason)
|
|||||||
FBSDKAppEventsFlushReasonPersistedEvents,
|
FBSDKAppEventsFlushReasonPersistedEvents,
|
||||||
FBSDKAppEventsFlushReasonEventThreshold,
|
FBSDKAppEventsFlushReasonEventThreshold,
|
||||||
FBSDKAppEventsFlushReasonEagerlyFlushingEvent
|
FBSDKAppEventsFlushReasonEagerlyFlushingEvent
|
||||||
};
|
} NS_SWIFT_NAME(AppEventsUtility.FlushReason);
|
||||||
|
|
||||||
|
NS_SWIFT_NAME(AppEventsUtility)
|
||||||
@interface FBSDKAppEventsUtility : NSObject
|
@interface FBSDKAppEventsUtility : NSObject
|
||||||
|
|
||||||
- (instancetype)init NS_UNAVAILABLE;
|
- (instancetype)init NS_UNAVAILABLE;
|
||||||
+ (instancetype)new NS_UNAVAILABLE;
|
+ (instancetype)new NS_UNAVAILABLE;
|
||||||
|
|
||||||
|
@property (class, nonatomic, copy, readonly) NSString *advertiserID;
|
||||||
|
@property (class, nonatomic, assign, readonly) FBSDKAdvertisingTrackingStatus advertisingTrackingStatus;
|
||||||
|
@property (class, nonatomic, strong, readonly) NSString *attributionID;
|
||||||
|
@property (class, nonatomic, assign, readonly) long unixTimeNow;
|
||||||
|
@property (class, nonatomic, assign, readonly) BOOL isDebugBuild;
|
||||||
|
|
||||||
+ (NSMutableDictionary *)activityParametersDictionaryForEvent:(NSString *)eventCategory
|
+ (NSMutableDictionary *)activityParametersDictionaryForEvent:(NSString *)eventCategory
|
||||||
implicitEventsOnly:(BOOL)implicitEventsOnly
|
implicitEventsOnly:(BOOL)implicitEventsOnly
|
||||||
shouldAccessAdvertisingID:(BOOL)shouldAccessAdvertisingID;
|
shouldAccessAdvertisingID:(BOOL)shouldAccessAdvertisingID;
|
||||||
+ (NSString *)advertiserID;
|
|
||||||
+ (FBSDKAdvertisingTrackingStatus)advertisingTrackingStatus;
|
|
||||||
+ (NSString *)attributionID;
|
|
||||||
+ (void)ensureOnMainThread:(NSString *)methodName className:(NSString *)className;
|
+ (void)ensureOnMainThread:(NSString *)methodName className:(NSString *)className;
|
||||||
+ (NSString *)flushReasonToString:(FBSDKAppEventsFlushReason)flushReason;
|
+ (NSString *)flushReasonToString:(FBSDKAppEventsFlushReason)flushReason;
|
||||||
+ (void)logAndNotify:(NSString *)msg allowLogAsDeveloperError:(BOOL)allowLogAsDeveloperError;
|
+ (void)logAndNotify:(NSString *)msg allowLogAsDeveloperError:(BOOL)allowLogAsDeveloperError;
|
||||||
+ (void)logAndNotify:(NSString *)msg;
|
+ (void)logAndNotify:(NSString *)msg;
|
||||||
+ (NSString *)persistenceFilePath:(NSString *)filename;
|
|
||||||
+ (NSString *)tokenStringToUseFor:(FBSDKAccessToken *)token;
|
+ (NSString *)tokenStringToUseFor:(FBSDKAccessToken *)token;
|
||||||
+ (long)unixTimeNow;
|
|
||||||
+ (BOOL)validateIdentifier:(NSString *)identifier;
|
+ (BOOL)validateIdentifier:(NSString *)identifier;
|
||||||
+ (id)getVariable:(NSString *)variableName fromInstance:(NSObject *)instance;
|
+ (id)getVariable:(NSString *)variableName fromInstance:(NSObject *)instance;
|
||||||
+ (NSNumber *)getNumberValue:(NSString *)text;
|
+ (NSNumber *)getNumberValue:(NSString *)text;
|
||||||
+ (BOOL)isDebugBuild;
|
|
||||||
+ (BOOL)isSensitiveUserData:(NSString *)text;
|
+ (BOOL)isSensitiveUserData:(NSString *)text;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
@ -47,21 +47,27 @@
|
|||||||
|
|
||||||
#if __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_7_0
|
#if __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_7_0
|
||||||
NSString *attributionID = [[self class] attributionID]; // Only present on iOS 6 and below.
|
NSString *attributionID = [[self class] attributionID]; // Only present on iOS 6 and below.
|
||||||
[FBSDKInternalUtility dictionary:parameters setObject:attributionID forKey:@"attribution"];
|
[FBSDKBasicUtility dictionary:parameters setObject:attributionID forKey:@"attribution"];
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (!implicitEventsOnly && shouldAccessAdvertisingID) {
|
if (!implicitEventsOnly && shouldAccessAdvertisingID) {
|
||||||
NSString *advertiserID = [[self class] advertiserID];
|
NSString *advertiserID = [[self class] advertiserID];
|
||||||
[FBSDKInternalUtility dictionary:parameters setObject:advertiserID forKey:@"advertiser_id"];
|
[FBSDKBasicUtility dictionary:parameters setObject:advertiserID forKey:@"advertiser_id"];
|
||||||
}
|
}
|
||||||
|
|
||||||
parameters[FBSDK_APPEVENTSUTILITY_ANONYMOUSID_KEY] = [self anonymousID];
|
parameters[FBSDK_APPEVENTSUTILITY_ANONYMOUSID_KEY] = [FBSDKBasicUtility anonymousID];
|
||||||
|
|
||||||
FBSDKAdvertisingTrackingStatus advertisingTrackingStatus = [[self class] advertisingTrackingStatus];
|
FBSDKAdvertisingTrackingStatus advertisingTrackingStatus = [[self class] advertisingTrackingStatus];
|
||||||
if (advertisingTrackingStatus != FBSDKAdvertisingTrackingUnspecified) {
|
if (advertisingTrackingStatus != FBSDKAdvertisingTrackingUnspecified) {
|
||||||
BOOL allowed = (advertisingTrackingStatus == FBSDKAdvertisingTrackingAllowed);
|
BOOL allowed = (advertisingTrackingStatus == FBSDKAdvertisingTrackingAllowed);
|
||||||
parameters[@"advertiser_tracking_enabled"] = @(allowed).stringValue;
|
parameters[@"advertiser_tracking_enabled"] = @(allowed).stringValue;
|
||||||
}
|
}
|
||||||
|
if (advertisingTrackingStatus == FBSDKAdvertisingTrackingAllowed) {
|
||||||
|
NSString *userData = [FBSDKAppEvents getUserData];
|
||||||
|
if (userData){
|
||||||
|
parameters[@"ud"] = userData;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
parameters[@"application_tracking_enabled"] = @(!FBSDKSettings.limitEventAndDataUsage).stringValue;
|
parameters[@"application_tracking_enabled"] = @(!FBSDKSettings.limitEventAndDataUsage).stringValue;
|
||||||
|
|
||||||
@ -69,10 +75,6 @@
|
|||||||
if (userID) {
|
if (userID) {
|
||||||
parameters[@"app_user_id"] = userID;
|
parameters[@"app_user_id"] = userID;
|
||||||
}
|
}
|
||||||
NSString *userData = [FBSDKAppEvents getUserData];
|
|
||||||
if (userData){
|
|
||||||
parameters[@"ud"] = userData;
|
|
||||||
}
|
|
||||||
|
|
||||||
[FBSDKAppEventsDeviceInfo extendDictionaryWithDeviceInfo:parameters];
|
[FBSDKAppEventsDeviceInfo extendDictionaryWithDeviceInfo:parameters];
|
||||||
|
|
||||||
@ -91,7 +93,7 @@
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (urlSchemes.count > 0) {
|
if (urlSchemes.count > 0) {
|
||||||
parameters[@"url_schemes"] = [FBSDKInternalUtility JSONStringForObject:urlSchemes error:NULL invalidObjectHandler:NULL];
|
parameters[@"url_schemes"] = [FBSDKBasicUtility JSONStringForObject:urlSchemes error:NULL invalidObjectHandler:NULL];
|
||||||
}
|
}
|
||||||
|
|
||||||
return parameters;
|
return parameters;
|
||||||
@ -99,7 +101,7 @@
|
|||||||
|
|
||||||
+ (NSString *)advertiserID
|
+ (NSString *)advertiserID
|
||||||
{
|
{
|
||||||
if (![[FBSDKSettings advertiserIDCollectionEnabled] boolValue]) {
|
if (!FBSDKSettings.isAdvertiserIDCollectionEnabled) {
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -133,22 +135,6 @@
|
|||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (NSString *)anonymousID
|
|
||||||
{
|
|
||||||
// Grab previously written anonymous ID and, if none have been generated, create and
|
|
||||||
// persist a new one which will remain associated with this app.
|
|
||||||
NSString *result = [[self class] retrievePersistedAnonymousID];
|
|
||||||
if (!result) {
|
|
||||||
// Generate a new anonymous ID. Create as a UUID, but then prepend the fairly
|
|
||||||
// arbitrary 'XZ' to the front so it's easily distinguishable from IDFA's which
|
|
||||||
// will only contain hex.
|
|
||||||
result = [NSString stringWithFormat:@"XZ%@", [NSUUID UUID].UUIDString];
|
|
||||||
|
|
||||||
[self persistAnonymousID:result];
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
+ (NSString *)attributionID
|
+ (NSString *)attributionID
|
||||||
{
|
{
|
||||||
#if TARGET_OS_TV
|
#if TARGET_OS_TV
|
||||||
@ -158,7 +144,8 @@
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// for tests only.
|
#pragma mark - Internal, for testing
|
||||||
|
|
||||||
+ (void)clearLibraryFiles
|
+ (void)clearLibraryFiles
|
||||||
{
|
{
|
||||||
[[NSFileManager defaultManager] removeItemAtPath:[[self class] persistenceFilePath:FBSDK_APPEVENTSUTILITY_ANONYMOUSIDFILENAME]
|
[[NSFileManager defaultManager] removeItemAtPath:[[self class] persistenceFilePath:FBSDK_APPEVENTSUTILITY_ANONYMOUSIDFILENAME]
|
||||||
@ -218,7 +205,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
[FBSDKLogger singleShotLogEntry:behaviorToLog logEntry:msg];
|
[FBSDKLogger singleShotLogEntry:behaviorToLog logEntry:msg];
|
||||||
NSError *error = [NSError fbErrorWithCode:FBSDKErrorAppEventsFlush message:msg];
|
NSError *error = [FBSDKError errorWithCode:FBSDKErrorAppEventsFlush message:msg];
|
||||||
[[NSNotificationCenter defaultCenter] postNotificationName:FBSDKAppEventsLoggingResultNotification object:error];
|
[[NSNotificationCenter defaultCenter] postNotificationName:FBSDKAppEventsLoggingResultNotification object:error];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -285,37 +272,6 @@ restOfStringCharacterSet:(NSCharacterSet *)restOfStringCharacterSet
|
|||||||
return YES;
|
return YES;
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (void)persistAnonymousID:(NSString *)anonymousID
|
|
||||||
{
|
|
||||||
[[self class] ensureOnMainThread:NSStringFromSelector(_cmd) className:NSStringFromClass(self)];
|
|
||||||
NSDictionary *data = @{ FBSDK_APPEVENTSUTILITY_ANONYMOUSID_KEY : anonymousID };
|
|
||||||
NSString *content = [FBSDKInternalUtility JSONStringForObject:data error:NULL invalidObjectHandler:NULL];
|
|
||||||
|
|
||||||
[content writeToFile:[[self class] persistenceFilePath:FBSDK_APPEVENTSUTILITY_ANONYMOUSIDFILENAME]
|
|
||||||
atomically:YES
|
|
||||||
encoding:NSASCIIStringEncoding
|
|
||||||
error:nil];
|
|
||||||
}
|
|
||||||
|
|
||||||
+ (NSString *)persistenceFilePath:(NSString *)filename
|
|
||||||
{
|
|
||||||
NSSearchPathDirectory directory = NSLibraryDirectory;
|
|
||||||
NSArray *paths = NSSearchPathForDirectoriesInDomains(directory, NSUserDomainMask, YES);
|
|
||||||
NSString *docDirectory = paths[0];
|
|
||||||
return [docDirectory stringByAppendingPathComponent:filename];
|
|
||||||
}
|
|
||||||
|
|
||||||
+ (NSString *)retrievePersistedAnonymousID
|
|
||||||
{
|
|
||||||
[[self class] ensureOnMainThread:NSStringFromSelector(_cmd) className:NSStringFromClass(self)];
|
|
||||||
NSString *file = [[self class] persistenceFilePath:FBSDK_APPEVENTSUTILITY_ANONYMOUSIDFILENAME];
|
|
||||||
NSString *content = [[NSString alloc] initWithContentsOfFile:file
|
|
||||||
encoding:NSASCIIStringEncoding
|
|
||||||
error:nil];
|
|
||||||
NSDictionary *results = [FBSDKInternalUtility objectForJSONString:content error:NULL];
|
|
||||||
return results[FBSDK_APPEVENTSUTILITY_ANONYMOUSID_KEY];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Given a candidate token (which may be nil), find the real token to string to use.
|
// Given a candidate token (which may be nil), find the real token to string to use.
|
||||||
// Precedence: 1) provided token, 2) current token, 3) app | client token, 4) fully anonymous session.
|
// Precedence: 1) provided token, 2) current token, 3) app | client token, 4) fully anonymous session.
|
||||||
+ (NSString *)tokenStringToUseFor:(FBSDKAccessToken *)token
|
+ (NSString *)tokenStringToUseFor:(FBSDKAccessToken *)token
|
||||||
@ -20,6 +20,7 @@
|
|||||||
#import <Foundation/Foundation.h>
|
#import <Foundation/Foundation.h>
|
||||||
#import <WebKit/WebKit.h>
|
#import <WebKit/WebKit.h>
|
||||||
|
|
||||||
|
NS_SWIFT_NAME(HybridAppEventsScriptMessageHandler)
|
||||||
@interface FBSDKHybridAppEventsScriptMessageHandler : NSObject <WKScriptMessageHandler>
|
@interface FBSDKHybridAppEventsScriptMessageHandler : NSObject <WKScriptMessageHandler>
|
||||||
|
|
||||||
@end
|
@end
|
||||||
@ -34,7 +34,7 @@ NSString *const FBSDKAppEventsWKWebViewMessagesPixelReferralParamKey = @"_fb_pix
|
|||||||
NSString *event = message.body[FBSDKAppEventsWKWebViewMessagesEventKey];
|
NSString *event = message.body[FBSDKAppEventsWKWebViewMessagesEventKey];
|
||||||
if (event.length > 0) {
|
if (event.length > 0) {
|
||||||
NSString *stringedParams = message.body[FBSDKAppEventsWKWebViewMessagesParamsKey];
|
NSString *stringedParams = message.body[FBSDKAppEventsWKWebViewMessagesParamsKey];
|
||||||
NSMutableDictionary <NSObject *, NSObject *> *params = nil;
|
NSMutableDictionary <NSString *, id> *params = nil;
|
||||||
NSError *jsonParseError = nil;
|
NSError *jsonParseError = nil;
|
||||||
if ([stringedParams isKindOfClass:[NSString class]]) {
|
if ([stringedParams isKindOfClass:[NSString class]]) {
|
||||||
params = [NSJSONSerialization JSONObjectWithData:[stringedParams dataUsingEncoding:NSUTF8StringEncoding]
|
params = [NSJSONSerialization JSONObjectWithData:[stringedParams dataUsingEncoding:NSUTF8StringEncoding]
|
||||||
@ -54,7 +54,9 @@ NSString *const FBSDKAppEventsWKWebViewMessagesPixelReferralParamKey = @"_fb_pix
|
|||||||
else {
|
else {
|
||||||
params[FBSDKAppEventsWKWebViewMessagesPixelReferralParamKey] = pixelID;
|
params[FBSDKAppEventsWKWebViewMessagesPixelReferralParamKey] = pixelID;
|
||||||
}
|
}
|
||||||
[FBSDKAppEvents logEvent:event parameters:params];
|
[FBSDKAppEvents logInternalEvent:event
|
||||||
|
parameters:params
|
||||||
|
isImplicitlyLogged:NO];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -19,6 +19,7 @@
|
|||||||
#import <Foundation/Foundation.h>
|
#import <Foundation/Foundation.h>
|
||||||
|
|
||||||
// Class to encapsulate implicit logging of purchase events
|
// Class to encapsulate implicit logging of purchase events
|
||||||
|
NS_SWIFT_NAME(PaymentObserver)
|
||||||
@interface FBSDKPaymentObserver : NSObject
|
@interface FBSDKPaymentObserver : NSObject
|
||||||
+ (void)startObservingTransactions;
|
+ (void)startObservingTransactions;
|
||||||
+ (void)stopObservingTransactions;
|
+ (void)stopObservingTransactions;
|
||||||
@ -20,24 +20,34 @@
|
|||||||
|
|
||||||
#import <StoreKit/StoreKit.h>
|
#import <StoreKit/StoreKit.h>
|
||||||
|
|
||||||
|
#import <FBSDKCoreKit/FBSDKCoreKit+Internal.h>
|
||||||
|
|
||||||
#import "FBSDKAppEvents+Internal.h"
|
#import "FBSDKAppEvents+Internal.h"
|
||||||
#import "FBSDKDynamicFrameworkLoader.h"
|
#import "FBSDKDynamicFrameworkLoader.h"
|
||||||
#import "FBSDKLogger.h"
|
#import "FBSDKLogger.h"
|
||||||
#import "FBSDKSettings.h"
|
#import "FBSDKSettings.h"
|
||||||
|
|
||||||
|
static NSString *const FBSDKPaymentObserverOriginalTransactionKey = @"com.facebook.appevents.PaymentObserver.originalTransaction";
|
||||||
|
static NSString *const FBSDKPaymentObserverDelimiter = @",";
|
||||||
|
|
||||||
static NSString *const FBSDKAppEventParameterImplicitlyLoggedPurchase = @"_implicitlyLogged";
|
static NSString *const FBSDKAppEventParameterImplicitlyLoggedPurchase = @"_implicitlyLogged";
|
||||||
static NSString *const FBSDKAppEventNamePurchaseFailed = @"fb_mobile_purchase_failed";
|
static NSString *const FBSDKAppEventNamePurchaseFailed = @"fb_mobile_purchase_failed";
|
||||||
static NSString *const FBSDKAppEventNamePurchaseRestored = @"fb_mobile_purchase_restored";
|
static NSString *const FBSDKAppEventNamePurchaseRestored = @"fb_mobile_purchase_restored";
|
||||||
static NSString *const FBSDKAppEventParameterNameInAppPurchaseType = @"fb_iap_product_type";
|
static NSString *const FBSDKAppEventParameterNameInAppPurchaseType = @"fb_iap_product_type";
|
||||||
static NSString *const FBSDKAppEventParameterNameProductTitle = @"fb_content_title";
|
static NSString *const FBSDKAppEventParameterNameProductTitle = @"fb_content_title";
|
||||||
|
static NSString *const FBSDKAppEventParameterNameOriginalTransactionID = @"fb_original_transaction_id";
|
||||||
static NSString *const FBSDKAppEventParameterNameTransactionID = @"fb_transaction_id";
|
static NSString *const FBSDKAppEventParameterNameTransactionID = @"fb_transaction_id";
|
||||||
static NSString *const FBSDKAppEventParameterNameTransactionDate = @"fb_transaction_date";
|
static NSString *const FBSDKAppEventParameterNameTransactionDate = @"fb_transaction_date";
|
||||||
static NSString *const FBSDKAppEventParameterNameSubscriptionPeriod = @"fb_iap_subs_period";
|
static NSString *const FBSDKAppEventParameterNameSubscriptionPeriod = @"fb_iap_subs_period";
|
||||||
|
static NSString *const FBSDKAppEventParameterNameIsStartTrial = @"fb_iap_is_start_trial";
|
||||||
|
static NSString *const FBSDKAppEventParameterNameHasFreeTrial = @"fb_iap_has_free_trial";
|
||||||
static NSString *const FBSDKAppEventParameterNameTrialPeriod = @"fb_iap_trial_period";
|
static NSString *const FBSDKAppEventParameterNameTrialPeriod = @"fb_iap_trial_period";
|
||||||
static NSString *const FBSDKAppEventParameterNameTrialPrice = @"fb_iap_trial_price";
|
static NSString *const FBSDKAppEventParameterNameTrialPrice = @"fb_iap_trial_price";
|
||||||
static int const FBSDKMaxParameterValueLength = 100;
|
static int const FBSDKMaxParameterValueLength = 100;
|
||||||
static NSMutableArray *g_pendingRequestors;
|
static NSMutableArray *g_pendingRequestors;
|
||||||
|
|
||||||
|
static NSString *const FBSDKGateKeeperAppEventsIfAutoLogSubs = @"app_events_if_auto_log_subs";
|
||||||
|
|
||||||
@interface FBSDKPaymentProductRequestor : NSObject<SKProductsRequestDelegate>
|
@interface FBSDKPaymentProductRequestor : NSObject<SKProductsRequestDelegate>
|
||||||
|
|
||||||
@property (nonatomic, retain) SKPaymentTransaction *transaction;
|
@property (nonatomic, retain) SKPaymentTransaction *transaction;
|
||||||
@ -65,9 +75,7 @@ static NSMutableArray *g_pendingRequestors;
|
|||||||
[[self singleton] stopObservingTransactions];
|
[[self singleton] stopObservingTransactions];
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
#pragma mark - Internal Methods
|
||||||
// Internal methods
|
|
||||||
//
|
|
||||||
|
|
||||||
+ (FBSDKPaymentObserver *)singleton
|
+ (FBSDKPaymentObserver *)singleton
|
||||||
{
|
{
|
||||||
@ -127,10 +135,6 @@ static NSMutableArray *g_pendingRequestors;
|
|||||||
|
|
||||||
- (void)handleTransaction:(SKPaymentTransaction *)transaction
|
- (void)handleTransaction:(SKPaymentTransaction *)transaction
|
||||||
{
|
{
|
||||||
// Ignore restored transaction
|
|
||||||
if (transaction.originalTransaction != nil) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
FBSDKPaymentProductRequestor *productRequest = [[FBSDKPaymentProductRequestor alloc] initWithTransaction:transaction];
|
FBSDKPaymentProductRequestor *productRequest = [[FBSDKPaymentProductRequestor alloc] initWithTransaction:transaction];
|
||||||
[productRequest resolveProducts];
|
[productRequest resolveProducts];
|
||||||
}
|
}
|
||||||
@ -142,6 +146,11 @@ static NSMutableArray *g_pendingRequestors;
|
|||||||
@end
|
@end
|
||||||
|
|
||||||
@implementation FBSDKPaymentProductRequestor
|
@implementation FBSDKPaymentProductRequestor
|
||||||
|
{
|
||||||
|
NSMutableSet<NSString *> *_originalTransactionSet;
|
||||||
|
NSSet<NSString *> *_eventsWithReceipt;
|
||||||
|
NSDateFormatter *_formatter;
|
||||||
|
}
|
||||||
|
|
||||||
+ (void)initialize
|
+ (void)initialize
|
||||||
{
|
{
|
||||||
@ -155,6 +164,16 @@ static NSMutableArray *g_pendingRequestors;
|
|||||||
self = [super init];
|
self = [super init];
|
||||||
if (self) {
|
if (self) {
|
||||||
_transaction = transaction;
|
_transaction = transaction;
|
||||||
|
_formatter = [[NSDateFormatter alloc] init];
|
||||||
|
_formatter.dateFormat = @"yyyy-MM-dd HH:mm:ssZ";
|
||||||
|
NSString *data = [[NSUserDefaults standardUserDefaults] stringForKey:FBSDKPaymentObserverOriginalTransactionKey];
|
||||||
|
_eventsWithReceipt = [NSSet setWithArray:@[FBSDKAppEventNamePurchased, FBSDKAppEventNameSubscribe,
|
||||||
|
FBSDKAppEventNameStartTrial]];
|
||||||
|
if (data) {
|
||||||
|
_originalTransactionSet = [NSMutableSet setWithArray:[data componentsSeparatedByString:FBSDKPaymentObserverDelimiter]];
|
||||||
|
} else {
|
||||||
|
_originalTransactionSet = [[NSMutableSet alloc] init];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
@ -192,86 +211,182 @@ static NSMutableArray *g_pendingRequestors;
|
|||||||
|
|
||||||
- (void)logTransactionEvent:(SKProduct *)product
|
- (void)logTransactionEvent:(SKProduct *)product
|
||||||
{
|
{
|
||||||
NSString *eventName = nil;
|
if ([self isSubscription:product] &&
|
||||||
|
[FBSDKGateKeeperManager boolForKey:FBSDKGateKeeperAppEventsIfAutoLogSubs
|
||||||
|
defaultValue:NO]) {
|
||||||
|
[self logImplicitSubscribeTransaction:self.transaction ofProduct:product];
|
||||||
|
} else {
|
||||||
|
[self logImplicitPurchaseTransaction:self.transaction ofProduct:product];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)isSubscription:(SKProduct *)product
|
||||||
|
{
|
||||||
|
#if !TARGET_OS_TV
|
||||||
|
#if __IPHONE_OS_VERSION_MAX_ALLOWED > __IPHONE_11_1
|
||||||
|
if (@available(iOS 11.2, *)) {
|
||||||
|
return (product.subscriptionPeriod != nil) && ((unsigned long)product.subscriptionPeriod.numberOfUnits > 0);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSMutableDictionary<NSString *, id> *)getEventParametersOfProduct:(SKProduct *)product
|
||||||
|
withTransaction:(SKPaymentTransaction *)transaction
|
||||||
|
{
|
||||||
NSString *transactionID = nil;
|
NSString *transactionID = nil;
|
||||||
NSString *transactionDate = nil;
|
NSString *transactionDate = nil;
|
||||||
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
|
switch (transaction.transactionState) {
|
||||||
formatter.dateFormat = @"yyyy-MM-dd HH:mm:ssZ";
|
|
||||||
switch (self.transaction.transactionState) {
|
|
||||||
case SKPaymentTransactionStatePurchasing:
|
case SKPaymentTransactionStatePurchasing:
|
||||||
eventName = FBSDKAppEventNameInitiatedCheckout;
|
|
||||||
break;
|
break;
|
||||||
case SKPaymentTransactionStatePurchased:
|
case SKPaymentTransactionStatePurchased:
|
||||||
eventName = FBSDKAppEventNamePurchased;
|
|
||||||
transactionID = self.transaction.transactionIdentifier;
|
transactionID = self.transaction.transactionIdentifier;
|
||||||
transactionDate = [formatter stringFromDate:self.transaction.transactionDate];
|
transactionDate = [_formatter stringFromDate:self.transaction.transactionDate];
|
||||||
break;
|
break;
|
||||||
case SKPaymentTransactionStateFailed:
|
case SKPaymentTransactionStateFailed:
|
||||||
eventName = FBSDKAppEventNamePurchaseFailed;
|
|
||||||
break;
|
break;
|
||||||
case SKPaymentTransactionStateRestored:
|
case SKPaymentTransactionStateRestored:
|
||||||
eventName = FBSDKAppEventNamePurchaseRestored;
|
transactionDate = [_formatter stringFromDate:self.transaction.transactionDate];
|
||||||
transactionDate = [formatter stringFromDate:self.transaction.transactionDate];
|
|
||||||
break;
|
break;
|
||||||
case SKPaymentTransactionStateDeferred:
|
default: break;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
if (!eventName) {
|
SKPayment *payment = transaction.payment;
|
||||||
[FBSDKLogger singleShotLogEntry:FBSDKLoggingBehaviorAppEvents
|
|
||||||
formatString:@"FBSDKPaymentObserver logTransactionEvent: event name cannot be nil"];
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
SKPayment *payment = self.transaction.payment;
|
|
||||||
NSMutableDictionary *eventParameters = [NSMutableDictionary dictionaryWithDictionary: @{
|
NSMutableDictionary *eventParameters = [NSMutableDictionary dictionaryWithDictionary: @{
|
||||||
FBSDKAppEventParameterNameContentID: payment.productIdentifier ?: @"",
|
FBSDKAppEventParameterNameContentID: payment.productIdentifier ?: @"",
|
||||||
FBSDKAppEventParameterNameNumItems: @(payment.quantity),
|
FBSDKAppEventParameterNameNumItems: @(payment.quantity),
|
||||||
FBSDKAppEventParameterNameTransactionDate: transactionDate ?: @"",
|
FBSDKAppEventParameterNameTransactionDate: transactionDate ?: @"",
|
||||||
}];
|
}];
|
||||||
double totalAmount = 0;
|
|
||||||
if (product) {
|
if (product) {
|
||||||
totalAmount = payment.quantity * product.price.doubleValue;
|
|
||||||
[eventParameters addEntriesFromDictionary: @{
|
[eventParameters addEntriesFromDictionary: @{
|
||||||
FBSDKAppEventParameterNameCurrency: [product.priceLocale objectForKey:NSLocaleCurrencyCode],
|
FBSDKAppEventParameterNameCurrency: [product.priceLocale objectForKey:NSLocaleCurrencyCode],
|
||||||
FBSDKAppEventParameterNameNumItems: @(payment.quantity),
|
FBSDKAppEventParameterNameNumItems: @(payment.quantity),
|
||||||
FBSDKAppEventParameterNameProductTitle: [self getTruncatedString:product.localizedTitle],
|
FBSDKAppEventParameterNameProductTitle: [self getTruncatedString:product.localizedTitle],
|
||||||
FBSDKAppEventParameterNameDescription: [self getTruncatedString:product.localizedDescription],
|
FBSDKAppEventParameterNameDescription: [self getTruncatedString:product.localizedDescription],
|
||||||
}];
|
}];
|
||||||
|
|
||||||
#if !TARGET_OS_TV
|
|
||||||
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_11_2
|
|
||||||
if (@available(iOS 11.2, *)) {
|
|
||||||
BOOL isSubscription = (product.subscriptionPeriod != nil) && ((unsigned long)product.subscriptionPeriod.numberOfUnits > 0);
|
|
||||||
if (isSubscription) {
|
|
||||||
// subs inapp
|
|
||||||
eventParameters[FBSDKAppEventParameterNameSubscriptionPeriod] = [self lengthOfSubscriptionPeriod:product.subscriptionPeriod];
|
|
||||||
eventParameters[FBSDKAppEventParameterNameInAppPurchaseType] = @"subs";
|
|
||||||
// trial information for subs
|
|
||||||
SKProductDiscount *discount = product.introductoryPrice;
|
|
||||||
if (discount) {
|
|
||||||
eventParameters[FBSDKAppEventParameterNameTrialPeriod] = [self lengthOfSubscriptionPeriod:discount.subscriptionPeriod];
|
|
||||||
eventParameters[FBSDKAppEventParameterNameTrialPrice] = discount.price;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
eventParameters[FBSDKAppEventParameterNameInAppPurchaseType] = @"inapp";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
if (transactionID) {
|
if (transactionID) {
|
||||||
eventParameters[FBSDKAppEventParameterNameTransactionID] = transactionID;
|
eventParameters[FBSDKAppEventParameterNameTransactionID] = transactionID;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[self logImplicitPurchaseEvent:eventName
|
#if !TARGET_OS_TV
|
||||||
valueToSum:totalAmount
|
#if __IPHONE_OS_VERSION_MAX_ALLOWED > __IPHONE_11_1
|
||||||
parameters:eventParameters];
|
if (@available(iOS 11.2, *)) {
|
||||||
|
if ([self isSubscription:product]) {
|
||||||
|
// subs inapp
|
||||||
|
eventParameters[FBSDKAppEventParameterNameSubscriptionPeriod] = [self durationOfSubscriptionPeriod:product.subscriptionPeriod];
|
||||||
|
eventParameters[FBSDKAppEventParameterNameInAppPurchaseType] = @"subs";
|
||||||
|
eventParameters[FBSDKAppEventParameterNameIsStartTrial] = [self isStartTrial:transaction ofProduct:product] ? @"1" : @"0";
|
||||||
|
// trial information for subs
|
||||||
|
SKProductDiscount *discount = product.introductoryPrice;
|
||||||
|
if (discount) {
|
||||||
|
if (discount.paymentMode == SKProductDiscountPaymentModeFreeTrial) {
|
||||||
|
eventParameters[FBSDKAppEventParameterNameHasFreeTrial] = @"1";
|
||||||
|
} else {
|
||||||
|
eventParameters[FBSDKAppEventParameterNameHasFreeTrial] = @"0";
|
||||||
|
}
|
||||||
|
eventParameters[FBSDKAppEventParameterNameTrialPeriod] = [self durationOfSubscriptionPeriod:discount.subscriptionPeriod];
|
||||||
|
eventParameters[FBSDKAppEventParameterNameTrialPrice] = discount.price;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
eventParameters[FBSDKAppEventParameterNameInAppPurchaseType] = @"inapp";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
return eventParameters;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSString *)lengthOfSubscriptionPeriod:(id)subcriptionPeriod
|
- (void)appendOriginalTransactionID:(NSString *)transactionID
|
||||||
|
{
|
||||||
|
if (!transactionID) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
[_originalTransactionSet addObject:transactionID];
|
||||||
|
[[NSUserDefaults standardUserDefaults] setObject:[[_originalTransactionSet allObjects] componentsJoinedByString:FBSDKPaymentObserverDelimiter]
|
||||||
|
forKey:FBSDKPaymentObserverOriginalTransactionKey];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)clearOriginalTransactionID:(NSString *)transactionID
|
||||||
|
{
|
||||||
|
if (!transactionID) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
[_originalTransactionSet removeObject:transactionID];
|
||||||
|
[[NSUserDefaults standardUserDefaults] setObject:[[_originalTransactionSet allObjects] componentsJoinedByString:FBSDKPaymentObserverDelimiter]
|
||||||
|
forKey:FBSDKPaymentObserverOriginalTransactionKey];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)isStartTrial:(SKPaymentTransaction *)transaction
|
||||||
|
ofProduct:(SKProduct *)product
|
||||||
{
|
{
|
||||||
#if !TARGET_OS_TV
|
#if !TARGET_OS_TV
|
||||||
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_11_2
|
#if __IPHONE_OS_VERSION_MAX_ALLOWED > __IPHONE_11_1
|
||||||
|
#if __IPHONE_OS_VERSION_MAX_ALLOWED > __IPHONE_11_4
|
||||||
|
#if __IPHONE_OS_VERSION_MAX_ALLOWED > __IPHONE_12_1
|
||||||
|
// promotional offer starting from iOS 12.2
|
||||||
|
if (@available(iOS 12.2, *)) {
|
||||||
|
SKPaymentDiscount *paymentDiscount = transaction.payment.paymentDiscount;
|
||||||
|
if (paymentDiscount) {
|
||||||
|
NSArray<SKProductDiscount *> *discounts = product.discounts;
|
||||||
|
for (SKProductDiscount *discount in discounts) {
|
||||||
|
if (discount.paymentMode == SKProductDiscountPaymentModeFreeTrial &&
|
||||||
|
[paymentDiscount.identifier isEqualToString:discount.identifier]) {
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
// introductory offer starting from iOS 11.2
|
||||||
|
if (@available(iOS 11.2, *)) {
|
||||||
|
if (product.introductoryPrice &&
|
||||||
|
product.introductoryPrice.paymentMode == SKProductDiscountPaymentModeFreeTrial) {
|
||||||
|
NSString *originalTransactionID = transaction.originalTransaction.transactionIdentifier;
|
||||||
|
// only consider the very first trial transaction as start trial
|
||||||
|
if (!originalTransactionID) {
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)hasStartTrial:(SKProduct *)product
|
||||||
|
{
|
||||||
|
#if !TARGET_OS_TV
|
||||||
|
#if __IPHONE_OS_VERSION_MAX_ALLOWED > __IPHONE_11_1
|
||||||
|
#if __IPHONE_OS_VERSION_MAX_ALLOWED > __IPHONE_11_4
|
||||||
|
#if __IPHONE_OS_VERSION_MAX_ALLOWED > __IPHONE_12_1
|
||||||
|
// promotional offer starting from iOS 12.2
|
||||||
|
if (@available(iOS 12.2, *)) {
|
||||||
|
NSArray<SKProductDiscount *> *discounts = product.discounts;
|
||||||
|
for (SKProductDiscount *discount in discounts) {
|
||||||
|
if (discount.paymentMode == SKProductDiscountPaymentModeFreeTrial) {
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
// introductory offer starting from iOS 11.2
|
||||||
|
if (@available(iOS 11.2, *)) {
|
||||||
|
if (product.introductoryPrice && (product.introductoryPrice.paymentMode == SKProductDiscountPaymentModeFreeTrial)) {
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSString *)durationOfSubscriptionPeriod:(id)subcriptionPeriod
|
||||||
|
{
|
||||||
|
#if !TARGET_OS_TV
|
||||||
|
#if __IPHONE_OS_VERSION_MAX_ALLOWED > __IPHONE_11_1
|
||||||
if (@available(iOS 11.2, *)) {
|
if (@available(iOS 11.2, *)) {
|
||||||
if (subcriptionPeriod && [subcriptionPeriod isKindOfClass:[SKProductSubscriptionPeriod class]]) {
|
if (subcriptionPeriod && [subcriptionPeriod isKindOfClass:[SKProductSubscriptionPeriod class]]) {
|
||||||
SKProductSubscriptionPeriod *period = (SKProductSubscriptionPeriod *)subcriptionPeriod;
|
SKProductSubscriptionPeriod *period = (SKProductSubscriptionPeriod *)subcriptionPeriod;
|
||||||
@ -323,12 +438,85 @@ static NSMutableArray *g_pendingRequestors;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)logImplicitPurchaseEvent:(NSString *)eventName
|
- (void)logImplicitSubscribeTransaction:(SKPaymentTransaction *)transaction
|
||||||
valueToSum:(double)valueToSum
|
ofProduct:(SKProduct *)product
|
||||||
parameters:(NSDictionary *)parameters {
|
{
|
||||||
|
NSString *eventName = nil;
|
||||||
|
NSString *originalTransactionID = transaction.originalTransaction.transactionIdentifier;
|
||||||
|
switch (transaction.transactionState) {
|
||||||
|
case SKPaymentTransactionStatePurchasing:
|
||||||
|
eventName = @"SubscriptionInitiatedCheckout";
|
||||||
|
break;
|
||||||
|
case SKPaymentTransactionStatePurchased:
|
||||||
|
if ([self isStartTrial:transaction ofProduct:product]) {
|
||||||
|
eventName = FBSDKAppEventNameStartTrial;
|
||||||
|
[self clearOriginalTransactionID:originalTransactionID];
|
||||||
|
} else {
|
||||||
|
if (originalTransactionID && [_originalTransactionSet containsObject:originalTransactionID]) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
eventName = FBSDKAppEventNameSubscribe;
|
||||||
|
[self appendOriginalTransactionID:(originalTransactionID ?: transaction.transactionIdentifier)];
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SKPaymentTransactionStateFailed:
|
||||||
|
eventName = @"SubscriptionFailed";
|
||||||
|
break;
|
||||||
|
case SKPaymentTransactionStateRestored:
|
||||||
|
eventName = @"SubscriptionRestore";
|
||||||
|
break;
|
||||||
|
case SKPaymentTransactionStateDeferred:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
double totalAmount = 0;
|
||||||
|
if (product) {
|
||||||
|
totalAmount = transaction.payment.quantity * product.price.doubleValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
[self logImplicitTransactionEvent:eventName
|
||||||
|
valueToSum:totalAmount
|
||||||
|
parameters:[self getEventParametersOfProduct:product withTransaction:transaction]];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)logImplicitPurchaseTransaction:(SKPaymentTransaction *)transaction
|
||||||
|
ofProduct:(SKProduct *)product
|
||||||
|
{
|
||||||
|
NSString *eventName = nil;
|
||||||
|
switch (transaction.transactionState) {
|
||||||
|
case SKPaymentTransactionStatePurchasing:
|
||||||
|
eventName = FBSDKAppEventNameInitiatedCheckout;
|
||||||
|
break;
|
||||||
|
case SKPaymentTransactionStatePurchased:
|
||||||
|
eventName = FBSDKAppEventNamePurchased;
|
||||||
|
break;
|
||||||
|
case SKPaymentTransactionStateFailed:
|
||||||
|
eventName = FBSDKAppEventNamePurchaseFailed;
|
||||||
|
break;
|
||||||
|
case SKPaymentTransactionStateRestored:
|
||||||
|
eventName = FBSDKAppEventNamePurchaseRestored;
|
||||||
|
break;
|
||||||
|
case SKPaymentTransactionStateDeferred:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
double totalAmount = 0;
|
||||||
|
if (product) {
|
||||||
|
totalAmount = transaction.payment.quantity * product.price.doubleValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
[self logImplicitTransactionEvent:eventName
|
||||||
|
valueToSum:totalAmount
|
||||||
|
parameters:[self getEventParametersOfProduct:product withTransaction:transaction]];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)logImplicitTransactionEvent:(NSString *)eventName
|
||||||
|
valueToSum:(double)valueToSum
|
||||||
|
parameters:(NSDictionary<NSString *, id> *)parameters
|
||||||
|
{
|
||||||
NSMutableDictionary *eventParameters = [NSMutableDictionary dictionaryWithDictionary:parameters];
|
NSMutableDictionary *eventParameters = [NSMutableDictionary dictionaryWithDictionary:parameters];
|
||||||
|
|
||||||
if ([eventName isEqualToString:FBSDKAppEventNamePurchased]) {
|
if ([_eventsWithReceipt containsObject:eventName]) {
|
||||||
NSData* receipt = [self fetchDeviceReceipt];
|
NSData* receipt = [self fetchDeviceReceipt];
|
||||||
if (receipt) {
|
if (receipt) {
|
||||||
NSString *base64encodedReceipt = [receipt base64EncodedStringWithOptions:0];
|
NSString *base64encodedReceipt = [receipt base64EncodedStringWithOptions:0];
|
||||||
@ -349,7 +537,8 @@ static NSMutableArray *g_pendingRequestors;
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Fetch the current receipt for this application.
|
// Fetch the current receipt for this application.
|
||||||
- (NSData*)fetchDeviceReceipt {
|
- (NSData*)fetchDeviceReceipt
|
||||||
|
{
|
||||||
NSURL *receiptURL = [NSBundle bundleForClass:[self class]].appStoreReceiptURL;
|
NSURL *receiptURL = [NSBundle bundleForClass:[self class]].appStoreReceiptURL;
|
||||||
NSData *receipt = [NSData dataWithContentsOfURL:receiptURL];
|
NSData *receipt = [NSData dataWithContentsOfURL:receiptURL];
|
||||||
return receipt;
|
return receipt;
|
||||||
@ -22,6 +22,7 @@ FOUNDATION_EXPORT NSString *const FBSDKTimeSpentFilename;
|
|||||||
|
|
||||||
// Class to encapsulate persisting of time spent data collected by [FBSDKAppEvents activateApp]. The activate app App Event is
|
// Class to encapsulate persisting of time spent data collected by [FBSDKAppEvents activateApp]. The activate app App Event is
|
||||||
// logged when restore: is called with sufficient time since the last deactivation.
|
// logged when restore: is called with sufficient time since the last deactivation.
|
||||||
|
NS_SWIFT_NAME(TimeSpentData)
|
||||||
@interface FBSDKTimeSpentData : NSObject
|
@interface FBSDKTimeSpentData : NSObject
|
||||||
|
|
||||||
+ (void)suspend;
|
+ (void)suspend;
|
||||||
@ -154,9 +154,9 @@ static const long INACTIVE_SECONDS_QUANTA[] =
|
|||||||
FBSDKTimeSpentPersistKeySessionID : _sessionID,
|
FBSDKTimeSpentPersistKeySessionID : _sessionID,
|
||||||
};
|
};
|
||||||
|
|
||||||
NSString *content = [FBSDKInternalUtility JSONStringForObject:timeSpentData error:NULL invalidObjectHandler:NULL];
|
NSString *content = [FBSDKBasicUtility JSONStringForObject:timeSpentData error:NULL invalidObjectHandler:NULL];
|
||||||
|
|
||||||
[content writeToFile:[FBSDKAppEventsUtility persistenceFilePath:FBSDKTimeSpentFilename]
|
[content writeToFile:[FBSDKBasicUtility persistenceFilePath:FBSDKTimeSpentFilename]
|
||||||
atomically:YES
|
atomically:YES
|
||||||
encoding:NSASCIIStringEncoding
|
encoding:NSASCIIStringEncoding
|
||||||
error:nil];
|
error:nil];
|
||||||
@ -181,7 +181,7 @@ static const long INACTIVE_SECONDS_QUANTA[] =
|
|||||||
if (!_isCurrentlyLoaded) {
|
if (!_isCurrentlyLoaded) {
|
||||||
|
|
||||||
NSString *content =
|
NSString *content =
|
||||||
[[NSString alloc] initWithContentsOfFile:[FBSDKAppEventsUtility persistenceFilePath:FBSDKTimeSpentFilename]
|
[[NSString alloc] initWithContentsOfFile:[FBSDKBasicUtility persistenceFilePath:FBSDKTimeSpentFilename]
|
||||||
usedEncoding:nil
|
usedEncoding:nil
|
||||||
error:nil];
|
error:nil];
|
||||||
|
|
||||||
@ -203,7 +203,7 @@ static const long INACTIVE_SECONDS_QUANTA[] =
|
|||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
NSDictionary *results = [FBSDKInternalUtility objectForJSONString:content error:NULL];
|
NSDictionary<id, id> *results = [FBSDKBasicUtility objectForJSONString:content error:NULL];
|
||||||
|
|
||||||
_lastSuspendTime = [results[FBSDKTimeSpentPersistKeyLastSuspendTime] longValue];
|
_lastSuspendTime = [results[FBSDKTimeSpentPersistKeyLastSuspendTime] longValue];
|
||||||
|
|
||||||
48
Example/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/AppEvents/Internal/FBSDKUserDataStore.h
generated
Normal file
48
Example/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/AppEvents/Internal/FBSDKUserDataStore.h
generated
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
// 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 "FBSDKAppEvents+Internal.h"
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_BEGIN
|
||||||
|
|
||||||
|
NS_SWIFT_NAME(UserDataStore)
|
||||||
|
@interface FBSDKUserDataStore : NSObject
|
||||||
|
|
||||||
|
+ (void)setAndHashUserEmail:(nullable NSString *)email
|
||||||
|
firstName:(nullable NSString *)firstName
|
||||||
|
lastName:(nullable NSString *)lastName
|
||||||
|
phone:(nullable NSString *)phone
|
||||||
|
dateOfBirth:(nullable NSString *)dateOfBirth
|
||||||
|
gender:(nullable NSString *)gender
|
||||||
|
city:(nullable NSString *)city
|
||||||
|
state:(nullable NSString *)state
|
||||||
|
zip:(nullable NSString *)zip
|
||||||
|
country:(nullable NSString *)country;
|
||||||
|
+ (void)setAndHashData:(nullable NSString *)data
|
||||||
|
forType:(FBSDKAppEventUserDataType)type;
|
||||||
|
+ (void)setHashData:(nullable NSString *)hashData
|
||||||
|
forType:(FBSDKAppEventUserDataType)type;
|
||||||
|
+ (nullable NSString *)getHashedData;
|
||||||
|
+ (nullable NSString *)getHashedDataForType:(FBSDKAppEventUserDataType)type;
|
||||||
|
+ (void)clearDataForType:(FBSDKAppEventUserDataType)type;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_END
|
||||||
199
Example/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/AppEvents/Internal/FBSDKUserDataStore.m
generated
Normal file
199
Example/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/AppEvents/Internal/FBSDKUserDataStore.m
generated
Normal file
@ -0,0 +1,199 @@
|
|||||||
|
// 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 "FBSDKUserDataStore.h"
|
||||||
|
|
||||||
|
#import "FBSDKAppEventsUtility.h"
|
||||||
|
#import "FBSDKLogger.h"
|
||||||
|
#import "FBSDKSettings.h"
|
||||||
|
#import "FBSDKUtility.h"
|
||||||
|
|
||||||
|
static NSString *const FBSDKUserDataKey = @"com.facebook.appevents.UserDataStore.userData";
|
||||||
|
|
||||||
|
static NSMutableDictionary<NSString *, NSString *> *hashedUserData;
|
||||||
|
static dispatch_queue_t serialQueue;
|
||||||
|
|
||||||
|
@implementation FBSDKUserDataStore
|
||||||
|
|
||||||
|
+ (void)initialize
|
||||||
|
{
|
||||||
|
serialQueue = dispatch_queue_create("com.facebook.appevents.UserDataStore", DISPATCH_QUEUE_SERIAL);
|
||||||
|
NSString *userData = [[NSUserDefaults standardUserDefaults] stringForKey:FBSDKUserDataKey];
|
||||||
|
if (userData) {
|
||||||
|
hashedUserData = (NSMutableDictionary<NSString *, NSString *> *)[NSJSONSerialization JSONObjectWithData:[userData dataUsingEncoding:NSUTF8StringEncoding]
|
||||||
|
options:NSJSONReadingMutableContainers
|
||||||
|
error:nil];
|
||||||
|
}
|
||||||
|
if (!hashedUserData) {
|
||||||
|
hashedUserData = [[NSMutableDictionary alloc] init];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (void)setAndHashUserEmail:(nullable NSString *)email
|
||||||
|
firstName:(nullable NSString *)firstName
|
||||||
|
lastName:(nullable NSString *)lastName
|
||||||
|
phone:(nullable NSString *)phone
|
||||||
|
dateOfBirth:(nullable NSString *)dateOfBirth
|
||||||
|
gender:(nullable NSString *)gender
|
||||||
|
city:(nullable NSString *)city
|
||||||
|
state:(nullable NSString *)state
|
||||||
|
zip:(nullable NSString *)zip
|
||||||
|
country:(nullable NSString *)country
|
||||||
|
{
|
||||||
|
NSMutableDictionary *ud = [[NSMutableDictionary alloc] init];
|
||||||
|
if (email) {
|
||||||
|
ud[FBSDKAppEventEmail] = [FBSDKUserDataStore encryptData:email type:FBSDKAppEventEmail];
|
||||||
|
}
|
||||||
|
if (firstName) {
|
||||||
|
ud[FBSDKAppEventFirstName] = [FBSDKUserDataStore encryptData:firstName type:FBSDKAppEventFirstName];
|
||||||
|
}
|
||||||
|
if (lastName) {
|
||||||
|
ud[FBSDKAppEventLastName] = [FBSDKUserDataStore encryptData:lastName type:FBSDKAppEventLastName];
|
||||||
|
}
|
||||||
|
if (phone) {
|
||||||
|
ud[FBSDKAppEventPhone] = [FBSDKUserDataStore encryptData:phone type:FBSDKAppEventPhone];
|
||||||
|
}
|
||||||
|
if (dateOfBirth) {
|
||||||
|
ud[FBSDKAppEventDateOfBirth] = [FBSDKUserDataStore encryptData:dateOfBirth type:FBSDKAppEventDateOfBirth];
|
||||||
|
}
|
||||||
|
if (gender) {
|
||||||
|
ud[FBSDKAppEventGender] = [FBSDKUserDataStore encryptData:gender type:FBSDKAppEventGender];
|
||||||
|
}
|
||||||
|
if (city) {
|
||||||
|
ud[FBSDKAppEventCity] = [FBSDKUserDataStore encryptData:city type:FBSDKAppEventCity];
|
||||||
|
}
|
||||||
|
if (state) {
|
||||||
|
ud[FBSDKAppEventState] = [FBSDKUserDataStore encryptData:state type:FBSDKAppEventState];
|
||||||
|
}
|
||||||
|
if (zip) {
|
||||||
|
ud[FBSDKAppEventZip] = [FBSDKUserDataStore encryptData:zip type:FBSDKAppEventZip];
|
||||||
|
}
|
||||||
|
if (country) {
|
||||||
|
ud[FBSDKAppEventCountry] = [FBSDKUserDataStore encryptData:country type:FBSDKAppEventCountry];
|
||||||
|
}
|
||||||
|
|
||||||
|
dispatch_async(serialQueue, ^{
|
||||||
|
hashedUserData = [ud mutableCopy];
|
||||||
|
[[NSUserDefaults standardUserDefaults] setObject:[FBSDKUserDataStore stringByHashedData:hashedUserData]
|
||||||
|
forKey:FBSDKUserDataKey];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (void)setAndHashData:(nullable NSString *)data
|
||||||
|
forType:(FBSDKAppEventUserDataType)type
|
||||||
|
{
|
||||||
|
[FBSDKUserDataStore setHashData:[FBSDKUserDataStore encryptData:data type:type]
|
||||||
|
forType:type];
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (void)setHashData:(nullable NSString *)hashData
|
||||||
|
forType:(FBSDKAppEventUserDataType)type
|
||||||
|
{
|
||||||
|
dispatch_async(serialQueue, ^{
|
||||||
|
if (!hashData) {
|
||||||
|
[hashedUserData removeObjectForKey:type];
|
||||||
|
} else {
|
||||||
|
hashedUserData[type] = hashData;
|
||||||
|
}
|
||||||
|
[[NSUserDefaults standardUserDefaults] setObject:[FBSDKUserDataStore stringByHashedData:hashedUserData]
|
||||||
|
forKey:FBSDKUserDataKey];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (void)clearDataForType:(FBSDKAppEventUserDataType)type
|
||||||
|
{
|
||||||
|
[FBSDKUserDataStore setAndHashData:nil forType:type];
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (NSString *)getHashedData
|
||||||
|
{
|
||||||
|
__block NSString *hashedUserDataString;
|
||||||
|
dispatch_sync(serialQueue, ^{
|
||||||
|
hashedUserDataString = [FBSDKUserDataStore stringByHashedData:hashedUserData];
|
||||||
|
});
|
||||||
|
return hashedUserDataString;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (NSString *)getHashedDataForType:(FBSDKAppEventUserDataType)type
|
||||||
|
{
|
||||||
|
__block NSString *hashedData;
|
||||||
|
dispatch_sync(serialQueue, ^{
|
||||||
|
hashedData = [hashedUserData objectForKey:type];
|
||||||
|
});
|
||||||
|
return hashedData;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (NSString *)stringByHashedData:(id)hashedData
|
||||||
|
{
|
||||||
|
NSError *error;
|
||||||
|
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:hashedData
|
||||||
|
options:0
|
||||||
|
error:&error];
|
||||||
|
if (jsonData) {
|
||||||
|
return [[NSString alloc] initWithData:jsonData
|
||||||
|
encoding:NSUTF8StringEncoding];
|
||||||
|
} else {
|
||||||
|
[FBSDKAppEventsUtility logAndNotify:[NSString stringWithFormat:@"Invalid json object: %@", error]];
|
||||||
|
return @"";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (NSString *)encryptData:(NSString *)data
|
||||||
|
type:(FBSDKAppEventUserDataType)type
|
||||||
|
{
|
||||||
|
if (data.length == 0 || [FBSDKUserDataStore maybeSHA256Hashed:data]) {
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
return [FBSDKUtility SHA256Hash:[FBSDKUserDataStore normalizeData:data type:type]];
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (NSString *)normalizeData:(NSString *)data
|
||||||
|
type:(FBSDKAppEventUserDataType)type
|
||||||
|
{
|
||||||
|
NSString *normalizedData = @"";
|
||||||
|
NSSet<FBSDKAppEventUserDataType> *set = [NSSet setWithArray:
|
||||||
|
@[FBSDKAppEventEmail, FBSDKAppEventFirstName, FBSDKAppEventLastName, FBSDKAppEventCity, FBSDKAppEventState, FBSDKAppEventCountry]];
|
||||||
|
if ([set containsObject:type]) {
|
||||||
|
normalizedData = [data stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
|
||||||
|
normalizedData = normalizedData.lowercaseString;
|
||||||
|
} else if ([type isEqualToString:FBSDKAppEventPhone]) {
|
||||||
|
NSError *error = nil;
|
||||||
|
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"[^0-9]"
|
||||||
|
options:NSRegularExpressionCaseInsensitive
|
||||||
|
error:&error
|
||||||
|
];
|
||||||
|
normalizedData = [regex stringByReplacingMatchesInString:data
|
||||||
|
options:0
|
||||||
|
range:NSMakeRange(0, data.length)
|
||||||
|
withTemplate:@""
|
||||||
|
];
|
||||||
|
} else if ([type isEqualToString:FBSDKAppEventGender]) {
|
||||||
|
NSString *temp = [data stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
|
||||||
|
temp = temp.lowercaseString;
|
||||||
|
normalizedData = temp.length > 0 ? [temp substringToIndex:1]: @"";
|
||||||
|
}
|
||||||
|
return normalizedData;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (BOOL)maybeSHA256Hashed:(NSString *)data
|
||||||
|
{
|
||||||
|
NSRange range = [data rangeOfString:@"[A-Fa-f0-9]{64}" options:NSRegularExpressionSearch];
|
||||||
|
return (data.length == 64) && (range.location != NSNotFound);
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
@ -18,21 +18,20 @@
|
|||||||
|
|
||||||
#import <Foundation/Foundation.h>
|
#import <Foundation/Foundation.h>
|
||||||
|
|
||||||
typedef void (^FBSDKURLSessionTaskHandler)(NSError *error,
|
NS_ASSUME_NONNULL_BEGIN
|
||||||
NSURLResponse *response,
|
|
||||||
NSData *responseData);
|
|
||||||
|
|
||||||
@interface FBSDKURLSessionTask : NSObject
|
@interface FBSDKRestrictiveDataFilterManager : NSObject
|
||||||
|
|
||||||
- (instancetype)init NS_UNAVAILABLE;
|
- (instancetype)init NS_UNAVAILABLE;
|
||||||
+ (instancetype)new NS_UNAVAILABLE;
|
+ (instancetype)new NS_UNAVAILABLE;
|
||||||
|
|
||||||
- (instancetype)initWithRequest:(NSURLRequest *)request
|
+ (void)enable;
|
||||||
fromSession:(NSURLSession *)session
|
+ (void)updateFilters:(nullable NSDictionary<NSString *, id> *)restrictiveParams;
|
||||||
completionHandler:(FBSDKURLSessionTaskHandler)handler
|
|
||||||
NS_DESIGNATED_INITIALIZER;
|
|
||||||
|
|
||||||
- (void)cancel;
|
+ (void)processEvents:(NSMutableArray<NSDictionary<NSString *, id> *> *)events;
|
||||||
- (void)start;
|
+ (nullable NSDictionary<NSString *, id> *)processParameters:(nullable NSDictionary<NSString *, id> *)parameters
|
||||||
|
eventName:(NSString *)eventName;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_END
|
||||||
@ -0,0 +1,165 @@
|
|||||||
|
// 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 "FBSDKRestrictiveDataFilterManager.h"
|
||||||
|
|
||||||
|
#import "FBSDKBasicUtility.h"
|
||||||
|
#import "FBSDKTypeUtility.h"
|
||||||
|
|
||||||
|
@interface FBSDKRestrictiveEventFilter : NSObject
|
||||||
|
|
||||||
|
@property (nonatomic, readonly, copy) NSString *eventName;
|
||||||
|
@property (nonatomic, readonly, copy) NSDictionary<NSString *, id> *eventParams;
|
||||||
|
|
||||||
|
- (instancetype)init NS_UNAVAILABLE;
|
||||||
|
+ (instancetype)new NS_UNAVAILABLE;
|
||||||
|
|
||||||
|
-(instancetype)initWithEventName:(NSString *)eventName
|
||||||
|
eventParams:(NSDictionary<NSString *, id> *)eventParams;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation FBSDKRestrictiveEventFilter
|
||||||
|
|
||||||
|
-(instancetype)initWithEventName:(NSString *)eventName
|
||||||
|
eventParams:(NSDictionary<NSString *, id> *)eventParams
|
||||||
|
{
|
||||||
|
self = [super init];
|
||||||
|
if (self) {
|
||||||
|
_eventName = eventName;
|
||||||
|
_eventParams = eventParams;
|
||||||
|
}
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation FBSDKRestrictiveDataFilterManager
|
||||||
|
|
||||||
|
static BOOL isRestrictiveEventFilterEnabled = NO;
|
||||||
|
|
||||||
|
static NSMutableArray<FBSDKRestrictiveEventFilter *> *_params;
|
||||||
|
static NSMutableSet<NSString *> *_deprecatedEvents;
|
||||||
|
|
||||||
|
+ (void)updateFilters:(nullable NSDictionary<NSString *, id> *)restrictiveParams
|
||||||
|
{
|
||||||
|
if (!isRestrictiveEventFilterEnabled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (restrictiveParams.count > 0) {
|
||||||
|
[_params removeAllObjects];
|
||||||
|
[_deprecatedEvents removeAllObjects];
|
||||||
|
NSMutableArray<FBSDKRestrictiveEventFilter *> *eventFilterArray = [NSMutableArray array];
|
||||||
|
NSMutableSet<NSString *> *deprecatedEventSet = [NSMutableSet set];
|
||||||
|
for (NSString *eventName in restrictiveParams.allKeys) {
|
||||||
|
if (restrictiveParams[eventName][@"is_deprecated_event"]) {
|
||||||
|
[deprecatedEventSet addObject:eventName];
|
||||||
|
}
|
||||||
|
if (restrictiveParams[eventName][@"restrictive_param"]) {
|
||||||
|
FBSDKRestrictiveEventFilter *restrictiveEventFilter = [[FBSDKRestrictiveEventFilter alloc] initWithEventName:eventName
|
||||||
|
eventParams:restrictiveParams[eventName][@"restrictive_param"]];
|
||||||
|
[eventFilterArray addObject:restrictiveEventFilter];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_params = eventFilterArray;
|
||||||
|
_deprecatedEvents = deprecatedEventSet;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (nullable NSString *)getMatchedDataTypeWithEventName:(NSString *)eventName
|
||||||
|
paramKey:(NSString *)paramKey
|
||||||
|
{
|
||||||
|
// match by params in custom events with event name
|
||||||
|
for (FBSDKRestrictiveEventFilter *filter in _params) {
|
||||||
|
if ([filter.eventName isEqualToString:eventName]) {
|
||||||
|
NSString *type = [FBSDKTypeUtility stringValue:filter.eventParams[paramKey]];
|
||||||
|
if (type) {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (BOOL)isDeprecatedEvent:(NSString *)eventName
|
||||||
|
{
|
||||||
|
return [_deprecatedEvents containsObject:eventName];
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (void)processEvents:(NSMutableArray<NSDictionary<NSString *, id> *> *)events
|
||||||
|
{
|
||||||
|
if (!isRestrictiveEventFilterEnabled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
NSArray<NSDictionary<NSString *, id> *> *eventArray = [events copy];
|
||||||
|
for (NSDictionary<NSString *, NSDictionary<NSString *, id> *> *event in eventArray) {
|
||||||
|
if ([FBSDKRestrictiveDataFilterManager isDeprecatedEvent:event[@"event"][@"_eventName"]]) {
|
||||||
|
[events removeObject:event];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (NSDictionary<NSString *,id> *)processParameters:(NSDictionary<NSString *,id> *)parameters
|
||||||
|
eventName:(NSString *)eventName
|
||||||
|
{
|
||||||
|
if (!isRestrictiveEventFilterEnabled) {
|
||||||
|
return parameters;
|
||||||
|
}
|
||||||
|
if (parameters) {
|
||||||
|
NSMutableDictionary<NSString *, id> *params = [NSMutableDictionary dictionaryWithDictionary:parameters];
|
||||||
|
NSMutableDictionary<NSString *, NSString *> *restrictedParams = [NSMutableDictionary dictionary];
|
||||||
|
|
||||||
|
for (NSString *key in [parameters keyEnumerator]) {
|
||||||
|
NSString *type = [FBSDKRestrictiveDataFilterManager getMatchedDataTypeWithEventName:eventName
|
||||||
|
paramKey:key];
|
||||||
|
if (type) {
|
||||||
|
[restrictedParams setObject:type forKey:key];
|
||||||
|
[params removeObjectForKey:key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ([[restrictedParams allKeys] count] > 0) {
|
||||||
|
NSString *restrictedParamsJSONString = [FBSDKBasicUtility JSONStringForObject:restrictedParams
|
||||||
|
error:NULL
|
||||||
|
invalidObjectHandler:NULL];
|
||||||
|
[FBSDKBasicUtility dictionary:params setObject:restrictedParamsJSONString forKey:@"_restrictedParams"];
|
||||||
|
}
|
||||||
|
|
||||||
|
return [params copy];
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (void)enable
|
||||||
|
{
|
||||||
|
isRestrictiveEventFilterEnabled = YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark Helper functions
|
||||||
|
|
||||||
|
+ (BOOL)isMatchedWithPattern:(NSString *)pattern
|
||||||
|
text:(NSString *)text
|
||||||
|
{
|
||||||
|
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
|
||||||
@ -22,16 +22,21 @@
|
|||||||
|
|
||||||
NS_ASSUME_NONNULL_BEGIN
|
NS_ASSUME_NONNULL_BEGIN
|
||||||
|
|
||||||
/*! The version of the App Link protocol that this library supports */
|
/** The version of the App Link protocol that this library supports */
|
||||||
FOUNDATION_EXPORT NSString *const FBSDKAppLinkVersion;
|
FOUNDATION_EXPORT NSString *const FBSDKAppLinkVersion
|
||||||
|
NS_SWIFT_NAME(AppLinkVersion);
|
||||||
|
|
||||||
/*!
|
/**
|
||||||
Contains App Link metadata relevant for navigation on this device
|
Contains App Link metadata relevant for navigation on this device
|
||||||
derived from the HTML at a given URL.
|
derived from the HTML at a given URL.
|
||||||
*/
|
*/
|
||||||
|
NS_SWIFT_NAME(AppLink)
|
||||||
@interface FBSDKAppLink : NSObject
|
@interface FBSDKAppLink : NSObject
|
||||||
|
|
||||||
/*!
|
- (instancetype)init NS_UNAVAILABLE;
|
||||||
|
+ (instancetype)new NS_UNAVAILABLE;
|
||||||
|
|
||||||
|
/**
|
||||||
Creates a FBSDKAppLink with the given list of FBSDKAppLinkTargets and target URL.
|
Creates a FBSDKAppLink with the given list of FBSDKAppLinkTargets and target URL.
|
||||||
|
|
||||||
Generally, this will only be used by implementers of the FBSDKAppLinkResolving protocol,
|
Generally, this will only be used by implementers of the FBSDKAppLinkResolving protocol,
|
||||||
@ -42,20 +47,21 @@ FOUNDATION_EXPORT NSString *const FBSDKAppLinkVersion;
|
|||||||
from App Link metadata.
|
from App Link metadata.
|
||||||
@param webURL the fallback web URL, if any, for the app link.
|
@param webURL the fallback web URL, if any, for the app link.
|
||||||
*/
|
*/
|
||||||
+ (instancetype)appLinkWithSourceURL:(NSURL *)sourceURL
|
+ (instancetype)appLinkWithSourceURL:(nullable NSURL *)sourceURL
|
||||||
targets:(NSArray<FBSDKAppLinkTarget *> *)targets
|
targets:(NSArray<FBSDKAppLinkTarget *> *)targets
|
||||||
webURL:(nullable NSURL *)webURL;
|
webURL:(nullable NSURL *)webURL
|
||||||
|
NS_SWIFT_NAME(init(sourceURL:targets:webURL:));
|
||||||
|
|
||||||
/*! The URL from which this FBSDKAppLink was derived */
|
/** The URL from which this FBSDKAppLink was derived */
|
||||||
@property (nonatomic, strong, readonly) NSURL *sourceURL;
|
@property (nonatomic, strong, readonly, nullable) NSURL *sourceURL;
|
||||||
|
|
||||||
/*!
|
/**
|
||||||
The ordered list of targets applicable to this platform that will be used
|
The ordered list of targets applicable to this platform that will be used
|
||||||
for navigation.
|
for navigation.
|
||||||
*/
|
*/
|
||||||
@property (nonatomic, copy, readonly) NSArray<FBSDKAppLinkTarget *> *targets;
|
@property (nonatomic, copy, readonly) NSArray<FBSDKAppLinkTarget *> *targets;
|
||||||
|
|
||||||
/*! The fallback web URL to use if no targets are installed on this device. */
|
/** The fallback web URL to use if no targets are installed on this device. */
|
||||||
@property (nonatomic, strong, readonly, nullable) NSURL *webURL;
|
@property (nonatomic, strong, readonly, nullable) NSURL *webURL;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
@ -23,17 +23,17 @@
|
|||||||
|
|
||||||
NS_ASSUME_NONNULL_BEGIN
|
NS_ASSUME_NONNULL_BEGIN
|
||||||
|
|
||||||
/*!
|
/**
|
||||||
The result of calling navigate on a FBSDKAppLinkNavigation
|
The result of calling navigate on a FBSDKAppLinkNavigation
|
||||||
*/
|
*/
|
||||||
typedef NS_ENUM(NSInteger, FBSDKAppLinkNavigationType) {
|
typedef NS_ENUM(NSInteger, FBSDKAppLinkNavigationType) {
|
||||||
/*! Indicates that the navigation failed and no app was opened */
|
/** Indicates that the navigation failed and no app was opened */
|
||||||
FBSDKAppLinkNavigationTypeFailure,
|
FBSDKAppLinkNavigationTypeFailure,
|
||||||
/*! Indicates that the navigation succeeded by opening the URL in the browser */
|
/** Indicates that the navigation succeeded by opening the URL in the browser */
|
||||||
FBSDKAppLinkNavigationTypeBrowser,
|
FBSDKAppLinkNavigationTypeBrowser,
|
||||||
/*! Indicates that the navigation succeeded by opening the URL in an app on the device */
|
/** Indicates that the navigation succeeded by opening the URL in an app on the device */
|
||||||
FBSDKAppLinkNavigationTypeApp
|
FBSDKAppLinkNavigationTypeApp
|
||||||
};
|
} NS_SWIFT_NAME(AppLinkNavigation.Type);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Describes the callback for appLinkFromURLInBackground.
|
Describes the callback for appLinkFromURLInBackground.
|
||||||
@ -41,67 +41,83 @@ typedef NS_ENUM(NSInteger, FBSDKAppLinkNavigationType) {
|
|||||||
@param error the error during the request, if any
|
@param error the error during the request, if any
|
||||||
|
|
||||||
*/
|
*/
|
||||||
typedef void (^FBSDKAppLinkNavigationHandler)(FBSDKAppLinkNavigationType navType, NSError * _Nullable error);
|
typedef void (^FBSDKAppLinkNavigationBlock)(FBSDKAppLinkNavigationType navType, NSError * _Nullable error)
|
||||||
|
NS_SWIFT_NAME(AppLinkNavigationBlock);
|
||||||
|
|
||||||
/*!
|
/**
|
||||||
Represents a pending request to navigate to an App Link. Most developers will
|
Represents a pending request to navigate to an App Link. Most developers will
|
||||||
simply use navigateToURLInBackground: to open a URL, but developers can build
|
simply use navigateToURLInBackground: to open a URL, but developers can build
|
||||||
custom requests with additional navigation and app data attached to them by
|
custom requests with additional navigation and app data attached to them by
|
||||||
creating FBSDKAppLinkNavigations themselves.
|
creating FBSDKAppLinkNavigations themselves.
|
||||||
*/
|
*/
|
||||||
NS_EXTENSION_UNAVAILABLE_IOS("Not available in app extension")
|
NS_EXTENSION_UNAVAILABLE_IOS("Not available in app extension")
|
||||||
|
NS_SWIFT_NAME(AppLinkNavigation)
|
||||||
@interface FBSDKAppLinkNavigation : NSObject
|
@interface FBSDKAppLinkNavigation : NSObject
|
||||||
|
|
||||||
/*!
|
- (instancetype)init NS_UNAVAILABLE;
|
||||||
|
+ (instancetype)new NS_UNAVAILABLE;
|
||||||
|
|
||||||
|
/**
|
||||||
|
The default resolver to be used for App Link resolution. If the developer has not set one explicitly,
|
||||||
|
a basic, built-in FBSDKWebViewAppLinkResolver will be used.
|
||||||
|
*/
|
||||||
|
@property (class, nonatomic, strong) id<FBSDKAppLinkResolving> defaultResolver
|
||||||
|
NS_SWIFT_NAME(default);
|
||||||
|
|
||||||
|
/**
|
||||||
The extras for the AppLinkNavigation. This will generally contain application-specific
|
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
|
data that should be passed along with the request, such as advertiser or affiliate IDs or
|
||||||
other such metadata relevant on this device.
|
other such metadata relevant on this device.
|
||||||
*/
|
*/
|
||||||
@property (nonatomic, copy, readonly) NSDictionary<NSString *, id> *extras;
|
@property (nonatomic, copy, readonly) NSDictionary<NSString *, id> *extras;
|
||||||
|
|
||||||
/*!
|
/**
|
||||||
The al_applink_data for the AppLinkNavigation. This will generally contain data common to
|
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
|
navigation attempts such as back-links, user agents, and other information that may be used
|
||||||
in routing and handling an App Link request.
|
in routing and handling an App Link request.
|
||||||
*/
|
*/
|
||||||
@property (nonatomic, copy, readonly) NSDictionary<NSString *, id> *appLinkData;
|
@property (nonatomic, copy, readonly) NSDictionary<NSString *, id> *appLinkData;
|
||||||
|
|
||||||
/*! The AppLink to navigate to */
|
/** The AppLink to navigate to */
|
||||||
@property (nonatomic, strong, readonly) FBSDKAppLink *appLink;
|
@property (nonatomic, strong, readonly) FBSDKAppLink *appLink;
|
||||||
|
|
||||||
/*!
|
/**
|
||||||
Return navigation type for current instance.
|
Return navigation type for current instance.
|
||||||
No-side-effect version of navigate:
|
No-side-effect version of navigate:
|
||||||
*/
|
*/
|
||||||
@property (nonatomic, readonly) FBSDKAppLinkNavigationType navigationType;
|
@property (nonatomic, readonly) FBSDKAppLinkNavigationType navigationType;
|
||||||
|
|
||||||
/*! Creates an AppLinkNavigation with the given link, extras, and App Link data */
|
/** Creates an AppLinkNavigation with the given link, extras, and App Link data */
|
||||||
+ (instancetype)navigationWithAppLink:(FBSDKAppLink *)appLink
|
+ (instancetype)navigationWithAppLink:(FBSDKAppLink *)appLink
|
||||||
extras:(NSDictionary<NSString *, id> *)extras
|
extras:(NSDictionary<NSString *, id> *)extras
|
||||||
appLinkData:(NSDictionary<NSString *, id> *)appLinkData;
|
appLinkData:(NSDictionary<NSString *, id> *)appLinkData
|
||||||
|
NS_SWIFT_NAME(init(appLink:extras:appLinkData:));
|
||||||
|
|
||||||
/*!
|
/**
|
||||||
Creates an NSDictionary with the correct format for iOS callback URLs,
|
Creates an NSDictionary with the correct format for iOS callback URLs,
|
||||||
to be used as 'appLinkData' argument in the call to navigationWithAppLink:extras:appLinkData:
|
to be used as 'appLinkData' argument in the call to navigationWithAppLink:extras:appLinkData:
|
||||||
*/
|
*/
|
||||||
+ (NSDictionary<NSString *, NSDictionary<NSString *, NSString *> *> *)callbackAppLinkDataForAppWithName:(NSString *)appName
|
+ (NSDictionary<NSString *, NSDictionary<NSString *, NSString *> *> *)callbackAppLinkDataForAppWithName:(NSString *)appName
|
||||||
url:(NSString *)url;
|
url:(NSString *)url
|
||||||
|
NS_SWIFT_NAME(callbackAppLinkData(forApp:url:));
|
||||||
|
|
||||||
/*! Performs the navigation */
|
/** Performs the navigation */
|
||||||
- (FBSDKAppLinkNavigationType)navigate:(NSError *__autoreleasing *)error;
|
- (FBSDKAppLinkNavigationType)navigate:(NSError **)error
|
||||||
|
__attribute__((swift_error(nonnull_error)));
|
||||||
|
|
||||||
/*! Returns a FBSDKAppLink for the given URL */
|
/** Returns a FBSDKAppLink for the given URL */
|
||||||
+ (void)resolveAppLink:(NSURL *)destination handler:(FBSDKAppLinkFromURLHandler)handler;
|
+ (void)resolveAppLink:(NSURL *)destination handler:(FBSDKAppLinkBlock)handler;
|
||||||
|
|
||||||
/*! Returns a FBSDKAppLink for the given URL using the given App Link resolution strategy */
|
/** Returns a FBSDKAppLink for the given URL using the given App Link resolution strategy */
|
||||||
+ (void)resolveAppLink:(NSURL *)destination
|
+ (void)resolveAppLink:(NSURL *)destination
|
||||||
resolver:(id<FBSDKAppLinkResolving>)resolver
|
resolver:(id<FBSDKAppLinkResolving>)resolver
|
||||||
handler:(FBSDKAppLinkFromURLHandler)handler;
|
handler:(FBSDKAppLinkBlock)handler;
|
||||||
|
|
||||||
/*! Navigates to a FBSDKAppLink and returns whether it opened in-app or in-browser */
|
/** Navigates to a FBSDKAppLink and returns whether it opened in-app or in-browser */
|
||||||
+ (FBSDKAppLinkNavigationType)navigateToAppLink:(FBSDKAppLink *)link error:(NSError *__autoreleasing *)error;
|
+ (FBSDKAppLinkNavigationType)navigateToAppLink:(FBSDKAppLink *)link error:(NSError **)error
|
||||||
|
__attribute__((swift_error(nonnull_error)));
|
||||||
|
|
||||||
/*!
|
/**
|
||||||
Returns a FBSDKAppLinkNavigationType based on a FBSDKAppLink.
|
Returns a FBSDKAppLinkNavigationType based on a FBSDKAppLink.
|
||||||
It's essentially a no-side-effect version of navigateToAppLink:error:,
|
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
|
allowing apps to determine flow based on the link type (e.g. open an
|
||||||
@ -109,28 +125,16 @@ NS_EXTENSION_UNAVAILABLE_IOS("Not available in app extension")
|
|||||||
*/
|
*/
|
||||||
+ (FBSDKAppLinkNavigationType)navigationTypeForLink:(FBSDKAppLink *)link;
|
+ (FBSDKAppLinkNavigationType)navigationTypeForLink:(FBSDKAppLink *)link;
|
||||||
|
|
||||||
/*! Navigates to a URL (an asynchronous action) and returns a FBSDKNavigationType */
|
/** Navigates to a URL (an asynchronous action) and returns a FBSDKNavigationType */
|
||||||
+ (void)navigateToURL:(NSURL *)destination handler:(FBSDKAppLinkNavigationHandler)handler;
|
+ (void)navigateToURL:(NSURL *)destination handler:(FBSDKAppLinkNavigationBlock)handler;
|
||||||
|
|
||||||
/*!
|
/**
|
||||||
Navigates to a URL (an asynchronous action) using the given App Link resolution
|
Navigates to a URL (an asynchronous action) using the given App Link resolution
|
||||||
strategy and returns a FBSDKNavigationType
|
strategy and returns a FBSDKNavigationType
|
||||||
*/
|
*/
|
||||||
+ (void)navigateToURL:(NSURL *)destination
|
+ (void)navigateToURL:(NSURL *)destination
|
||||||
resolver:(id<FBSDKAppLinkResolving>)resolver
|
resolver:(id<FBSDKAppLinkResolving>)resolver
|
||||||
handler:(FBSDKAppLinkNavigationHandler)handler;
|
handler:(FBSDKAppLinkNavigationBlock)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
|
@end
|
||||||
|
|
||||||
@ -208,21 +208,21 @@ static id<FBSDKAppLinkResolving> defaultResolver;
|
|||||||
|
|
||||||
+ (void)resolveAppLink:(NSURL *)destination
|
+ (void)resolveAppLink:(NSURL *)destination
|
||||||
resolver:(id<FBSDKAppLinkResolving>)resolver
|
resolver:(id<FBSDKAppLinkResolving>)resolver
|
||||||
handler:(FBSDKAppLinkFromURLHandler)handler {
|
handler:(FBSDKAppLinkBlock)handler {
|
||||||
[resolver appLinkFromURL:destination handler:handler];
|
[resolver appLinkFromURL:destination handler:handler];
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (void)resolveAppLink:(NSURL *)destination handler:(FBSDKAppLinkFromURLHandler)handler {
|
+ (void)resolveAppLink:(NSURL *)destination handler:(FBSDKAppLinkBlock)handler {
|
||||||
[self resolveAppLink:destination resolver:[self defaultResolver] handler:handler];
|
[self resolveAppLink:destination resolver:[self defaultResolver] handler:handler];
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (void)navigateToURL:(NSURL *)destination handler:(FBSDKAppLinkNavigationHandler)handler {
|
+ (void)navigateToURL:(NSURL *)destination handler:(FBSDKAppLinkNavigationBlock)handler {
|
||||||
[self navigateToURL:destination resolver:[self defaultResolver] handler:handler];
|
[self navigateToURL:destination resolver:[self defaultResolver] handler:handler];
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (void)navigateToURL:(NSURL *)destination
|
+ (void)navigateToURL:(NSURL *)destination
|
||||||
resolver:(id<FBSDKAppLinkResolving>)resolver
|
resolver:(id<FBSDKAppLinkResolving>)resolver
|
||||||
handler:(FBSDKAppLinkNavigationHandler)handler {
|
handler:(FBSDKAppLinkNavigationBlock)handler {
|
||||||
|
|
||||||
dispatch_async(dispatch_get_main_queue(), ^{
|
dispatch_async(dispatch_get_main_queue(), ^{
|
||||||
[self resolveAppLink:destination
|
[self resolveAppLink:destination
|
||||||
66
Example/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/AppLink/FBSDKAppLinkResolver.h
generated
Normal file
66
Example/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/AppLink/FBSDKAppLinkResolver.h
generated
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
// 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
|
||||||
|
|
||||||
|
/**
|
||||||
|
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 (^FBSDKAppLinksBlock)(NSDictionary<NSURL *, FBSDKAppLink *> * appLinks,
|
||||||
|
NSError * _Nullable error)
|
||||||
|
NS_SWIFT_NAME(AppLinksBlock);
|
||||||
|
|
||||||
|
/**
|
||||||
|
|
||||||
|
Provides an implementation of the FBSDKAppLinkResolving protocol that uses the Facebook App Link
|
||||||
|
Index API to resolve App Links given a URL. It also provides an additional helper method that can resolve
|
||||||
|
multiple App Links in a single call.
|
||||||
|
|
||||||
|
Usage of this type requires a client token. See `[FBSDKSettings setClientToken:]`
|
||||||
|
*/
|
||||||
|
|
||||||
|
NS_SWIFT_NAME(AppLinkResolver)
|
||||||
|
@interface FBSDKAppLinkResolver : NSObject<FBSDKAppLinkResolving>
|
||||||
|
|
||||||
|
- (instancetype)init NS_UNAVAILABLE;
|
||||||
|
+ (instancetype)new NS_UNAVAILABLE;
|
||||||
|
|
||||||
|
/**
|
||||||
|
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:(FBSDKAppLinksBlock)handler
|
||||||
|
NS_EXTENSION_UNAVAILABLE_IOS("Not available in app extension");
|
||||||
|
|
||||||
|
/**
|
||||||
|
Allocates and initializes a new instance of FBSDKAppLinkResolver.
|
||||||
|
*/
|
||||||
|
+ (instancetype)resolver
|
||||||
|
NS_SWIFT_NAME(init());
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_END
|
||||||
@ -20,13 +20,9 @@
|
|||||||
|
|
||||||
#import <UIKit/UIKit.h>
|
#import <UIKit/UIKit.h>
|
||||||
|
|
||||||
#import <Bolts/BFAppLink.h>
|
|
||||||
#import <Bolts/BFAppLinkTarget.h>
|
|
||||||
#import <Bolts/BFTask.h>
|
|
||||||
#import <Bolts/BFTaskCompletionSource.h>
|
|
||||||
|
|
||||||
#import "FBSDKAccessToken.h"
|
#import "FBSDKAccessToken.h"
|
||||||
#import "FBSDKAppLink.h"
|
#import "FBSDKAppLink.h"
|
||||||
|
#import "FBSDKAppLinkTarget.h"
|
||||||
#import "FBSDKGraphRequest+Internal.h"
|
#import "FBSDKGraphRequest+Internal.h"
|
||||||
#import "FBSDKGraphRequestConnection.h"
|
#import "FBSDKGraphRequestConnection.h"
|
||||||
#import "FBSDKInternalUtility.h"
|
#import "FBSDKInternalUtility.h"
|
||||||
@ -46,47 +42,35 @@ static NSString *const kAppLinksKey = @"app_links";
|
|||||||
|
|
||||||
@interface FBSDKAppLinkResolver ()
|
@interface FBSDKAppLinkResolver ()
|
||||||
|
|
||||||
@property (nonatomic, strong) NSMutableDictionary<NSURL *, BFAppLink *> *cachedBFAppLinks;
|
|
||||||
@property (nonatomic, strong) NSMutableDictionary<NSURL *, FBSDKAppLink *> *cachedFBSDKAppLinks;
|
@property (nonatomic, strong) NSMutableDictionary<NSURL *, FBSDKAppLink *> *cachedFBSDKAppLinks;
|
||||||
@property (nonatomic, assign) UIUserInterfaceIdiom userInterfaceIdiom;
|
@property (nonatomic, assign) UIUserInterfaceIdiom userInterfaceIdiom;
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@implementation FBSDKAppLinkResolver
|
@implementation FBSDKAppLinkResolver
|
||||||
|
|
||||||
static Class g_BFTaskCompletionSourceClass;
|
|
||||||
static Class g_BFAppLinkTargetClass;
|
|
||||||
static Class g_BFAppLinkClass;
|
|
||||||
static Class g_BFTaskClass;
|
|
||||||
|
|
||||||
+ (void)initialize
|
+ (void)initialize
|
||||||
{
|
{
|
||||||
if (self == [FBSDKAppLinkResolver class]) {
|
if (self == [FBSDKAppLinkResolver class]) {
|
||||||
g_BFTaskCompletionSourceClass = [FBSDKInternalUtility
|
|
||||||
resolveBoltsClassWithName:@"BFTaskCompletionSource"];
|
|
||||||
g_BFAppLinkTargetClass = [FBSDKInternalUtility resolveBoltsClassWithName:@"BFAppLinkTarget"];
|
|
||||||
g_BFTaskClass = [FBSDKInternalUtility resolveBoltsClassWithName:@"BFTask"];
|
|
||||||
g_BFAppLinkClass = [FBSDKInternalUtility resolveBoltsClassWithName:@"BFAppLink"];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (instancetype)initWithUserInterfaceIdiom:(UIUserInterfaceIdiom)userInterfaceIdiom
|
- (instancetype)initWithUserInterfaceIdiom:(UIUserInterfaceIdiom)userInterfaceIdiom
|
||||||
{
|
{
|
||||||
if (self = [super init]) {
|
if (self = [super init]) {
|
||||||
self.cachedBFAppLinks = [NSMutableDictionary dictionary];
|
|
||||||
self.cachedFBSDKAppLinks = [NSMutableDictionary dictionary];
|
self.cachedFBSDKAppLinks = [NSMutableDictionary dictionary];
|
||||||
self.userInterfaceIdiom = userInterfaceIdiom;
|
self.userInterfaceIdiom = userInterfaceIdiom;
|
||||||
}
|
}
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)appLinkFromURL:(NSURL *)url handler:(FBSDKAppLinkFromURLHandler)handler
|
- (void)appLinkFromURL:(NSURL *)url handler:(FBSDKAppLinkBlock)handler
|
||||||
{
|
{
|
||||||
[self appLinksFromURLs:@[url] handler:^(NSDictionary<NSURL *, FBSDKAppLink *> *urls, NSError * _Nullable error) {
|
[self appLinksFromURLs:@[url] handler:^(NSDictionary<NSURL *, FBSDKAppLink *> *urls, NSError * _Nullable error) {
|
||||||
handler(urls[url], error);
|
handler(urls[url], error);
|
||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)appLinksFromURLs:(NSArray<NSURL *> *)urls handler:(FBSDKAppLinksFromURLArrayHandler)handler
|
- (void)appLinksFromURLs:(NSArray<NSURL *> *)urls handler:(FBSDKAppLinksBlock)handler
|
||||||
{
|
{
|
||||||
if (![FBSDKSettings clientToken] && ![FBSDKAccessToken currentAccessToken]) {
|
if (![FBSDKSettings clientToken] && ![FBSDKAccessToken currentAccessToken]) {
|
||||||
[FBSDKLogger singleShotLogEntry:FBSDKLoggingBehaviorDeveloperErrors
|
[FBSDKLogger singleShotLogEntry:FBSDKLoggingBehaviorDeveloperErrors
|
||||||
@ -166,7 +150,7 @@ static Class g_BFTaskClass;
|
|||||||
NSURL *fallbackUrl = webFallbackString ? [NSURL URLWithString:webFallbackString] : url;
|
NSURL *fallbackUrl = webFallbackString ? [NSURL URLWithString:webFallbackString] : url;
|
||||||
|
|
||||||
NSNumber *shouldFallback = webTarget[kShouldFallbackKey];
|
NSNumber *shouldFallback = webTarget[kShouldFallbackKey];
|
||||||
if (shouldFallback && !shouldFallback.boolValue) {
|
if (shouldFallback != nil && !shouldFallback.boolValue) {
|
||||||
fallbackUrl = nil;
|
fallbackUrl = nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -182,115 +166,6 @@ static Class g_BFTaskClass;
|
|||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (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];
|
|
||||||
|
|
||||||
@synchronized (self.cachedBFAppLinks) {
|
|
||||||
for (NSURL *url in urls) {
|
|
||||||
if (self.cachedBFAppLinks[url]) {
|
|
||||||
appLinks[url] = self.cachedBFAppLinks[url];
|
|
||||||
} else {
|
|
||||||
[toFind addObject:url];
|
|
||||||
#pragma clang diagnostic push
|
|
||||||
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
|
||||||
NSString *toFindString = [url.absoluteString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
|
|
||||||
#pragma clang diagnostic pop
|
|
||||||
if (toFindString) {
|
|
||||||
[toFindStrings addObject:toFindString];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (toFind.count == 0) {
|
|
||||||
// All of the URLs have already been found.
|
|
||||||
return [g_BFTaskClass taskWithResult:appLinks];
|
|
||||||
}
|
|
||||||
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];
|
|
||||||
BFTaskCompletionSource *tcs = [g_BFTaskCompletionSourceClass taskCompletionSource];
|
|
||||||
[request startWithCompletionHandler:^(FBSDKGraphRequestConnection *connection, id result, NSError *error) {
|
|
||||||
if (error) {
|
|
||||||
[tcs setError:error];
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
for (NSURL *url in toFind) {
|
|
||||||
id nestedObject = result[url.absoluteString][kAppLinksKey];
|
|
||||||
NSMutableArray *rawTargets = [NSMutableArray array];
|
|
||||||
if (idiomSpecificField) {
|
|
||||||
[rawTargets addObjectsFromArray:nestedObject[idiomSpecificField]];
|
|
||||||
}
|
|
||||||
[rawTargets addObjectsFromArray:nestedObject[kIOSKey]];
|
|
||||||
|
|
||||||
NSMutableArray<BFAppLinkTarget *> *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]]];
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
BFAppLink *link = [g_BFAppLinkClass appLinkWithSourceURL:url
|
|
||||||
targets:targets
|
|
||||||
webURL:fallbackUrl];
|
|
||||||
@synchronized (self.cachedBFAppLinks) {
|
|
||||||
self.cachedBFAppLinks[url] = link;
|
|
||||||
}
|
|
||||||
appLinks[url] = link;
|
|
||||||
}
|
|
||||||
[tcs setResult:appLinks];
|
|
||||||
}];
|
|
||||||
return tcs.task;
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma clang diagnostic push
|
|
||||||
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
|
||||||
- (BFTask *)appLinkFromURLInBackground:(NSURL *)url
|
|
||||||
{
|
|
||||||
// Implement in terms of appLinksFromURLsInBackground
|
|
||||||
BFTask *resolveTask = [self appLinksFromURLsInBackground:@[url]];
|
|
||||||
return [resolveTask continueWithSuccessBlock:^id(BFTask *task) {
|
|
||||||
return task.result[url];
|
|
||||||
}];
|
|
||||||
}
|
|
||||||
#pragma clang diagnostic pop
|
|
||||||
|
|
||||||
+ (instancetype)resolver
|
+ (instancetype)resolver
|
||||||
{
|
{
|
||||||
return [[self alloc] initWithUserInterfaceIdiom:UI_USER_INTERFACE_IDIOM()];
|
return [[self alloc] initWithUserInterfaceIdiom:UI_USER_INTERFACE_IDIOM()];
|
||||||
@ -28,22 +28,16 @@ NS_ASSUME_NONNULL_BEGIN
|
|||||||
@param error the error during the request, if any
|
@param error the error during the request, if any
|
||||||
|
|
||||||
*/
|
*/
|
||||||
typedef void (^FBSDKAppLinkFromURLHandler)(FBSDKAppLink * _Nullable appLink, NSError * _Nullable error);
|
typedef void (^FBSDKAppLinkBlock)(FBSDKAppLink * _Nullable appLink, NSError * _Nullable error)
|
||||||
|
NS_SWIFT_NAME(AppLinkBlock);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
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
|
Implement this protocol to provide an alternate strategy for resolving
|
||||||
App Links that may include pre-fetching, caching, or querying for App Link
|
App Links that may include pre-fetching, caching, or querying for App Link
|
||||||
data from an index provided by a service provider.
|
data from an index provided by a service provider.
|
||||||
*/
|
*/
|
||||||
|
NS_SWIFT_NAME(AppLinkResolving)
|
||||||
@protocol FBSDKAppLinkResolving <NSObject>
|
@protocol FBSDKAppLinkResolving <NSObject>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -52,7 +46,7 @@ typedef void (^FBSDKAppLinksFromURLArrayHandler)(NSDictionary<NSURL *, FBSDKAppL
|
|||||||
@param url The URL to resolve into an App Link.
|
@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.
|
@param handler The completion block that will return an App Link for the given URL.
|
||||||
*/
|
*/
|
||||||
- (void)appLinkFromURL:(NSURL *)url handler:(FBSDKAppLinkFromURLHandler)handler
|
- (void)appLinkFromURL:(NSURL *)url handler:(FBSDKAppLinkBlock)handler
|
||||||
NS_EXTENSION_UNAVAILABLE_IOS("Not available in app extension");
|
NS_EXTENSION_UNAVAILABLE_IOS("Not available in app extension");
|
||||||
|
|
||||||
@end
|
@end
|
||||||
@ -26,71 +26,80 @@ NS_ASSUME_NONNULL_BEGIN
|
|||||||
@class FBSDKAppLink;
|
@class FBSDKAppLink;
|
||||||
@class FBSDKAppLinkReturnToRefererController;
|
@class FBSDKAppLinkReturnToRefererController;
|
||||||
|
|
||||||
/*!
|
/**
|
||||||
Protocol that a class can implement in order to be notified when the user has navigated back
|
Protocol that a class can implement in order to be notified when the user has navigated back
|
||||||
to the referer of an App Link.
|
to the referer of an App Link.
|
||||||
*/
|
*/
|
||||||
|
NS_SWIFT_NAME(AppLinkReturnToRefererControllerDelegate)
|
||||||
@protocol FBSDKAppLinkReturnToRefererControllerDelegate <NSObject>
|
@protocol FBSDKAppLinkReturnToRefererControllerDelegate <NSObject>
|
||||||
|
|
||||||
@optional
|
@optional
|
||||||
|
|
||||||
/*! Called when the user has tapped to navigate, but before the navigation has been performed. */
|
/** Called when the user has tapped to navigate, but before the navigation has been performed. */
|
||||||
- (void)returnToRefererController:(FBSDKAppLinkReturnToRefererController *)controller
|
- (void)returnToRefererController:(FBSDKAppLinkReturnToRefererController *)controller
|
||||||
willNavigateToAppLink:(FBSDKAppLink *)appLink;
|
willNavigateToAppLink:(FBSDKAppLink *)appLink
|
||||||
|
NS_SWIFT_NAME(return(to:willNavigateTo:));
|
||||||
|
|
||||||
/*! Called after the navigation has been attempted, with an indication of whether the referer
|
/** Called after the navigation has been attempted, with an indication of whether the referer
|
||||||
app link was successfully opened. */
|
app link was successfully opened. */
|
||||||
- (void)returnToRefererController:(FBSDKAppLinkReturnToRefererController *)controller
|
- (void)returnToRefererController:(FBSDKAppLinkReturnToRefererController *)controller
|
||||||
didNavigateToAppLink:(FBSDKAppLink *)url
|
didNavigateToAppLink:(FBSDKAppLink *)url
|
||||||
type:(FBSDKAppLinkNavigationType)type;
|
type:(FBSDKAppLinkNavigationType)type
|
||||||
|
NS_SWIFT_NAME(return(to:didNavigateTo:type:));
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
/*!
|
/**
|
||||||
A controller class that implements default behavior for a FBSDKAppLinkReturnToRefererView, including
|
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.
|
the ability to display the view above the navigation bar for navigation-based apps.
|
||||||
*/
|
*/
|
||||||
NS_EXTENSION_UNAVAILABLE_IOS("Not available in app extension")
|
NS_EXTENSION_UNAVAILABLE_IOS("Not available in app extension")
|
||||||
|
NS_SWIFT_NAME(AppLinkReturnToRefererController)
|
||||||
@interface FBSDKAppLinkReturnToRefererController : NSObject <FBSDKAppLinkReturnToRefererViewDelegate>
|
@interface FBSDKAppLinkReturnToRefererController : NSObject <FBSDKAppLinkReturnToRefererViewDelegate>
|
||||||
|
|
||||||
/*!
|
/**
|
||||||
The delegate that will be notified when the user navigates back to the referer.
|
The delegate that will be notified when the user navigates back to the referer.
|
||||||
*/
|
*/
|
||||||
@property (nonatomic, weak, nullable) id<FBSDKAppLinkReturnToRefererControllerDelegate> delegate;
|
@property (nonatomic, weak, nullable) id<FBSDKAppLinkReturnToRefererControllerDelegate> delegate;
|
||||||
|
|
||||||
/*!
|
/**
|
||||||
The FBSDKAppLinkReturnToRefererView this controller is controlling.
|
The FBSDKAppLinkReturnToRefererView this controller is controlling.
|
||||||
*/
|
*/
|
||||||
@property (nonatomic, strong) FBSDKAppLinkReturnToRefererView *view;
|
@property (nonatomic, strong) FBSDKAppLinkReturnToRefererView *view;
|
||||||
|
|
||||||
/*!
|
/**
|
||||||
Initializes a controller suitable for controlling a FBSDKAppLinkReturnToRefererView that is to be displayed
|
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).
|
contained within another UIView (i.e., not displayed above the navigation bar).
|
||||||
*/
|
*/
|
||||||
- (instancetype)init NS_DESIGNATED_INITIALIZER;
|
- (instancetype)init NS_DESIGNATED_INITIALIZER;
|
||||||
|
|
||||||
/*!
|
/**
|
||||||
Initializes a controller suitable for controlling a FBSDKAppLinkReturnToRefererView that is to be displayed
|
Initializes a controller suitable for controlling a FBSDKAppLinkReturnToRefererView that is to be displayed
|
||||||
displayed above the navigation bar.
|
displayed above the navigation bar.
|
||||||
*/
|
|
||||||
- (instancetype)initForDisplayAboveNavController:(UINavigationController *)navController;
|
|
||||||
|
|
||||||
/*!
|
@param navController The Navigation Controller for display above
|
||||||
|
*/
|
||||||
|
- (instancetype)initForDisplayAboveNavController:(UINavigationController *)navController
|
||||||
|
NS_SWIFT_NAME(init(navController:));
|
||||||
|
|
||||||
|
/**
|
||||||
Removes the view entirely from the navigation controller it is currently displayed in.
|
Removes the view entirely from the navigation controller it is currently displayed in.
|
||||||
*/
|
*/
|
||||||
- (void)removeFromNavController;
|
- (void)removeFromNavController;
|
||||||
|
|
||||||
/*!
|
/**
|
||||||
Shows the FBSDKAppLinkReturnToRefererView with the specified referer information. If nil or missing data,
|
Shows the FBSDKAppLinkReturnToRefererView with the specified referer information. If nil or missing data,
|
||||||
the view will not be displayed. */
|
the view will not be displayed. */
|
||||||
- (void)showViewForRefererAppLink:(FBSDKAppLink *)refererAppLink;
|
- (void)showViewForRefererAppLink:(FBSDKAppLink *)refererAppLink
|
||||||
|
NS_SWIFT_NAME(showView(forReferer:));
|
||||||
|
|
||||||
/*!
|
/**
|
||||||
Shows the FBSDKAppLinkReturnToRefererView with referer information extracted from the specified URL.
|
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. */
|
If nil or missing referer App Link data, the view will not be displayed. */
|
||||||
- (void)showViewForRefererURL:(NSURL *)url;
|
- (void)showViewForRefererURL:(NSURL *)url
|
||||||
|
NS_SWIFT_NAME(showView(forReferer:));
|
||||||
|
|
||||||
/*!
|
/**
|
||||||
Closes the view, possibly animating it.
|
Closes the view, possibly animating it.
|
||||||
*/
|
*/
|
||||||
- (void)closeViewAnimated:(BOOL)animated;
|
- (void)closeViewAnimated:(BOOL)animated;
|
||||||
@ -25,33 +25,35 @@ NS_ASSUME_NONNULL_BEGIN
|
|||||||
|
|
||||||
typedef NS_ENUM(NSUInteger, FBSDKIncludeStatusBarInSize) {
|
typedef NS_ENUM(NSUInteger, FBSDKIncludeStatusBarInSize) {
|
||||||
FBSDKIncludeStatusBarInSizeNever,
|
FBSDKIncludeStatusBarInSizeNever,
|
||||||
FBSDKIncludeStatusBarInSizeIOS7AndLater,
|
|
||||||
FBSDKIncludeStatusBarInSizeAlways,
|
FBSDKIncludeStatusBarInSizeAlways,
|
||||||
};
|
} NS_SWIFT_NAME(FBAppLinkReturnToRefererView.StatusBarSizeInclude);
|
||||||
|
|
||||||
@class FBSDKAppLinkReturnToRefererView;
|
@class FBSDKAppLinkReturnToRefererView;
|
||||||
@class FBSDKURL;
|
@class FBSDKURL;
|
||||||
|
|
||||||
/*!
|
/**
|
||||||
Protocol that a class can implement in order to be notified when the user has navigated back
|
Protocol that a class can implement in order to be notified when the user has navigated back
|
||||||
to the referer of an App Link.
|
to the referer of an App Link.
|
||||||
*/
|
*/
|
||||||
|
NS_SWIFT_NAME(AppLinkReturnToRefererViewDelegate)
|
||||||
@protocol FBSDKAppLinkReturnToRefererViewDelegate <NSObject>
|
@protocol FBSDKAppLinkReturnToRefererViewDelegate <NSObject>
|
||||||
|
|
||||||
/*!
|
/**
|
||||||
Called when the user has tapped inside the close button.
|
Called when the user has tapped inside the close button.
|
||||||
*/
|
*/
|
||||||
- (void)returnToRefererViewDidTapInsideCloseButton:(FBSDKAppLinkReturnToRefererView *)view;
|
- (void)returnToRefererViewDidTapInsideCloseButton:(FBSDKAppLinkReturnToRefererView *)view
|
||||||
|
NS_SWIFT_NAME(returnToRefererViewDidTapInsideCloseButton(_:));
|
||||||
|
|
||||||
/*!
|
/**
|
||||||
Called when the user has tapped inside the App Link portion of the view.
|
Called when the user has tapped inside the App Link portion of the view.
|
||||||
*/
|
*/
|
||||||
- (void)returnToRefererViewDidTapInsideLink:(FBSDKAppLinkReturnToRefererView *)view
|
- (void)returnToRefererViewDidTapInsideLink:(FBSDKAppLinkReturnToRefererView *)view
|
||||||
link:(FBSDKAppLink *)link;
|
link:(FBSDKAppLink *)link
|
||||||
|
NS_SWIFT_NAME(returnToRefererView(_:didTapInside:));
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
/*!
|
/**
|
||||||
Provides a UIView that displays a button allowing users to navigate back to the
|
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
|
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
|
contained referer data. The user can also close the view by clicking a close button
|
||||||
@ -59,31 +61,33 @@ typedef NS_ENUM(NSUInteger, FBSDKIncludeStatusBarInSize) {
|
|||||||
referer data, it will have zero size and no UI will be displayed.
|
referer data, it will have zero size and no UI will be displayed.
|
||||||
*/
|
*/
|
||||||
NS_EXTENSION_UNAVAILABLE_IOS("Not available in app extension")
|
NS_EXTENSION_UNAVAILABLE_IOS("Not available in app extension")
|
||||||
|
NS_SWIFT_NAME(FBAppLinkReturnToRefererView)
|
||||||
@interface FBSDKAppLinkReturnToRefererView : UIView
|
@interface FBSDKAppLinkReturnToRefererView : UIView
|
||||||
|
|
||||||
/*!
|
/**
|
||||||
The delegate that will be notified when the user navigates back to the referer.
|
The delegate that will be notified when the user navigates back to the referer.
|
||||||
*/
|
*/
|
||||||
@property (nonatomic, weak, nullable) id<FBSDKAppLinkReturnToRefererViewDelegate> delegate;
|
@property (nonatomic, weak, nullable) id<FBSDKAppLinkReturnToRefererViewDelegate> delegate;
|
||||||
|
|
||||||
/*!
|
/**
|
||||||
The color of the text label and close button.
|
The color of the text label and close button.
|
||||||
*/
|
*/
|
||||||
@property (nonatomic, strong) UIColor *textColor;
|
@property (nonatomic, strong) UIColor *textColor;
|
||||||
|
|
||||||
@property (nonatomic, strong) FBSDKAppLink *refererAppLink;
|
@property (nonatomic, strong) FBSDKAppLink *refererAppLink;
|
||||||
|
|
||||||
/*!
|
/**
|
||||||
Indicates whether to extend the size of the view to include the current status bar
|
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
|
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.
|
above; this property has no effect on earlier versions of iOS.
|
||||||
*/
|
*/
|
||||||
@property (nonatomic, assign) FBSDKIncludeStatusBarInSize includeStatusBarInSize;
|
@property (nonatomic, assign) FBSDKIncludeStatusBarInSize includeStatusBarInSize
|
||||||
|
NS_SWIFT_NAME(statusBarSizeInclude);
|
||||||
|
|
||||||
/*!
|
/**
|
||||||
Indicates whether the user has closed the view by clicking the close button.
|
Indicates whether the user has closed the view by clicking the close button.
|
||||||
*/
|
*/
|
||||||
@property (nonatomic, assign) BOOL closed;
|
@property (nonatomic, assign, getter=isClosed) BOOL closed;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@ -63,7 +63,7 @@ static const CGFloat FBSDKCloseButtonHeight = 12.0;
|
|||||||
|
|
||||||
- (void)commonInit {
|
- (void)commonInit {
|
||||||
// Initialization code
|
// Initialization code
|
||||||
_includeStatusBarInSize = FBSDKIncludeStatusBarInSizeIOS7AndLater;
|
_includeStatusBarInSize = FBSDKIncludeStatusBarInSizeAlways;
|
||||||
|
|
||||||
// iOS 7 system blue color
|
// iOS 7 system blue color
|
||||||
self.backgroundColor = [UIColor colorWithRed:0.0f green:122.0f / 255.0f blue:1.0f alpha:1.0f];
|
self.backgroundColor = [UIColor colorWithRed:0.0f green:122.0f / 255.0f blue:1.0f alpha:1.0f];
|
||||||
@ -151,11 +151,6 @@ static const CGFloat FBSDKCloseButtonHeight = 12.0;
|
|||||||
case FBSDKIncludeStatusBarInSizeAlways:
|
case FBSDKIncludeStatusBarInSizeAlways:
|
||||||
include = YES;
|
include = YES;
|
||||||
break;
|
break;
|
||||||
case FBSDKIncludeStatusBarInSizeIOS7AndLater: {
|
|
||||||
float systemVersion = [UIDevice currentDevice].systemVersion.floatValue;
|
|
||||||
include = (systemVersion >= 7.0);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case FBSDKIncludeStatusBarInSizeNever:
|
case FBSDKIncludeStatusBarInSizeNever:
|
||||||
include = NO;
|
include = NO;
|
||||||
break;
|
break;
|
||||||
@ -20,24 +20,29 @@
|
|||||||
|
|
||||||
NS_ASSUME_NONNULL_BEGIN
|
NS_ASSUME_NONNULL_BEGIN
|
||||||
|
|
||||||
/*!
|
/**
|
||||||
Represents a target defined in App Link metadata, consisting of at least
|
Represents a target defined in App Link metadata, consisting of at least
|
||||||
a URL, and optionally an App Store ID and name.
|
a URL, and optionally an App Store ID and name.
|
||||||
*/
|
*/
|
||||||
|
NS_SWIFT_NAME(AppLinkTarget)
|
||||||
@interface FBSDKAppLinkTarget : NSObject
|
@interface FBSDKAppLinkTarget : NSObject
|
||||||
|
|
||||||
/*! Creates a FBSDKAppLinkTarget with the given app site and target URL. */
|
- (instancetype)init NS_UNAVAILABLE;
|
||||||
+ (instancetype)appLinkTargetWithURL:(NSURL *)url
|
+ (instancetype)new NS_UNAVAILABLE;
|
||||||
|
|
||||||
|
/** Creates a FBSDKAppLinkTarget with the given app site and target URL. */
|
||||||
|
+ (instancetype)appLinkTargetWithURL:(nullable NSURL *)url
|
||||||
appStoreId:(nullable NSString *)appStoreId
|
appStoreId:(nullable NSString *)appStoreId
|
||||||
appName:(NSString *)appName;
|
appName:(NSString *)appName
|
||||||
|
NS_SWIFT_NAME(init(url:appStoreId:appName:));
|
||||||
|
|
||||||
/*! The URL prefix for this app link target */
|
/** The URL prefix for this app link target */
|
||||||
@property (nonatomic, strong, readonly) NSURL *URL;
|
@property (nonatomic, strong, readonly, nullable) NSURL *URL;
|
||||||
|
|
||||||
/*! The app ID for the app store */
|
/** The app ID for the app store */
|
||||||
@property (nonatomic, copy, readonly, nullable) NSString *appStoreId;
|
@property (nonatomic, copy, readonly, nullable) NSString *appStoreId;
|
||||||
|
|
||||||
/*! The name of the app */
|
/** The name of the app */
|
||||||
@property (nonatomic, copy, readonly) NSString *appName;
|
@property (nonatomic, copy, readonly) NSString *appName;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
@ -18,6 +18,8 @@
|
|||||||
|
|
||||||
#import <Foundation/Foundation.h>
|
#import <Foundation/Foundation.h>
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_BEGIN
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Describes the callback for fetchDeferredAppLink.
|
Describes the callback for fetchDeferredAppLink.
|
||||||
@param url the url representing the deferred App Link
|
@param url the url representing the deferred App Link
|
||||||
@ -27,21 +29,19 @@
|
|||||||
The url may also have a fb_click_time_utc query parameter that
|
The url may also have a fb_click_time_utc query parameter that
|
||||||
represents when the click occurred that caused the deferred App Link to be created.
|
represents when the click occurred that caused the deferred App Link to be created.
|
||||||
*/
|
*/
|
||||||
typedef void (^FBSDKDeferredAppLinkHandler)(NSURL *url, NSError *error);
|
typedef void (^FBSDKURLBlock)(NSURL *_Nullable url, NSError *_Nullable error)
|
||||||
|
NS_SWIFT_NAME(URLBlock);
|
||||||
|
|
||||||
/**
|
|
||||||
Describes the callback for fetchOrganicDeferredAppLink.
|
|
||||||
@param url the url representing the deferred App Link
|
|
||||||
*/
|
|
||||||
typedef void (^FBSDKDeferredAppInviteHandler)(NSURL *url);
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Class containing App Links related utility methods.
|
Class containing App Links related utility methods.
|
||||||
*/
|
*/
|
||||||
|
NS_SWIFT_NAME(AppLinkUtility)
|
||||||
@interface FBSDKAppLinkUtility : NSObject
|
@interface FBSDKAppLinkUtility : NSObject
|
||||||
|
|
||||||
|
- (instancetype)init NS_UNAVAILABLE;
|
||||||
|
+ (instancetype)new NS_UNAVAILABLE;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Call this method from the main thread to fetch deferred applink data if you use Mobile App
|
Call this method from the main thread to fetch deferred applink data if you use Mobile App
|
||||||
Engagement Ads (https://developers.facebook.com/docs/ads-for-apps/mobile-app-ads-engagement).
|
Engagement Ads (https://developers.facebook.com/docs/ads-for-apps/mobile-app-ads-engagement).
|
||||||
@ -59,21 +59,10 @@ typedef void (^FBSDKDeferredAppInviteHandler)(NSURL *url);
|
|||||||
been processed (e.g., you should call this method from your application delegate's
|
been processed (e.g., you should call this method from your application delegate's
|
||||||
applicationDidBecomeActive:).
|
applicationDidBecomeActive:).
|
||||||
*/
|
*/
|
||||||
+ (void)fetchDeferredAppLink:(FBSDKDeferredAppLinkHandler)handler;
|
+ (void)fetchDeferredAppLink:(nullable FBSDKURLBlock)handler;
|
||||||
|
|
||||||
/**
|
|
||||||
|
|
||||||
@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.");
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Call this method to fetch promotion code from the url, if it's present. This function
|
Call this method to fetch promotion code from the url, if it's present.
|
||||||
requires Bolts framework.
|
|
||||||
|
|
||||||
Note: This throws an exception if Bolts.framework is not linked. Add '[BFURL class]' in intialize method
|
|
||||||
of your AppDelegate.
|
|
||||||
|
|
||||||
@param url App Link url that was passed to the app.
|
@param url App Link url that was passed to the app.
|
||||||
|
|
||||||
@ -84,6 +73,8 @@ DEPRECATED_MSG_ATTRIBUTE("This method is no longer available.");
|
|||||||
This can be used to fetch the promotion code that was associated with the invite when it
|
This can be used to fetch the promotion code that was associated with the invite when it
|
||||||
was created. This method should be called with the url from the openURL method.
|
was created. This method should be called with the url from the openURL method.
|
||||||
*/
|
*/
|
||||||
+ (NSString*)appInvitePromotionCodeFromURL:(NSURL*)url;
|
+ (nullable NSString *)appInvitePromotionCodeFromURL:(NSURL *)url;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_END
|
||||||
@ -18,12 +18,11 @@
|
|||||||
|
|
||||||
#import "FBSDKAppLinkUtility.h"
|
#import "FBSDKAppLinkUtility.h"
|
||||||
|
|
||||||
#import <Bolts/BFURL.h>
|
|
||||||
|
|
||||||
#import "FBSDKAppEventsUtility.h"
|
#import "FBSDKAppEventsUtility.h"
|
||||||
#import "FBSDKGraphRequest.h"
|
#import "FBSDKGraphRequest.h"
|
||||||
#import "FBSDKInternalUtility.h"
|
#import "FBSDKInternalUtility.h"
|
||||||
#import "FBSDKSettings.h"
|
#import "FBSDKSettings.h"
|
||||||
|
#import "FBSDKURL.h"
|
||||||
#import "FBSDKUtility.h"
|
#import "FBSDKUtility.h"
|
||||||
|
|
||||||
static NSString *const FBSDKLastDeferredAppLink = @"com.facebook.sdk:lastDeferredAppLink%@";
|
static NSString *const FBSDKLastDeferredAppLink = @"com.facebook.sdk:lastDeferredAppLink%@";
|
||||||
@ -31,7 +30,7 @@ static NSString *const FBSDKDeferredAppLinkEvent = @"DEFERRED_APP_LINK";
|
|||||||
|
|
||||||
@implementation FBSDKAppLinkUtility {}
|
@implementation FBSDKAppLinkUtility {}
|
||||||
|
|
||||||
+ (void)fetchDeferredAppLink:(FBSDKDeferredAppLinkHandler)handler
|
+ (void)fetchDeferredAppLink:(FBSDKURLBlock)handler
|
||||||
{
|
{
|
||||||
NSAssert([NSThread isMainThread], @"FBSDKAppLink fetchDeferredAppLink: must be invoked from main thread.");
|
NSAssert([NSThread isMainThread], @"FBSDKAppLink fetchDeferredAppLink: must be invoked from main thread.");
|
||||||
|
|
||||||
@ -49,7 +48,7 @@ static NSString *const FBSDKDeferredAppLinkEvent = @"DEFERRED_APP_LINK";
|
|||||||
parameters:deferredAppLinkParameters
|
parameters:deferredAppLinkParameters
|
||||||
tokenString:nil
|
tokenString:nil
|
||||||
version:nil
|
version:nil
|
||||||
HTTPMethod:@"POST"];
|
HTTPMethod:FBSDKHTTPMethodPOST];
|
||||||
|
|
||||||
[deferredAppLinkRequest startWithCompletionHandler:^(FBSDKGraphRequestConnection *connection,
|
[deferredAppLinkRequest startWithCompletionHandler:^(FBSDKGraphRequestConnection *connection,
|
||||||
id result,
|
id result,
|
||||||
@ -80,14 +79,9 @@ static NSString *const FBSDKDeferredAppLinkEvent = @"DEFERRED_APP_LINK";
|
|||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (BOOL)fetchDeferredAppInvite:(FBSDKDeferredAppInviteHandler)handler
|
+ (NSString *)appInvitePromotionCodeFromURL:(NSURL *)url
|
||||||
{
|
{
|
||||||
return NO;
|
FBSDKURL *parsedUrl = [FBSDKURL URLWithURL:url];
|
||||||
}
|
|
||||||
|
|
||||||
+ (NSString*)appInvitePromotionCodeFromURL:(NSURL*)url;
|
|
||||||
{
|
|
||||||
BFURL *parsedUrl = [[FBSDKInternalUtility resolveBoltsClassWithName:@"BFURL"] URLWithURL:url];
|
|
||||||
NSDictionary *extras = parsedUrl.appLinkExtras;
|
NSDictionary *extras = parsedUrl.appLinkExtras;
|
||||||
if (extras) {
|
if (extras) {
|
||||||
NSString *deeplinkContextString = extras[@"deeplink_context"];
|
NSString *deeplinkContextString = extras[@"deeplink_context"];
|
||||||
@ -95,7 +89,7 @@ static NSString *const FBSDKDeferredAppLinkEvent = @"DEFERRED_APP_LINK";
|
|||||||
// Parse deeplinkContext and extract promo code
|
// Parse deeplinkContext and extract promo code
|
||||||
if (deeplinkContextString.length > 0) {
|
if (deeplinkContextString.length > 0) {
|
||||||
NSError *error = nil;
|
NSError *error = nil;
|
||||||
NSDictionary *deeplinkContextData = [FBSDKInternalUtility objectForJSONString:deeplinkContextString error:&error];
|
NSDictionary<id, id> *deeplinkContextData = [FBSDKBasicUtility objectForJSONString:deeplinkContextString error:&error];
|
||||||
if (!error && [deeplinkContextData isKindOfClass:[NSDictionary class]]) {
|
if (!error && [deeplinkContextData isKindOfClass:[NSDictionary class]]) {
|
||||||
return deeplinkContextData[@"promo_code"];
|
return deeplinkContextData[@"promo_code"];
|
||||||
}
|
}
|
||||||
@ -22,16 +22,18 @@
|
|||||||
|
|
||||||
NS_ASSUME_NONNULL_BEGIN
|
NS_ASSUME_NONNULL_BEGIN
|
||||||
|
|
||||||
/*!
|
/**
|
||||||
A reference implementation for an App Link resolver that uses a hidden UIWebView
|
A reference implementation for an App Link resolver that uses a hidden WKWebView
|
||||||
to parse the HTML containing App Link metadata.
|
to parse the HTML containing App Link metadata.
|
||||||
*/
|
*/
|
||||||
|
NS_SWIFT_NAME(WebViewAppLinkResolver)
|
||||||
@interface FBSDKWebViewAppLinkResolver : NSObject <FBSDKAppLinkResolving>
|
@interface FBSDKWebViewAppLinkResolver : NSObject <FBSDKAppLinkResolving>
|
||||||
|
|
||||||
/*!
|
/**
|
||||||
Gets the instance of a FBSDKWebViewAppLinkResolver.
|
Gets the instance of a FBSDKWebViewAppLinkResolver.
|
||||||
*/
|
*/
|
||||||
+ (instancetype)sharedInstance;
|
@property (class, nonatomic, readonly, strong) FBSDKWebViewAppLinkResolver *sharedInstance
|
||||||
|
NS_SWIFT_NAME(shared);
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@ -19,6 +19,7 @@
|
|||||||
#import "FBSDKWebViewAppLinkResolver.h"
|
#import "FBSDKWebViewAppLinkResolver.h"
|
||||||
|
|
||||||
#import <UIKit/UIKit.h>
|
#import <UIKit/UIKit.h>
|
||||||
|
#import <WebKit/WebKit.h>
|
||||||
|
|
||||||
#import "FBSDKAppLink.h"
|
#import "FBSDKAppLink.h"
|
||||||
#import "FBSDKAppLinkTarget.h"
|
#import "FBSDKAppLinkTarget.h"
|
||||||
@ -29,7 +30,8 @@
|
|||||||
@param error the error during the request, if any
|
@param error the error during the request, if any
|
||||||
|
|
||||||
*/
|
*/
|
||||||
typedef void (^FBSDKURLFollowRedirectsHandler)(NSDictionary<NSString *, id> *result, NSError * _Nullable error);
|
typedef void (^FBSDKURLFollowRedirectsBlock)(NSDictionary<NSString *, id> *result, NSError * _Nullable error)
|
||||||
|
NS_SWIFT_NAME(URLFollowRedirectsBlock);
|
||||||
|
|
||||||
// Defines JavaScript to extract app link tags from HTML content
|
// Defines JavaScript to extract app link tags from HTML content
|
||||||
static NSString *const FBSDKWebViewAppLinkResolverTagExtractionJavaScript = @""
|
static NSString *const FBSDKWebViewAppLinkResolverTagExtractionJavaScript = @""
|
||||||
@ -61,40 +63,39 @@ static NSString *const FBSDKWebViewAppLinkResolverIPadKey = @"ipad";
|
|||||||
static NSString *const FBSDKWebViewAppLinkResolverWebURLKey = @"url";
|
static NSString *const FBSDKWebViewAppLinkResolverWebURLKey = @"url";
|
||||||
static NSString *const FBSDKWebViewAppLinkResolverShouldFallbackKey = @"should_fallback";
|
static NSString *const FBSDKWebViewAppLinkResolverShouldFallbackKey = @"should_fallback";
|
||||||
|
|
||||||
@interface FBSDKWebViewAppLinkResolverWebViewDelegate : NSObject <UIWebViewDelegate>
|
@interface FBSDKWebViewAppLinkResolverWebViewDelegate : NSObject <WKNavigationDelegate>
|
||||||
|
|
||||||
@property (nonatomic, copy) void (^didFinishLoad)(UIWebView *webView);
|
@property (nonatomic, copy) void (^didFinishLoad)(WKWebView *webView);
|
||||||
@property (nonatomic, copy) void (^didFailLoadWithError)(UIWebView *webView, NSError *error);
|
@property (nonatomic, copy) void (^didFailLoadWithError)(WKWebView *webView, NSError *error);
|
||||||
@property (nonatomic, assign) BOOL hasLoaded;
|
@property (nonatomic, assign) BOOL hasLoaded;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@implementation FBSDKWebViewAppLinkResolverWebViewDelegate
|
@implementation FBSDKWebViewAppLinkResolverWebViewDelegate
|
||||||
|
|
||||||
- (void)webViewDidFinishLoad:(UIWebView *)webView {
|
- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation
|
||||||
if (self.didFinishLoad) {
|
{
|
||||||
self.didFinishLoad(webView);
|
if (self.didFinishLoad) {
|
||||||
}
|
self.didFinishLoad(webView);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)webViewDidStartLoad:(UIWebView *)webView {
|
- (void)webView:(WKWebView *)webView didFailNavigation:(WKNavigation *)navigation withError:(NSError *)error
|
||||||
|
{
|
||||||
|
if (self.didFailLoadWithError) {
|
||||||
|
self.didFailLoadWithError(webView, error);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error {
|
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler
|
||||||
if (self.didFailLoadWithError) {
|
{
|
||||||
self.didFailLoadWithError(webView, error);
|
if (self.hasLoaded) {
|
||||||
}
|
self.didFinishLoad(webView);
|
||||||
}
|
decisionHandler(WKNavigationActionPolicyCancel);
|
||||||
|
}
|
||||||
|
|
||||||
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
|
self.hasLoaded = YES;
|
||||||
if (self.hasLoaded) {
|
decisionHandler(WKNavigationActionPolicyAllow);
|
||||||
// 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
|
@end
|
||||||
@ -110,7 +111,7 @@ static NSString *const FBSDKWebViewAppLinkResolverShouldFallbackKey = @"should_f
|
|||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)followRedirects:(NSURL *)url handler:(FBSDKURLFollowRedirectsHandler)handler
|
- (void)followRedirects:(NSURL *)url handler:(FBSDKURLFollowRedirectsBlock)handler
|
||||||
{
|
{
|
||||||
// This task will be resolved with either the redirect NSURL
|
// This task will be resolved with either the redirect NSURL
|
||||||
// or a dictionary with the response data to be returned.
|
// or a dictionary with the response data to be returned.
|
||||||
@ -145,7 +146,7 @@ static NSString *const FBSDKWebViewAppLinkResolverShouldFallbackKey = @"should_f
|
|||||||
}] resume];
|
}] resume];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)appLinkFromURL:(NSURL *)url handler:(FBSDKAppLinkFromURLHandler)handler
|
- (void)appLinkFromURL:(NSURL *)url handler:(FBSDKAppLinkBlock)handler
|
||||||
{
|
{
|
||||||
dispatch_async(dispatch_get_main_queue(), ^{
|
dispatch_async(dispatch_get_main_queue(), ^{
|
||||||
[self followRedirects:url handler:^(NSDictionary<NSString *,id> *result, NSError * _Nullable error) {
|
[self followRedirects:url handler:^(NSDictionary<NSString *,id> *result, NSError * _Nullable error) {
|
||||||
@ -158,32 +159,41 @@ static NSString *const FBSDKWebViewAppLinkResolverShouldFallbackKey = @"should_f
|
|||||||
NSData *responseData = result[@"data"];
|
NSData *responseData = result[@"data"];
|
||||||
NSHTTPURLResponse *response = result[@"response"];
|
NSHTTPURLResponse *response = result[@"response"];
|
||||||
|
|
||||||
UIWebView *webView = [[UIWebView alloc] init];
|
WKWebView *webView = [[WKWebView alloc] init];
|
||||||
|
|
||||||
FBSDKWebViewAppLinkResolverWebViewDelegate *listener = [[FBSDKWebViewAppLinkResolverWebViewDelegate alloc] init];
|
FBSDKWebViewAppLinkResolverWebViewDelegate *listener = [[FBSDKWebViewAppLinkResolverWebViewDelegate alloc] init];
|
||||||
__block FBSDKWebViewAppLinkResolverWebViewDelegate *retainedListener = listener;
|
__block FBSDKWebViewAppLinkResolverWebViewDelegate *retainedListener = listener;
|
||||||
listener.didFinishLoad = ^(UIWebView *view) {
|
listener.didFinishLoad = ^(WKWebView *view) {
|
||||||
if (retainedListener) {
|
if (retainedListener) {
|
||||||
NSDictionary<NSString *, id> *ogData = [self getALDataFromLoadedPage:view];
|
[self getALDataFromLoadedPage:view handler:^(NSDictionary<NSString *,id> *ogData) {
|
||||||
[view removeFromSuperview];
|
[view removeFromSuperview];
|
||||||
view.delegate = nil;
|
view.navigationDelegate = nil;
|
||||||
retainedListener = nil;
|
retainedListener = nil;
|
||||||
handler([self appLinkFromALData:ogData destination:url], nil);
|
handler([self appLinkFromALData:ogData destination:url], nil);
|
||||||
|
}];
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
listener.didFailLoadWithError = ^(UIWebView* view, NSError *loadError) {
|
listener.didFailLoadWithError = ^(WKWebView *view, NSError *loadError) {
|
||||||
if (retainedListener) {
|
if (retainedListener) {
|
||||||
[view removeFromSuperview];
|
[view removeFromSuperview];
|
||||||
view.delegate = nil;
|
view.navigationDelegate = nil;
|
||||||
retainedListener = nil;
|
retainedListener = nil;
|
||||||
handler(nil, loadError);
|
handler(nil, loadError);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
webView.delegate = listener;
|
webView.navigationDelegate = listener;
|
||||||
webView.hidden = YES;
|
webView.hidden = YES;
|
||||||
[webView loadData:responseData
|
if (@available(iOS 9.0, *)) {
|
||||||
MIMEType:response.MIMEType
|
[webView loadData:responseData
|
||||||
textEncodingName:response.textEncodingName
|
MIMEType:response.MIMEType
|
||||||
baseURL:response.URL];
|
characterEncodingName:response.textEncodingName
|
||||||
|
baseURL:response.URL];
|
||||||
|
} else {
|
||||||
|
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
|
||||||
|
[request setValue:FBSDKWebViewAppLinkResolverMetaTagPrefix forHTTPHeaderField:FBSDKWebViewAppLinkResolverPreferHeader];
|
||||||
|
[webView loadRequest:request];
|
||||||
|
}
|
||||||
|
|
||||||
UIWindow *window = [UIApplication sharedApplication].windows.firstObject;
|
UIWindow *window = [UIApplication sharedApplication].windows.firstObject;
|
||||||
[window addSubview:webView];
|
[window addSubview:webView];
|
||||||
}];
|
}];
|
||||||
@ -227,15 +237,20 @@ static NSString *const FBSDKWebViewAppLinkResolverShouldFallbackKey = @"should_f
|
|||||||
return al;
|
return al;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSDictionary<NSString *, id> *)getALDataFromLoadedPage:(UIWebView *)webView {
|
- (void)getALDataFromLoadedPage:(WKWebView *)webView
|
||||||
// Run some JavaScript in the webview to fetch the meta tags.
|
handler:(void (^)(NSDictionary<NSString *, id> *))handler
|
||||||
NSString *jsonString = [webView stringByEvaluatingJavaScriptFromString:FBSDKWebViewAppLinkResolverTagExtractionJavaScript];
|
{
|
||||||
NSError *error = nil;
|
// Run some JavaScript in the webview to fetch the meta tags.
|
||||||
NSArray<NSDictionary<NSString *, id> *> *arr =
|
[webView evaluateJavaScript:FBSDKWebViewAppLinkResolverTagExtractionJavaScript
|
||||||
[NSJSONSerialization JSONObjectWithData:[jsonString dataUsingEncoding:NSUTF8StringEncoding]
|
completionHandler:^(id _Nullable evaluateResult, NSError * _Nullable error) {
|
||||||
options:0
|
NSString *jsonString = [evaluateResult isKindOfClass:[NSString class]] ? evaluateResult : nil;
|
||||||
error:&error];
|
error = nil;
|
||||||
return [self parseALData:arr];
|
NSArray<NSDictionary<NSString *, id> *> *arr =
|
||||||
|
[NSJSONSerialization JSONObjectWithData:[jsonString dataUsingEncoding:NSUTF8StringEncoding]
|
||||||
|
options:0
|
||||||
|
error:&error];
|
||||||
|
handler([self parseALData:arr]);
|
||||||
|
}];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -18,12 +18,14 @@
|
|||||||
|
|
||||||
#import <Foundation/Foundation.h>
|
#import <Foundation/Foundation.h>
|
||||||
|
|
||||||
#import "FBSDKAccessTokenCaching.h"
|
NS_ASSUME_NONNULL_BEGIN
|
||||||
|
|
||||||
FOUNDATION_EXPORT NSString *const FBSDKTokenInformationUUIDKey;
|
NS_SWIFT_NAME(MeasurementEventListener)
|
||||||
|
@interface FBSDKMeasurementEventListener : NSObject
|
||||||
|
|
||||||
@interface FBSDKAccessTokenCacheV3 : NSObject<FBSDKAccessTokenCaching>
|
@property (class, nonatomic, strong, readonly) FBSDKMeasurementEventListener *defaultListener
|
||||||
|
NS_SWIFT_NAME(default);
|
||||||
+ (FBSDKAccessToken *)accessTokenForV3Dictionary:(NSDictionary *)dictionary;
|
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_END
|
||||||
@ -16,37 +16,37 @@
|
|||||||
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
// 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 "FBSDKBoltsMeasurementEventListener.h"
|
#import "FBSDKMeasurementEventListener.h"
|
||||||
|
|
||||||
#import "FBSDKAppEvents+Internal.h"
|
#import "FBSDKAppEvents+Internal.h"
|
||||||
#import "FBSDKTimeSpentData.h"
|
#import "FBSDKTimeSpentData.h"
|
||||||
|
|
||||||
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0
|
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0
|
||||||
|
|
||||||
static NSNotificationName const BoltsMeasurementEventNotification = @"com.parse.bolts.measurement_event";
|
static NSNotificationName const FBSDKMeasurementEventNotification = @"com.facebook.facebook-objc-sdk.measurement_event";
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
static NSString *const BoltsMeasurementEventNotification = @"com.parse.bolts.measurement_event";
|
static NSString *const FBSDKMeasurementEventNotification = @"com.facebook.facebook-objc-sdk.measurement_event";
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static NSString *const BoltsMeasurementEventName = @"event_name";
|
static NSString *const FBSDKMeasurementEventName = @"event_name";
|
||||||
static NSString *const BoltsMeasurementEventArgs = @"event_args";
|
static NSString *const FBSDKMeasurementEventArgs = @"event_args";
|
||||||
static NSString *const BoltsMeasurementEventPrefix = @"bf_";
|
static NSString *const FBSDKMeasurementEventPrefix = @"bf_";
|
||||||
|
|
||||||
@implementation FBSDKBoltsMeasurementEventListener
|
@implementation FBSDKMeasurementEventListener
|
||||||
|
|
||||||
+ (instancetype)defaultListener
|
+ (instancetype)defaultListener
|
||||||
{
|
{
|
||||||
static dispatch_once_t dispatchOnceLocker = 0;
|
static dispatch_once_t dispatchOnceLocker = 0;
|
||||||
static FBSDKBoltsMeasurementEventListener *defaultListener = nil;
|
static FBSDKMeasurementEventListener *defaultListener = nil;
|
||||||
dispatch_once(&dispatchOnceLocker, ^{
|
dispatch_once(&dispatchOnceLocker, ^{
|
||||||
defaultListener = [[self alloc] init];
|
defaultListener = [[self alloc] init];
|
||||||
NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
|
NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
|
||||||
[center addObserver:defaultListener
|
[center addObserver:defaultListener
|
||||||
selector:@selector(logFBAppEventForNotification:)
|
selector:@selector(logFBAppEventForNotification:)
|
||||||
name:BoltsMeasurementEventNotification
|
name:FBSDKMeasurementEventNotification
|
||||||
object:nil];
|
object:nil];
|
||||||
});
|
});
|
||||||
return defaultListener;
|
return defaultListener;
|
||||||
@ -55,15 +55,15 @@ static NSString *const BoltsMeasurementEventPrefix = @"bf_";
|
|||||||
- (void)logFBAppEventForNotification:(NSNotification *)note
|
- (void)logFBAppEventForNotification:(NSNotification *)note
|
||||||
{
|
{
|
||||||
// when catch al_nav_in event, we set source application for FBAppEvents.
|
// when catch al_nav_in event, we set source application for FBAppEvents.
|
||||||
if ([note.userInfo[BoltsMeasurementEventName] isEqualToString:@"al_nav_in"]) {
|
if ([note.userInfo[FBSDKMeasurementEventName] isEqualToString:@"al_nav_in"]) {
|
||||||
NSString *sourceApplication = note.userInfo[BoltsMeasurementEventArgs][@"sourceApplication"];
|
NSString *sourceApplication = note.userInfo[FBSDKMeasurementEventArgs][@"sourceApplication"];
|
||||||
if (sourceApplication) {
|
if (sourceApplication) {
|
||||||
[FBSDKTimeSpentData setSourceApplication:sourceApplication isFromAppLink:YES];
|
[FBSDKTimeSpentData setSourceApplication:sourceApplication isFromAppLink:YES];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
NSDictionary *eventArgs = note.userInfo[BoltsMeasurementEventArgs];
|
NSDictionary<NSString *, id> *eventArgs = note.userInfo[FBSDKMeasurementEventArgs];
|
||||||
NSMutableDictionary *logData = [[NSMutableDictionary alloc] init];
|
NSMutableDictionary<NSString *, id> *logData = [[NSMutableDictionary alloc] init];
|
||||||
for(NSString *key in eventArgs.allKeys) {
|
for (NSString *key in eventArgs.allKeys) {
|
||||||
NSError *error = nil;
|
NSError *error = nil;
|
||||||
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"[^0-9a-zA-Z _-]" options:0 error:&error];
|
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"[^0-9a-zA-Z _-]" options:0 error:&error];
|
||||||
NSString *safeKey = [regex stringByReplacingMatchesInString:key
|
NSString *safeKey = [regex stringByReplacingMatchesInString:key
|
||||||
@ -73,10 +73,9 @@ static NSString *const BoltsMeasurementEventPrefix = @"bf_";
|
|||||||
safeKey = [safeKey stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@" -"]];
|
safeKey = [safeKey stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@" -"]];
|
||||||
logData[safeKey] = eventArgs[key];
|
logData[safeKey] = eventArgs[key];
|
||||||
}
|
}
|
||||||
[FBSDKAppEvents logImplicitEvent:[BoltsMeasurementEventPrefix stringByAppendingString:note.userInfo[BoltsMeasurementEventName]]
|
[FBSDKAppEvents logInternalEvent:[FBSDKMeasurementEventPrefix stringByAppendingString:note.userInfo[FBSDKMeasurementEventName]]
|
||||||
valueToSum:nil
|
|
||||||
parameters:logData
|
parameters:logData
|
||||||
accessToken:nil];
|
isImplicitlyLogged:YES];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)dealloc
|
- (void)dealloc
|
||||||
@ -18,9 +18,17 @@
|
|||||||
|
|
||||||
#import <Foundation/Foundation.h>
|
#import <Foundation/Foundation.h>
|
||||||
|
|
||||||
#import "FBSDKAccessToken.h"
|
#import "FBSDKCrashObserving.h"
|
||||||
#import "FBSDKAccessTokenCaching.h"
|
|
||||||
|
|
||||||
@interface FBSDKAccessTokenCacheV4 : NSObject<FBSDKAccessTokenCaching>
|
NS_ASSUME_NONNULL_BEGIN
|
||||||
|
|
||||||
|
@interface FBSDKCrashHandler : NSObject
|
||||||
|
|
||||||
|
+ (void)disable;
|
||||||
|
+ (void)addObserver:(id<FBSDKCrashObserving>)observer;
|
||||||
|
+ (void)removeObserver:(id<FBSDKCrashObserving>)observer;
|
||||||
|
+ (void)clearCrashReportFiles;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_END
|
||||||
322
Example/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Basics/Instrument/FBSDKCrashHandler.m
generated
Normal file
322
Example/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Basics/Instrument/FBSDKCrashHandler.m
generated
Normal file
@ -0,0 +1,322 @@
|
|||||||
|
// 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 "FBSDKCrashHandler.h"
|
||||||
|
|
||||||
|
#import <sys/utsname.h>
|
||||||
|
|
||||||
|
#import <UIKit/UIKit.h>
|
||||||
|
|
||||||
|
#import "FBSDKLibAnalyzer.h"
|
||||||
|
|
||||||
|
#define FBSDK_MAX_CRASH_LOGS 5
|
||||||
|
#define FBSDK_CRASH_PATH_NAME @"instrument"
|
||||||
|
|
||||||
|
static NSUncaughtExceptionHandler *previousExceptionHandler = NULL;
|
||||||
|
static NSString *mappingTableIdentifier = NULL;
|
||||||
|
static NSString *directoryPath;
|
||||||
|
|
||||||
|
NSString *const kFBSDKAppVersion = @"app_version";
|
||||||
|
NSString *const kFBSDKCallstack = @"callstack";
|
||||||
|
NSString *const kFBSDKCrashReason = @"reason";
|
||||||
|
NSString *const kFBSDKCrashTimestamp = @"timestamp";
|
||||||
|
NSString *const kFBSDKDeviceModel = @"device_model";
|
||||||
|
NSString *const kFBSDKDeviceOSVersion = @"device_os_version";
|
||||||
|
|
||||||
|
NSString *const kFBSDKMapingTable = @"mapping_table";
|
||||||
|
NSString *const kFBSDKMappingTableIdentifier = @"mapping_table_identifier";
|
||||||
|
|
||||||
|
@implementation FBSDKCrashHandler
|
||||||
|
|
||||||
|
static NSHashTable<id<FBSDKCrashObserving>> *_observers;
|
||||||
|
static NSArray<NSDictionary<NSString *, id> *> *_processedCrashLogs;
|
||||||
|
static BOOL _isTurnedOff;
|
||||||
|
|
||||||
|
# pragma mark - Class Methods
|
||||||
|
|
||||||
|
+ (void)initialize
|
||||||
|
{
|
||||||
|
NSString *dirPath = [NSTemporaryDirectory() stringByAppendingPathComponent:FBSDK_CRASH_PATH_NAME];
|
||||||
|
if (![[NSFileManager defaultManager] fileExistsAtPath:dirPath]) {
|
||||||
|
[[NSFileManager defaultManager] createDirectoryAtPath:dirPath withIntermediateDirectories:NO attributes:NULL error:NULL];
|
||||||
|
}
|
||||||
|
directoryPath = dirPath;
|
||||||
|
NSString *identifier = [[NSUUID UUID] UUIDString];
|
||||||
|
mappingTableIdentifier = [identifier stringByReplacingOccurrencesOfString:@"-" withString:@""];
|
||||||
|
_observers = [[NSHashTable alloc] init];
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (void)sendCrashLogs
|
||||||
|
{
|
||||||
|
NSArray<id<FBSDKCrashObserving>> *observers = [_observers copy];
|
||||||
|
for (id<FBSDKCrashObserving> observer in observers) {
|
||||||
|
if (observer && [observer respondsToSelector:@selector(didReceiveCrashLogs:)]) {
|
||||||
|
NSArray<NSDictionary<NSString *, id> *> *filteredCrashLogs = [self filterCrashLogs:observer.prefixes];
|
||||||
|
[observer didReceiveCrashLogs:filteredCrashLogs];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (NSArray<NSDictionary<NSString *, id> *> *)filterCrashLogs:(NSArray<NSString *> *)prefixList
|
||||||
|
{
|
||||||
|
NSMutableArray<NSDictionary<NSString *, id> *> *crashLogs = [NSMutableArray array];
|
||||||
|
for (NSDictionary<NSString *, id> *crashLog in _processedCrashLogs) {
|
||||||
|
NSArray<NSString *> *callstack = crashLog[kFBSDKCallstack];
|
||||||
|
if ([self callstack:callstack containsPrefix:prefixList]) {
|
||||||
|
[crashLogs addObject:crashLog];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return crashLogs;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (BOOL)callstack:(NSArray<NSString *> *)callstack
|
||||||
|
containsPrefix:(NSArray<NSString *> *)prefixList
|
||||||
|
{
|
||||||
|
NSString *callStackString = [callstack componentsJoinedByString:@""];
|
||||||
|
for (NSString *prefix in prefixList) {
|
||||||
|
if ([callStackString containsString:prefix]) {
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (void)disable
|
||||||
|
{
|
||||||
|
_isTurnedOff = YES;
|
||||||
|
[FBSDKCrashHandler uninstallExceptionsHandler];
|
||||||
|
_observers = nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (void)addObserver:(id<FBSDKCrashObserving>)observer
|
||||||
|
{
|
||||||
|
if (_isTurnedOff || ![self isSafeToGenerateMapping]) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
static dispatch_once_t onceToken = 0;
|
||||||
|
dispatch_once(&onceToken, ^{
|
||||||
|
[FBSDKCrashHandler installExceptionsHandler];
|
||||||
|
_processedCrashLogs = [self getProcessedCrashLogs];
|
||||||
|
});
|
||||||
|
if (![_observers containsObject:observer]) {
|
||||||
|
[_observers addObject:observer];
|
||||||
|
[self generateMethodMapping:observer];
|
||||||
|
[self sendCrashLogs];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (void)removeObserver:(id<FBSDKCrashObserving>)observer
|
||||||
|
{
|
||||||
|
if ([_observers containsObject:observer]) {
|
||||||
|
[_observers removeObject:observer];
|
||||||
|
if (_observers.count == 0) {
|
||||||
|
[FBSDKCrashHandler uninstallExceptionsHandler];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# pragma mark handler function
|
||||||
|
|
||||||
|
+ (void)installExceptionsHandler
|
||||||
|
{
|
||||||
|
NSUncaughtExceptionHandler *currentHandler = NSGetUncaughtExceptionHandler();
|
||||||
|
|
||||||
|
if (currentHandler != FBSDKExceptionHandler) {
|
||||||
|
previousExceptionHandler = currentHandler;
|
||||||
|
NSSetUncaughtExceptionHandler(&FBSDKExceptionHandler);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (void)uninstallExceptionsHandler
|
||||||
|
{
|
||||||
|
NSSetUncaughtExceptionHandler(previousExceptionHandler);
|
||||||
|
previousExceptionHandler = nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void FBSDKExceptionHandler(NSException *exception)
|
||||||
|
{
|
||||||
|
[FBSDKCrashHandler saveException:exception];
|
||||||
|
if (previousExceptionHandler) {
|
||||||
|
previousExceptionHandler(exception);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - Storage
|
||||||
|
|
||||||
|
+ (void)saveException:(NSException *)exception
|
||||||
|
{
|
||||||
|
if (exception.callStackSymbols && exception.name) {
|
||||||
|
NSArray<NSString *> *stackSymbols = [NSArray arrayWithArray:exception.callStackSymbols];
|
||||||
|
[self saveCrashLog:@{
|
||||||
|
kFBSDKCallstack : stackSymbols,
|
||||||
|
kFBSDKCrashReason : exception.name,
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (void)saveSignal:(int)signal withCallStack:(NSArray<NSString *> *)callStack
|
||||||
|
{
|
||||||
|
if (callStack) {
|
||||||
|
NSString *signalDescription = [NSString stringWithCString:strsignal(signal) encoding:NSUTF8StringEncoding] ?: [NSString stringWithFormat:@"SIGNUM(%i)", signal];
|
||||||
|
[self saveCrashLog:@{
|
||||||
|
kFBSDKCallstack : callStack,
|
||||||
|
kFBSDKCrashReason : signalDescription,
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (NSArray<NSDictionary<NSString *, id> *> *)getProcessedCrashLogs
|
||||||
|
{
|
||||||
|
NSArray<NSDictionary<NSString *, id> *> *crashLogs = [self loadCrashLogs];
|
||||||
|
if (0 == crashLogs.count) {
|
||||||
|
[self clearCrashReportFiles];
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
NSMutableArray<NSDictionary<NSString *, id> *> *processedCrashLogs = [NSMutableArray array];
|
||||||
|
|
||||||
|
for (NSDictionary<NSString *, id> *crashLog in crashLogs) {
|
||||||
|
NSArray<NSString *> *callstack = crashLog[kFBSDKCallstack];
|
||||||
|
NSDictionary<NSString *, id> *methodMapping = [self loadLibData:crashLog];
|
||||||
|
NSArray<NSString *> *symbolicatedCallstack = [FBSDKLibAnalyzer symbolicateCallstack:callstack methodMapping:methodMapping];
|
||||||
|
NSMutableDictionary<NSString *, id> *symbolicatedCrashLog = [NSMutableDictionary dictionaryWithDictionary:crashLog];
|
||||||
|
if (symbolicatedCallstack) {
|
||||||
|
[symbolicatedCrashLog setObject:symbolicatedCallstack forKey:kFBSDKCallstack];
|
||||||
|
[symbolicatedCrashLog removeObjectForKey:kFBSDKMappingTableIdentifier];
|
||||||
|
[processedCrashLogs addObject:symbolicatedCrashLog];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return processedCrashLogs;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (NSArray<NSDictionary<NSString *, id> *> *)loadCrashLogs
|
||||||
|
{
|
||||||
|
NSArray<NSString *> *files = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:directoryPath error:NULL];
|
||||||
|
NSArray<NSString *> *fileNames = [[self getCrashLogFileNames:files] sortedArrayUsingComparator:^NSComparisonResult(id _Nonnull obj1, id _Nonnull obj2){
|
||||||
|
return [obj2 compare:obj1];
|
||||||
|
}];
|
||||||
|
NSMutableArray<NSDictionary<NSString *, id> *> *crashLogArray = [NSMutableArray array];
|
||||||
|
|
||||||
|
for (NSUInteger i = 0; i < MIN(fileNames.count, FBSDK_MAX_CRASH_LOGS); i++) {
|
||||||
|
NSDictionary<NSString *, id> *crashLog = [self loadCrashLog:fileNames[i]];
|
||||||
|
[crashLogArray addObject:crashLog];
|
||||||
|
}
|
||||||
|
return [crashLogArray copy];
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (NSDictionary<NSString *,id> *)loadCrashLog:(NSString *)fileName
|
||||||
|
{
|
||||||
|
return [NSDictionary dictionaryWithContentsOfFile:[directoryPath stringByAppendingPathComponent:fileName]];
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (void)clearCrashReportFiles
|
||||||
|
{
|
||||||
|
NSArray<NSString *> *files = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:directoryPath error:nil];
|
||||||
|
|
||||||
|
for (NSUInteger i = 0; i < files.count; i++) {
|
||||||
|
// remove all crash related files except for the current mapping table
|
||||||
|
if ([files[i] hasPrefix:@"crash_"] && ![files[i] containsString:mappingTableIdentifier]) {
|
||||||
|
[[NSFileManager defaultManager] removeItemAtPath:[directoryPath stringByAppendingPathComponent:files[i]] error:nil];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (NSArray<NSString *> *)getCrashLogFileNames:(NSArray<NSString *> *)files
|
||||||
|
{
|
||||||
|
NSMutableArray<NSString *> *fileNames = [NSMutableArray array];
|
||||||
|
|
||||||
|
for (NSString *fileName in files) {
|
||||||
|
if ([fileName hasPrefix:@"crash_log_"] && [fileName hasSuffix:@".json"]) {
|
||||||
|
[fileNames addObject:fileName];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return fileNames;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (void)saveCrashLog:(NSDictionary<NSString *, id> *)crashLog
|
||||||
|
{
|
||||||
|
NSMutableDictionary<NSString *, id> *completeCrashLog = [NSMutableDictionary dictionaryWithDictionary:crashLog];
|
||||||
|
NSString *currentTimestamp = [NSString stringWithFormat:@"%.0lf", [[NSDate date] timeIntervalSince1970]];
|
||||||
|
|
||||||
|
[completeCrashLog setObject:currentTimestamp forKey:kFBSDKCrashTimestamp];
|
||||||
|
[completeCrashLog setObject:mappingTableIdentifier forKey:kFBSDKMappingTableIdentifier];
|
||||||
|
|
||||||
|
NSBundle *mainBundle = [NSBundle mainBundle];
|
||||||
|
NSString *version = [mainBundle objectForInfoDictionaryKey:@"CFBundleShortVersionString"];
|
||||||
|
NSString *build = [mainBundle objectForInfoDictionaryKey:@"CFBundleVersion"];
|
||||||
|
[completeCrashLog setObject:[NSString stringWithFormat:@"%@(%@)", version, build] forKey:kFBSDKAppVersion];
|
||||||
|
|
||||||
|
struct utsname systemInfo;
|
||||||
|
uname(&systemInfo);
|
||||||
|
[completeCrashLog setObject:@(systemInfo.machine) forKey:kFBSDKDeviceModel];
|
||||||
|
|
||||||
|
[completeCrashLog setObject:[UIDevice currentDevice].systemVersion forKey:kFBSDKDeviceOSVersion];
|
||||||
|
|
||||||
|
[completeCrashLog writeToFile:[self getPathToCrashFile:currentTimestamp]
|
||||||
|
atomically:YES];
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (void)generateMethodMapping:(id<FBSDKCrashObserving>)observer
|
||||||
|
{
|
||||||
|
if (observer.prefixes.count == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
[[NSUserDefaults standardUserDefaults] setObject:mappingTableIdentifier forKey:kFBSDKMappingTableIdentifier];
|
||||||
|
NSDictionary<NSString *, NSString *> *methodMapping = [FBSDKLibAnalyzer getMethodsTable:observer.prefixes
|
||||||
|
frameworks:observer.frameworks];
|
||||||
|
if (methodMapping.count > 0){
|
||||||
|
[methodMapping writeToFile:[self getPathToLibDataFile:mappingTableIdentifier]
|
||||||
|
atomically:YES];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (NSDictionary<NSString *, id> *)loadLibData:(NSDictionary<NSString *, id> *)crashLog
|
||||||
|
{
|
||||||
|
NSString *identifier = [crashLog objectForKey:kFBSDKMappingTableIdentifier];
|
||||||
|
return [NSDictionary dictionaryWithContentsOfFile:[self getPathToLibDataFile:identifier]];
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (NSString *)getPathToCrashFile:(NSString *)timestamp
|
||||||
|
{
|
||||||
|
return [directoryPath stringByAppendingPathComponent:
|
||||||
|
[NSString stringWithFormat:@"crash_log_%@.json", timestamp]];
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (NSString *)getPathToLibDataFile:(NSString *)identifier
|
||||||
|
{
|
||||||
|
return [directoryPath stringByAppendingPathComponent:
|
||||||
|
[NSString stringWithFormat:@"crash_lib_data_%@.json", identifier]];
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (BOOL)isSafeToGenerateMapping
|
||||||
|
{
|
||||||
|
#if TARGET_OS_SIMULATOR
|
||||||
|
return YES;
|
||||||
|
#else
|
||||||
|
NSString *identifier = [[NSUserDefaults standardUserDefaults] objectForKey:kFBSDKMappingTableIdentifier];
|
||||||
|
//first app start
|
||||||
|
if (!identifier) {
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
return [[NSFileManager defaultManager] fileExistsAtPath:[self getPathToLibDataFile:identifier]];
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
34
Example/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Basics/Instrument/FBSDKCrashObserving.h
generated
Normal file
34
Example/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Basics/Instrument/FBSDKCrashObserving.h
generated
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
// Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
|
||||||
|
//
|
||||||
|
// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,
|
||||||
|
// copy, modify, and distribute this software in source code or binary form for use
|
||||||
|
// in connection with the web services and APIs provided by Facebook.
|
||||||
|
//
|
||||||
|
// As with any software that integrates with the Facebook platform, your use of
|
||||||
|
// this software is subject to the Facebook Developer Principles and Policies
|
||||||
|
// [http://developers.facebook.com/policy/]. This copyright notice shall be
|
||||||
|
// included in all copies or substantial portions of the software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||||
|
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||||
|
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||||
|
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||||
|
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_BEGIN
|
||||||
|
|
||||||
|
@protocol FBSDKCrashObserving <NSObject>
|
||||||
|
|
||||||
|
@property (nonatomic, copy) NSArray<NSString *> *prefixes;
|
||||||
|
@property (nonatomic, copy, nullable) NSArray<NSString *> *frameworks;
|
||||||
|
|
||||||
|
@optional
|
||||||
|
|
||||||
|
- (void)didReceiveCrashLogs:(NSArray<NSDictionary<NSString *, id> *> *)crashLogs;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_END
|
||||||
32
Example/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Basics/Instrument/FBSDKLibAnalyzer.h
generated
Normal file
32
Example/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Basics/Instrument/FBSDKLibAnalyzer.h
generated
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
// Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
|
||||||
|
//
|
||||||
|
// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,
|
||||||
|
// copy, modify, and distribute this software in source code or binary form for use
|
||||||
|
// in connection with the web services and APIs provided by Facebook.
|
||||||
|
//
|
||||||
|
// As with any software that integrates with the Facebook platform, your use of
|
||||||
|
// this software is subject to the Facebook Developer Principles and Policies
|
||||||
|
// [http://developers.facebook.com/policy/]. This copyright notice shall be
|
||||||
|
// included in all copies or substantial portions of the software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||||
|
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||||
|
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||||
|
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||||
|
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_BEGIN
|
||||||
|
|
||||||
|
@interface FBSDKLibAnalyzer : NSObject
|
||||||
|
|
||||||
|
+ (NSDictionary<NSString *, NSString *> *)getMethodsTable:(NSArray<NSString *> *)prefixes
|
||||||
|
frameworks:(NSArray<NSString *> * _Nullable)frameworks;
|
||||||
|
+ (nullable NSArray<NSString *> *)symbolicateCallstack:(NSArray<NSString *> *)callstack
|
||||||
|
methodMapping:(NSDictionary<NSString *,id> *)methodMapping;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_END
|
||||||
218
Example/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Basics/Instrument/FBSDKLibAnalyzer.m
generated
Normal file
218
Example/Pods/FBSDKCoreKit/FBSDKCoreKit/FBSDKCoreKit/Basics/Instrument/FBSDKLibAnalyzer.m
generated
Normal file
@ -0,0 +1,218 @@
|
|||||||
|
// 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 "FBSDKLibAnalyzer.h"
|
||||||
|
|
||||||
|
#import <objc/runtime.h>
|
||||||
|
|
||||||
|
@implementation FBSDKLibAnalyzer
|
||||||
|
|
||||||
|
static NSMutableDictionary<NSString *, NSString *> *_methodMapping;
|
||||||
|
|
||||||
|
+ (void)initialize
|
||||||
|
{
|
||||||
|
_methodMapping = [NSMutableDictionary dictionary];
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (NSDictionary<NSString *, NSString *> *)getMethodsTable:(NSArray<NSString *> *)prefixes
|
||||||
|
frameworks:(NSArray<NSString *> *)frameworks
|
||||||
|
{
|
||||||
|
NSArray<NSString *> *allClasses = [self getClassNames:prefixes frameworks:frameworks];
|
||||||
|
for (NSString *className in allClasses) {
|
||||||
|
Class class = NSClassFromString(className);
|
||||||
|
if (class) {
|
||||||
|
[self addClass:class isClassMethod:NO];
|
||||||
|
[self addClass:object_getClass(class) isClassMethod:YES];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return [_methodMapping copy];
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - private methods
|
||||||
|
|
||||||
|
+ (NSArray<NSString *> *)getClassNames:(NSArray<NSString *> *)prefixes
|
||||||
|
frameworks:(NSArray<NSString *> *)frameworks
|
||||||
|
{
|
||||||
|
NSMutableArray<NSString *> *classNames = [NSMutableArray new];
|
||||||
|
// from main bundle
|
||||||
|
[classNames addObjectsFromArray:[self getClassesFrom:[[NSBundle mainBundle] executablePath]
|
||||||
|
prefixes:prefixes]];
|
||||||
|
// from dynamic libraries
|
||||||
|
if (frameworks.count > 0) {
|
||||||
|
unsigned int count = 0;
|
||||||
|
const char **images = objc_copyImageNames(&count);
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
NSString *image = [NSString stringWithUTF8String:images[i]];
|
||||||
|
for (NSString *framework in frameworks) {
|
||||||
|
if ([image containsString:framework]) {
|
||||||
|
[classNames addObjectsFromArray:[self getClassesFrom:image
|
||||||
|
prefixes:nil]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free(images);
|
||||||
|
}
|
||||||
|
|
||||||
|
return [classNames copy];
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (NSArray<NSString *> *)getClassesFrom:(NSString *)image
|
||||||
|
prefixes:(NSArray<NSString *> *)prefixes
|
||||||
|
{
|
||||||
|
NSMutableArray<NSString *> *classNames = [NSMutableArray array];
|
||||||
|
unsigned int count = 0;
|
||||||
|
const char **classes = objc_copyClassNamesForImage([image UTF8String], &count);
|
||||||
|
for (unsigned int i = 0; i < count; i++){
|
||||||
|
NSString *className = [NSString stringWithUTF8String:classes[i]];
|
||||||
|
if (prefixes.count > 0) {
|
||||||
|
for (NSString *prefix in prefixes) {
|
||||||
|
if ([className hasPrefix:prefix]) {
|
||||||
|
[classNames addObject:className];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
[classNames addObject:className];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free(classes);
|
||||||
|
return [classNames copy];
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (void)addClass:(Class)class
|
||||||
|
isClassMethod:(BOOL)isClassMethod
|
||||||
|
{
|
||||||
|
unsigned int methodsCount = 0;
|
||||||
|
Method *methods = class_copyMethodList(class, &methodsCount);
|
||||||
|
|
||||||
|
NSString *methodType = isClassMethod ? @"+" : @"-";
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < methodsCount; i++) {
|
||||||
|
Method method = methods[i];
|
||||||
|
|
||||||
|
if (method) {
|
||||||
|
SEL selector = method_getName(method);
|
||||||
|
|
||||||
|
IMP methodImplementation = class_getMethodImplementation(class, selector);
|
||||||
|
NSString *methodAddress = [NSString stringWithFormat:@"0x%010lx", (unsigned long)methodImplementation];
|
||||||
|
NSString *methodName = [NSString stringWithFormat:@"%@[%@ %@]",
|
||||||
|
methodType,
|
||||||
|
NSStringFromClass(class),
|
||||||
|
NSStringFromSelector(selector)];
|
||||||
|
|
||||||
|
if (methodAddress && methodName) {
|
||||||
|
[_methodMapping setObject:methodName forKey:methodAddress];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free(methods);
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (NSArray<NSString *> *)symbolicateCallstack:(NSArray<NSString *> *)callstack
|
||||||
|
methodMapping:(NSDictionary<NSString *,id> *)methodMapping
|
||||||
|
{
|
||||||
|
if (!callstack || !methodMapping) {
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
NSArray<NSString *> *sortedAllAddress = [methodMapping.allKeys sortedArrayUsingComparator:^NSComparisonResult(id _Nonnull obj1, id _Nonnull obj2) {
|
||||||
|
return [obj1 compare:obj2];
|
||||||
|
}];
|
||||||
|
|
||||||
|
BOOL containsFBSDKFunction = NO;
|
||||||
|
NSInteger nonSDKMethodCount = 0;
|
||||||
|
NSMutableArray<NSString *> *symbolicatedCallstack = [NSMutableArray array];
|
||||||
|
|
||||||
|
for (NSUInteger i = 0; i < callstack.count; i++){
|
||||||
|
NSString *rawAddress = [self getAddress:callstack[i]];
|
||||||
|
NSString *addressString = [NSString stringWithFormat:@"0x%@",[rawAddress substringWithRange:NSMakeRange(rawAddress.length - 10, 10)]];
|
||||||
|
NSString *methodAddress = [self searchMethod:addressString sortedAllAddress:sortedAllAddress];
|
||||||
|
|
||||||
|
if (methodAddress) {
|
||||||
|
containsFBSDKFunction = YES;
|
||||||
|
nonSDKMethodCount == 0 ?: [symbolicatedCallstack addObject:[NSString stringWithFormat:@"(%ld DEV METHODS)", (long)nonSDKMethodCount]];
|
||||||
|
nonSDKMethodCount = 0;
|
||||||
|
NSString *methodName = [methodMapping objectForKey:methodAddress];
|
||||||
|
[symbolicatedCallstack addObject:[NSString stringWithFormat:@"%@%@", methodName, [self getOffset:addressString secondString:methodAddress]]];
|
||||||
|
} else {
|
||||||
|
nonSDKMethodCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
nonSDKMethodCount == 0 ?: [symbolicatedCallstack addObject:[NSString stringWithFormat:@"(%ld DEV METHODS)", (long)nonSDKMethodCount]];
|
||||||
|
|
||||||
|
return containsFBSDKFunction ? symbolicatedCallstack : nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (NSString *)getAddress:(NSString *)callstackEntry
|
||||||
|
{
|
||||||
|
NSArray<NSString *> *components = [callstackEntry componentsSeparatedByString:@" "];
|
||||||
|
for (NSString *component in components) {
|
||||||
|
if ([component containsString:@"0x"]) {
|
||||||
|
return component;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (NSString *)getOffset:(NSString *)firstString
|
||||||
|
secondString:(NSString *)secondString
|
||||||
|
{
|
||||||
|
if (!firstString || !secondString) {
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
unsigned long long first = 0, second = 0;
|
||||||
|
NSScanner *scanner = [NSScanner scannerWithString:firstString];
|
||||||
|
[scanner scanHexLongLong:&first];
|
||||||
|
|
||||||
|
scanner = [NSScanner scannerWithString:secondString];
|
||||||
|
[scanner scanHexLongLong:&second];
|
||||||
|
|
||||||
|
unsigned long long difference = first - second;
|
||||||
|
return [NSString stringWithFormat:@"+%llu", difference];
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (NSString *)searchMethod:(NSString *)address
|
||||||
|
sortedAllAddress:(NSArray<NSString *> *)sortedAllAddress
|
||||||
|
{
|
||||||
|
if (0 == sortedAllAddress.count) {
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
NSString *lowestAddress = sortedAllAddress[0];
|
||||||
|
NSString *highestAddress = sortedAllAddress[sortedAllAddress.count - 1];
|
||||||
|
|
||||||
|
if ([address compare:lowestAddress] == NSOrderedAscending || [address compare:highestAddress] == NSOrderedDescending) {
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ([address compare:lowestAddress] == NSOrderedSame) {
|
||||||
|
return lowestAddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ([address compare:highestAddress] == NSOrderedSame) {
|
||||||
|
return highestAddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
NSUInteger index = [sortedAllAddress indexOfObject:address
|
||||||
|
inSortedRange:NSMakeRange(0, sortedAllAddress.count - 1)
|
||||||
|
options:NSBinarySearchingInsertionIndex
|
||||||
|
usingComparator:^NSComparisonResult(id _Nonnull obj1, id _Nonnull obj2) {
|
||||||
|
return [obj1 compare:obj2];
|
||||||
|
}];
|
||||||
|
return sortedAllAddress[index - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user