adding pods method of package managing
This commit is contained in:
Generated
+17
@@ -0,0 +1,17 @@
|
||||
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.
|
||||
Generated
+83
@@ -0,0 +1,83 @@
|
||||
# Facebook SDK for iOS
|
||||
|
||||
[](https://cocoapods.org/pods/FBSDKCoreKit)
|
||||
[](https://circleci.com/gh/facebook/facebook-ios-sdk/tree/master)
|
||||
|
||||
[](https://cocoapods.org/pods/FBSDKCoreKit)
|
||||
[](https://github.com/Carthage/Carthage)
|
||||
|
||||
This open-source library allows you to integrate Facebook into your iOS app.
|
||||
|
||||
Learn more about the provided samples, documentation, integrating the SDK into your app, accessing source code, and more
|
||||
at https://developers.facebook.com/docs/ios
|
||||
|
||||
Please take a moment and [subscribe to releases](https://docs.github.com/en/enterprise/2.15/user/articles/watching-and-unwatching-repositories) so that you can be notified about new features, deprecations, and critical fixes. To see information about the latest release, consult our [changelog](CHANGELOG.md).
|
||||
|
||||
|
||||
## TRY IT OUT
|
||||
|
||||
### Swift Package Manager
|
||||
|
||||
1. In Xcode, select File > Swift Packages > Add Package Dependency.
|
||||
1. Follow the prompts using the URL for this repository
|
||||
1. Select the `Facebook`-prefixed libraries you want to use
|
||||
1. Check-out the tutorials available online at: <https://developers.facebook.com/docs/ios/getting-started>
|
||||
1. Start coding! Visit <https://developers.facebook.com/docs/ios> for tutorials and reference documentation.
|
||||
|
||||
## iOS 14 CHANGES
|
||||
|
||||
### Data Disclosure
|
||||
|
||||
Due to the release of iOS 14, tracking events that your app collects and sends to Facebook may require you to disclosed these data types in the App Store Connect questionnaire. It is your responsibility to ensure this is reflected in your application’s privacy policy. Visit our blogpost for information on affected Facebook SDKs, APIs, and products and the Apple App Store Privacy Details article to learn more about the data types you will need to disclose.
|
||||
|
||||
link to FB blogpost https://developers.facebook.com/blog/post/2020/10/22/preparing-for-apple-app-store-data-disclosure-requirements/
|
||||
|
||||
apple store details https://developer.apple.com/app-store/app-privacy-details/
|
||||
|
||||
## FEATURES
|
||||
|
||||
- Login - <https://developers.facebook.com/docs/facebook-login>
|
||||
- Sharing - <https://developers.facebook.com/docs/sharing>
|
||||
- App Links - <https://developers.facebook.com/docs/applinks>
|
||||
- Graph API - <https://developers.facebook.com/docs/ios/graph>
|
||||
- Analytics - <https://developers.facebook.com/docs/analytics>
|
||||
|
||||
## GIVE FEEDBACK
|
||||
|
||||
Please report bugs or issues to our designated developer support team -- <https://developers.facebook.com/support/bugs/> -- as this will help us resolve them more quickly.
|
||||
|
||||
You can also visit our [Facebook Developer Community Forum](https://developers.facebook.com/community/),
|
||||
join the [Facebook Developers Group on Facebook](https://www.facebook.com/groups/fbdevelopers/),
|
||||
ask questions on [Stack Overflow](http://facebook.stackoverflow.com),
|
||||
or open an issue in this repository.
|
||||
|
||||
## CONTRIBUTE
|
||||
|
||||
Facebook welcomes contributions to our SDKs. Please see the [CONTRIBUTING](CONTRIBUTING) file.
|
||||
|
||||
## LICENSE
|
||||
|
||||
See the [LICENSE](LICENSE) file.
|
||||
|
||||
## SECURITY POLICY
|
||||
|
||||
See the [SECURITY POLICY](SECURITY.md) for more info on our bug bounty program.
|
||||
|
||||
## DEVELOPER TERMS
|
||||
|
||||
- By enabling Facebook integrations, including through this SDK, you can share information with Facebook, including
|
||||
information about people’s use of your app. Facebook will use information received in accordance with our
|
||||
[Data Use Policy](https://www.facebook.com/about/privacy/), including to provide you with insights about the
|
||||
effectiveness of your ads and the use of your app. These integrations also enable us and our partners to serve ads on
|
||||
and off Facebook.
|
||||
- You may limit your sharing of information with us by updating the Insights control in the developer tool
|
||||
`https://developers.facebook.com/apps/{app_id}/settings/advanced`.
|
||||
- If you use a Facebook integration, including to share information with us, you agree and confirm that you have
|
||||
provided appropriate and sufficiently prominent notice to and obtained the appropriate consent from your users
|
||||
regarding such collection, use, and disclosure (including, at a minimum, through your privacy policy). You further
|
||||
agree that you will not share information with us about children under the age of 13.
|
||||
- You agree to comply with all applicable laws and regulations and also agree to our Terms
|
||||
<https://www.facebook.com/policies/>, including our Platform Policies <https://developers.facebook.com/policy/> and
|
||||
Advertising Guidelines, as applicable <https://www.facebook.com/ad_guidelines.php>.
|
||||
|
||||
By using the Facebook SDK for iOS you agree to these terms.
|
||||
@@ -0,0 +1,44 @@
|
||||
// Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
|
||||
//
|
||||
// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,
|
||||
// copy, modify, and distribute this software in source code or binary form for use
|
||||
// in connection with the web services and APIs provided by Facebook.
|
||||
//
|
||||
// As with any software that integrates with the Facebook platform, your use of
|
||||
// this software is subject to the Facebook Developer Principles and Policies
|
||||
// [http://developers.facebook.com/policy/]. This copyright notice shall be
|
||||
// included in all copies or substantial portions of the software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#import "TargetConditionals.h"
|
||||
|
||||
#if !TARGET_OS_TV
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#import "FBAEMAdvertiserRuleMatching.h"
|
||||
#import "FBAEMAdvertiserRuleOperator.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
NS_SWIFT_NAME(AEMAdvertiserMultiEntryRule)
|
||||
@interface FBAEMAdvertiserMultiEntryRule : NSObject<FBAEMAdvertiserRuleMatching, NSCopying, NSSecureCoding>
|
||||
|
||||
@property (nonatomic, readonly, assign) FBAEMAdvertiserRuleOperator operator;
|
||||
|
||||
@property (nonatomic, readonly) NSArray<id<FBAEMAdvertiserRuleMatching>> *rules;
|
||||
|
||||
- (instancetype)initWithOperator:(FBAEMAdvertiserRuleOperator)op
|
||||
rules:(NSArray<id<FBAEMAdvertiserRuleMatching>> *)rules;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,101 @@
|
||||
// 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 "TargetConditionals.h"
|
||||
|
||||
#if !TARGET_OS_TV
|
||||
|
||||
#import "FBAEMAdvertiserMultiEntryRule.h"
|
||||
|
||||
#import "FBAEMAdvertiserSingleEntryRule.h"
|
||||
|
||||
static NSString *const OPERATOR_KEY = @"operator";
|
||||
static NSString *const RULES_KEY = @"rules";
|
||||
|
||||
@implementation FBAEMAdvertiserMultiEntryRule
|
||||
|
||||
- (instancetype)initWithOperator:(FBAEMAdvertiserRuleOperator)op
|
||||
rules:(NSArray<id<FBAEMAdvertiserRuleMatching>> *)rules
|
||||
{
|
||||
if (self = [super init]) {
|
||||
_operator = op;
|
||||
_rules = rules;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
#pragma mark - FBAEMAdvertiserRuleMatching
|
||||
|
||||
- (BOOL)isMatchedEventParameters:(nullable NSDictionary<NSString *, id> *)eventParams
|
||||
{
|
||||
@try {
|
||||
BOOL isMatched = _operator == FBAEMAdvertiserRuleOperatorOr ? NO : YES;
|
||||
for (id<FBAEMAdvertiserRuleMatching> rule in _rules) {
|
||||
BOOL doesSubruleMatch = [rule isMatchedEventParameters:eventParams];
|
||||
if (_operator == FBAEMAdvertiserRuleOperatorAnd) {
|
||||
isMatched = isMatched & doesSubruleMatch;
|
||||
}
|
||||
if (_operator == FBAEMAdvertiserRuleOperatorOr) {
|
||||
isMatched = isMatched | doesSubruleMatch;
|
||||
}
|
||||
if (_operator == FBAEMAdvertiserRuleOperatorNot) {
|
||||
isMatched = isMatched & !doesSubruleMatch;
|
||||
}
|
||||
}
|
||||
return isMatched;
|
||||
} @catch (NSException *exception) {
|
||||
#if DEBUG
|
||||
#if FBTEST
|
||||
@throw exception;
|
||||
#endif
|
||||
#endif
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - NSCoding
|
||||
|
||||
+ (BOOL)supportsSecureCoding
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (instancetype)initWithCoder:(NSCoder *)decoder
|
||||
{
|
||||
FBAEMAdvertiserRuleOperator op = [decoder decodeIntegerForKey:OPERATOR_KEY];
|
||||
NSSet *classes = [NSSet setWithArray:@[NSArray.class, FBAEMAdvertiserMultiEntryRule.class, FBAEMAdvertiserSingleEntryRule.class]];
|
||||
NSArray<id<FBAEMAdvertiserRuleMatching>> *rules = [decoder decodeObjectOfClasses:classes forKey:RULES_KEY];
|
||||
return [self initWithOperator:op rules:rules];
|
||||
}
|
||||
|
||||
- (void)encodeWithCoder:(NSCoder *)encoder
|
||||
{
|
||||
[encoder encodeInteger:_operator forKey:OPERATOR_KEY];
|
||||
[encoder encodeObject:_rules forKey:RULES_KEY];
|
||||
}
|
||||
|
||||
#pragma mark - NSCopying
|
||||
|
||||
- (instancetype)copyWithZone:(NSZone *)zone
|
||||
{
|
||||
return self;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,38 @@
|
||||
|
||||
// Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
|
||||
//
|
||||
// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,
|
||||
// copy, modify, and distribute this software in source code or binary form for use
|
||||
// in connection with the web services and APIs provided by Facebook.
|
||||
//
|
||||
// As with any software that integrates with the Facebook platform, your use of
|
||||
// this software is subject to the Facebook Developer Principles and Policies
|
||||
// [http://developers.facebook.com/policy/]. This copyright notice shall be
|
||||
// included in all copies or substantial portions of the software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#import "TargetConditionals.h"
|
||||
|
||||
#if !TARGET_OS_TV
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#import "FBAEMAdvertiserRuleMatching.h"
|
||||
#import "FBAEMAdvertiserRuleProviding.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
NS_SWIFT_NAME(AEMAdvertiserRuleFactory)
|
||||
@interface FBAEMAdvertiserRuleFactory : NSObject<FBAEMAdvertiserRuleProviding>
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,184 @@
|
||||
// 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 "TargetConditionals.h"
|
||||
|
||||
#if !TARGET_OS_TV
|
||||
|
||||
#import "FBAEMAdvertiserRuleFactory.h"
|
||||
|
||||
#import "FBAEMAdvertiserMultiEntryRule.h"
|
||||
#import "FBAEMAdvertiserSingleEntryRule.h"
|
||||
#import "FBCoreKitBasicsImportForAEMKit.h"
|
||||
|
||||
@implementation FBAEMAdvertiserRuleFactory
|
||||
|
||||
- (nullable id<FBAEMAdvertiserRuleMatching>)createRuleWithJson:(nullable NSString *)json
|
||||
{
|
||||
@try {
|
||||
json = [FBSDKTypeUtility stringValueOrNil:json];
|
||||
if (!json) {
|
||||
return nil;
|
||||
}
|
||||
NSDictionary<NSString *, id> *rule = [FBSDKBasicUtility objectForJSONString:json error:nil];
|
||||
return [self createRuleWithDict:rule];
|
||||
} @catch (NSException *exception) {
|
||||
NSLog(@"Fail to parse Advertiser Rules with JSON");
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (nullable id<FBAEMAdvertiserRuleMatching>)createRuleWithDict:(NSDictionary<NSString *, id> *)dict
|
||||
{
|
||||
@try {
|
||||
dict = [FBSDKTypeUtility dictionaryValue:dict];
|
||||
if (!dict) {
|
||||
return nil;
|
||||
}
|
||||
FBAEMAdvertiserRuleOperator op = [self getOperator:dict];
|
||||
if ([self isOperatorForMultiEntryRule:op]) {
|
||||
return [self createMultiEntryRuleWithDict:dict];
|
||||
} else {
|
||||
return [self createSingleEntryRuleWithDict:dict];
|
||||
}
|
||||
} @catch (NSException *exception) {
|
||||
NSLog(@"Fail to parse Advertiser Rules with Dict");
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (nullable FBAEMAdvertiserMultiEntryRule *)createMultiEntryRuleWithDict:(NSDictionary<NSString *, id> *)dict
|
||||
{
|
||||
dict = [FBSDKTypeUtility dictionaryValue:dict];
|
||||
if (!dict) {
|
||||
return nil;
|
||||
}
|
||||
NSString *opString = [self primaryKeyForRule:dict];
|
||||
FBAEMAdvertiserRuleOperator operator = [self getOperator:dict];
|
||||
if (![self isOperatorForMultiEntryRule:operator]) {
|
||||
return nil;
|
||||
}
|
||||
NSArray<NSDictionary *> *subrules = [FBSDKTypeUtility dictionary:dict objectForKey:opString ofType:NSArray.class];
|
||||
NSMutableArray<id<FBAEMAdvertiserRuleMatching>> *rules = [NSMutableArray new];
|
||||
for (NSDictionary *subrule in subrules) {
|
||||
id<FBAEMAdvertiserRuleMatching> entryRule = [self createRuleWithDict:subrule];
|
||||
if (!entryRule) {
|
||||
return nil;
|
||||
}
|
||||
[FBSDKTypeUtility array:rules addObject:entryRule];
|
||||
}
|
||||
if (!rules.count) {
|
||||
return nil;
|
||||
}
|
||||
return [[FBAEMAdvertiserMultiEntryRule alloc] initWithOperator:operator rules:rules];
|
||||
}
|
||||
|
||||
- (nullable FBAEMAdvertiserSingleEntryRule *)createSingleEntryRuleWithDict:(NSDictionary<NSString *, id> *)dict
|
||||
{
|
||||
dict = [FBSDKTypeUtility dictionaryValue:dict];
|
||||
if (!dict) {
|
||||
return nil;
|
||||
}
|
||||
NSString *paramKey = [self primaryKeyForRule:dict];
|
||||
NSDictionary<NSString *, id> *rawRule = [FBSDKTypeUtility dictionary:dict objectForKey:paramKey ofType:NSDictionary.class];
|
||||
NSString *encodedOperator = [self primaryKeyForRule:rawRule];
|
||||
FBAEMAdvertiserRuleOperator operator = [self getOperator:rawRule];
|
||||
NSString *linguisticCondition = nil;
|
||||
NSNumber *numericalCondition = nil;
|
||||
NSArray *arrayCondition = nil;
|
||||
switch (operator) {
|
||||
case Unknown:
|
||||
default:
|
||||
return nil;
|
||||
case FBAEMAdvertiserRuleOperatorContains:
|
||||
case FBAEMAdvertiserRuleOperatorNotContains:
|
||||
case FBAEMAdvertiserRuleOperatorStartsWith:
|
||||
case FBAEMAdvertiserRuleOperatorI_Contains:
|
||||
case FBAEMAdvertiserRuleOperatorI_NotContains:
|
||||
case FBAEMAdvertiserRuleOperatorI_StartsWith:
|
||||
case FBAEMAdvertiserRuleOperatorRegexMatch:
|
||||
case FBAEMAdvertiserRuleOperatorEqual:
|
||||
case FBAEMAdvertiserRuleOperatorNotEqual:
|
||||
linguisticCondition = [FBSDKTypeUtility dictionary:rawRule objectForKey:encodedOperator ofType:NSString.class]; break;
|
||||
case FBAEMAdvertiserRuleOperatorLessThan:
|
||||
case FBAEMAdvertiserRuleOperatorLessThanOrEqual:
|
||||
case FBAEMAdvertiserRuleOperatorGreaterThan:
|
||||
case FBAEMAdvertiserRuleOperatorGreaterThanOrEqual:
|
||||
numericalCondition = [FBSDKTypeUtility dictionary:rawRule objectForKey:encodedOperator ofType:NSNumber.class]; break;
|
||||
case FBAEMAdvertiserRuleOperatorI_IsAny:
|
||||
case FBAEMAdvertiserRuleOperatorI_IsNotAny:
|
||||
case FBAEMAdvertiserRuleOperatorIsAny:
|
||||
case FBAEMAdvertiserRuleOperatorIsNotAny:
|
||||
arrayCondition = [FBSDKTypeUtility dictionary:rawRule objectForKey:encodedOperator ofType:NSArray.class]; break;
|
||||
}
|
||||
if (linguisticCondition || numericalCondition != nil || arrayCondition.count > 0) {
|
||||
return [[FBAEMAdvertiserSingleEntryRule alloc] initWithOperator:operator paramKey:paramKey linguisticCondition:linguisticCondition numericalCondition:numericalCondition arrayCondition:arrayCondition];
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (nullable NSString *)primaryKeyForRule:(NSDictionary<NSString *, id> *)rule
|
||||
{
|
||||
NSArray<NSString *> *keys = [rule allKeys];
|
||||
NSString *key = keys.firstObject;
|
||||
return [FBSDKTypeUtility stringValueOrNil:key];
|
||||
}
|
||||
|
||||
- (FBAEMAdvertiserRuleOperator)getOperator:(NSDictionary<NSString *, id> *)rule
|
||||
{
|
||||
NSString *key = [self primaryKeyForRule:rule];
|
||||
if (!key) {
|
||||
return Unknown;
|
||||
}
|
||||
NSArray<NSString *> *operatorKeys = @[
|
||||
@"unknown",
|
||||
@"and",
|
||||
@"or",
|
||||
@"not",
|
||||
@"contains",
|
||||
@"not_contains",
|
||||
@"starts_with",
|
||||
@"i_contains",
|
||||
@"i_not_contains",
|
||||
@"i_starts_with",
|
||||
@"regex_match",
|
||||
@"eq",
|
||||
@"neq",
|
||||
@"lt",
|
||||
@"lte",
|
||||
@"gt",
|
||||
@"gte",
|
||||
@"i_is_any",
|
||||
@"i_is_not_any",
|
||||
@"is_any",
|
||||
@"is_not_any"
|
||||
];
|
||||
NSInteger index = [operatorKeys indexOfObject:key.lowercaseString];
|
||||
return index == NSNotFound ? Unknown : index;
|
||||
}
|
||||
|
||||
- (BOOL)isOperatorForMultiEntryRule:(FBAEMAdvertiserRuleOperator)operator
|
||||
{
|
||||
return operator == FBAEMAdvertiserRuleOperatorAnd
|
||||
|| operator == FBAEMAdvertiserRuleOperatorOr
|
||||
|| operator == FBAEMAdvertiserRuleOperatorNot;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,35 @@
|
||||
// Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
|
||||
//
|
||||
// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,
|
||||
// copy, modify, and distribute this software in source code or binary form for use
|
||||
// in connection with the web services and APIs provided by Facebook.
|
||||
//
|
||||
// As with any software that integrates with the Facebook platform, your use of
|
||||
// this software is subject to the Facebook Developer Principles and Policies
|
||||
// [http://developers.facebook.com/policy/]. This copyright notice shall be
|
||||
// included in all copies or substantial portions of the software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#import "TargetConditionals.h"
|
||||
|
||||
#if !TARGET_OS_TV
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@protocol FBAEMAdvertiserRuleMatching <NSObject>
|
||||
|
||||
- (BOOL)isMatchedEventParameters:(nullable NSDictionary<NSString *, id> *)eventParams;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,50 @@
|
||||
// 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 "TargetConditionals.h"
|
||||
|
||||
#if !TARGET_OS_TV
|
||||
|
||||
typedef NS_CLOSED_ENUM(NSInteger, FBAEMAdvertiserRuleOperator)
|
||||
{
|
||||
Unknown = 0,
|
||||
// Multi Entry Rule Operator
|
||||
FBAEMAdvertiserRuleOperatorAnd,
|
||||
FBAEMAdvertiserRuleOperatorOr,
|
||||
FBAEMAdvertiserRuleOperatorNot,
|
||||
// Single Entry Rule Operator
|
||||
FBAEMAdvertiserRuleOperatorContains,
|
||||
FBAEMAdvertiserRuleOperatorNotContains,
|
||||
FBAEMAdvertiserRuleOperatorStartsWith,
|
||||
FBAEMAdvertiserRuleOperatorI_Contains,
|
||||
FBAEMAdvertiserRuleOperatorI_NotContains,
|
||||
FBAEMAdvertiserRuleOperatorI_StartsWith,
|
||||
FBAEMAdvertiserRuleOperatorRegexMatch,
|
||||
FBAEMAdvertiserRuleOperatorEqual,
|
||||
FBAEMAdvertiserRuleOperatorNotEqual,
|
||||
FBAEMAdvertiserRuleOperatorLessThan,
|
||||
FBAEMAdvertiserRuleOperatorLessThanOrEqual,
|
||||
FBAEMAdvertiserRuleOperatorGreaterThan,
|
||||
FBAEMAdvertiserRuleOperatorGreaterThanOrEqual,
|
||||
FBAEMAdvertiserRuleOperatorI_IsAny,
|
||||
FBAEMAdvertiserRuleOperatorI_IsNotAny,
|
||||
FBAEMAdvertiserRuleOperatorIsAny,
|
||||
FBAEMAdvertiserRuleOperatorIsNotAny
|
||||
} NS_SWIFT_NAME(AEMAdvertiserRuleOperator);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,37 @@
|
||||
// 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 "TargetConditionals.h"
|
||||
|
||||
#if !TARGET_OS_TV
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/// Describes anything that can provide instances of `AEMAdvertiserRuleMatching`
|
||||
NS_SWIFT_NAME(AEMAdvertiserRuleProviding)
|
||||
@protocol FBAEMAdvertiserRuleProviding
|
||||
|
||||
- (nullable id<FBAEMAdvertiserRuleMatching>)createRuleWithJson:(nullable NSString *)json;
|
||||
|
||||
- (nullable id<FBAEMAdvertiserRuleMatching>)createRuleWithDict:(NSDictionary<NSString *, id> *)dict;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,53 @@
|
||||
// Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
|
||||
//
|
||||
// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,
|
||||
// copy, modify, and distribute this software in source code or binary form for use
|
||||
// in connection with the web services and APIs provided by Facebook.
|
||||
//
|
||||
// As with any software that integrates with the Facebook platform, your use of
|
||||
// this software is subject to the Facebook Developer Principles and Policies
|
||||
// [http://developers.facebook.com/policy/]. This copyright notice shall be
|
||||
// included in all copies or substantial portions of the software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#import "TargetConditionals.h"
|
||||
|
||||
#if !TARGET_OS_TV
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#import "FBAEMAdvertiserRuleMatching.h"
|
||||
#import "FBAEMAdvertiserRuleOperator.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
NS_SWIFT_NAME(AEMAdvertiserSingleEntryRule)
|
||||
@interface FBAEMAdvertiserSingleEntryRule : NSObject<FBAEMAdvertiserRuleMatching, NSCopying, NSSecureCoding>
|
||||
|
||||
@property (nonatomic, readonly, assign) FBAEMAdvertiserRuleOperator operator;
|
||||
|
||||
@property (nonatomic, readonly) NSString *paramKey;
|
||||
|
||||
@property (nullable, nonatomic, readonly) NSString *linguisticCondition;
|
||||
|
||||
@property (nullable, nonatomic, readonly) NSNumber *numericalCondition;
|
||||
|
||||
@property (nullable, nonatomic, readonly) NSArray *arrayCondition;
|
||||
|
||||
- (instancetype)initWithOperator:(FBAEMAdvertiserRuleOperator)op
|
||||
paramKey:(NSString *)paramKey
|
||||
linguisticCondition:(nullable NSString *)linguisticCondition
|
||||
numericalCondition:(nullable NSNumber *)numericalCondition
|
||||
arrayCondition:(nullable NSArray *)arrayCondition;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,267 @@
|
||||
// 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 "TargetConditionals.h"
|
||||
|
||||
#if !TARGET_OS_TV
|
||||
|
||||
#import "FBAEMAdvertiserSingleEntryRule.h"
|
||||
|
||||
#import "FBCoreKitBasicsImportForAEMKit.h"
|
||||
|
||||
static NSString *const OPERATOR_KEY = @"operator";
|
||||
static NSString *const PARAMKEY_KEY = @"param_key";
|
||||
static NSString *const STRING_VALUE_KEY = @"string_value";
|
||||
static NSString *const NUMBER_VALUE_KEY = @"number_value";
|
||||
static NSString *const ARRAY_VALUE_KEY = @"array_value";
|
||||
static NSString *const PARAM_DELIMETER = @".";
|
||||
static NSString *const ASTERISK_DELIMETER = @"[*]";
|
||||
|
||||
@implementation FBAEMAdvertiserSingleEntryRule
|
||||
|
||||
- (instancetype)initWithOperator:(FBAEMAdvertiserRuleOperator)op
|
||||
paramKey:(NSString *)paramKey
|
||||
linguisticCondition:(nullable NSString *)linguisticCondition
|
||||
numericalCondition:(nullable NSNumber *)numericalCondition
|
||||
arrayCondition:(nullable NSArray *)arrayCondition
|
||||
{
|
||||
if ((self = [super init])) {
|
||||
_operator = op;
|
||||
_paramKey = paramKey;
|
||||
_linguisticCondition = linguisticCondition;
|
||||
_numericalCondition = numericalCondition;
|
||||
_arrayCondition = arrayCondition;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
#pragma mark - FBAEMAdvertiserRuleMatching
|
||||
|
||||
- (BOOL)isMatchedEventParameters:(nullable NSDictionary<NSString *, id> *)eventParams
|
||||
{
|
||||
@try {
|
||||
NSArray<NSString *> *paramPath = [_paramKey componentsSeparatedByString:PARAM_DELIMETER];
|
||||
return [self isMatchedEventParameters:eventParams paramPath:paramPath];
|
||||
} @catch (NSException *exception) {
|
||||
#if DEBUG
|
||||
#if FBTEST
|
||||
@throw exception;
|
||||
#endif
|
||||
#endif
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)isMatchedEventParameters:(nullable NSDictionary<NSString *, id> *)eventParams
|
||||
paramPath:(NSArray<NSString *> *)paramPath
|
||||
{
|
||||
eventParams = [FBSDKTypeUtility dictionaryValue:eventParams];
|
||||
if (!eventParams || !paramPath.count) {
|
||||
return NO;
|
||||
}
|
||||
NSString *param = [FBSDKTypeUtility stringValueOrNil:paramPath.firstObject];
|
||||
if ([param hasSuffix:ASTERISK_DELIMETER]) {
|
||||
return [self isMatchedWithAsteriskParam:param eventParameters:eventParams paramPath:paramPath];
|
||||
}
|
||||
// if data does not contain the key, we should return false directly.
|
||||
if (!param || ![[eventParams allKeys] containsObject:param]) {
|
||||
return NO;
|
||||
}
|
||||
// Apply operator rule if the last param is reached
|
||||
if (paramPath.count == 1) {
|
||||
NSString *stringValue = nil;
|
||||
NSNumber *numericalValue = nil;
|
||||
switch (_operator) {
|
||||
case FBAEMAdvertiserRuleOperatorContains:
|
||||
case FBAEMAdvertiserRuleOperatorNotContains:
|
||||
case FBAEMAdvertiserRuleOperatorStartsWith:
|
||||
case FBAEMAdvertiserRuleOperatorI_Contains:
|
||||
case FBAEMAdvertiserRuleOperatorI_NotContains:
|
||||
case FBAEMAdvertiserRuleOperatorI_StartsWith:
|
||||
case FBAEMAdvertiserRuleOperatorRegexMatch:
|
||||
case FBAEMAdvertiserRuleOperatorEqual:
|
||||
case FBAEMAdvertiserRuleOperatorNotEqual:
|
||||
case FBAEMAdvertiserRuleOperatorI_IsAny:
|
||||
case FBAEMAdvertiserRuleOperatorI_IsNotAny:
|
||||
case FBAEMAdvertiserRuleOperatorIsAny:
|
||||
case FBAEMAdvertiserRuleOperatorIsNotAny:
|
||||
stringValue = [FBSDKTypeUtility dictionary:eventParams objectForKey:param ofType:NSString.class]; break;
|
||||
case FBAEMAdvertiserRuleOperatorLessThan:
|
||||
case FBAEMAdvertiserRuleOperatorLessThanOrEqual:
|
||||
case FBAEMAdvertiserRuleOperatorGreaterThan:
|
||||
case FBAEMAdvertiserRuleOperatorGreaterThanOrEqual:
|
||||
numericalValue = [FBSDKTypeUtility dictionary:eventParams objectForKey:param ofType:NSNumber.class]; break;
|
||||
default: break;
|
||||
}
|
||||
return [self isMatchedWithStringValue:stringValue numericalValue:numericalValue];
|
||||
}
|
||||
NSDictionary<NSString *, id> *subParams = [FBSDKTypeUtility dictionary:eventParams objectForKey:param ofType:NSDictionary.class];
|
||||
NSRange range = NSMakeRange(1, paramPath.count - 1);
|
||||
NSArray *subParamPath = [paramPath subarrayWithRange:range];
|
||||
return [self isMatchedEventParameters:subParams paramPath:subParamPath];
|
||||
}
|
||||
|
||||
- (BOOL)isMatchedWithAsteriskParam:(NSString *)param
|
||||
eventParameters:(NSDictionary<NSString *, id> *)eventParams
|
||||
paramPath:(NSArray<NSString *> *)paramPath
|
||||
{
|
||||
param = [param substringToIndex:param.length - ASTERISK_DELIMETER.length];
|
||||
NSArray<NSDictionary *> *items = [FBSDKTypeUtility dictionary:eventParams objectForKey:param ofType:NSArray.class];
|
||||
if (!items.count || paramPath.count < 2) {
|
||||
return NO;
|
||||
}
|
||||
BOOL isMatched = NO;
|
||||
NSRange range = NSMakeRange(1, paramPath.count - 1);
|
||||
NSArray *subParamPath = [paramPath subarrayWithRange:range];
|
||||
for (NSDictionary *item in items) {
|
||||
isMatched |= [self isMatchedEventParameters:item paramPath:subParamPath];
|
||||
if (isMatched) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return isMatched;
|
||||
}
|
||||
|
||||
- (BOOL)isMatchedWithStringValue:(nullable NSString *)stringValue
|
||||
numericalValue:(nullable NSNumber *)numericalValue
|
||||
{
|
||||
BOOL isMatched = NO;
|
||||
switch (_operator) {
|
||||
case FBAEMAdvertiserRuleOperatorContains:
|
||||
isMatched = stringValue && [stringValue containsString:_linguisticCondition]; break;
|
||||
case FBAEMAdvertiserRuleOperatorNotContains:
|
||||
isMatched = !(stringValue && [stringValue containsString:_linguisticCondition]); break;
|
||||
case FBAEMAdvertiserRuleOperatorStartsWith:
|
||||
isMatched = stringValue && [stringValue hasPrefix:_linguisticCondition]; break;
|
||||
case FBAEMAdvertiserRuleOperatorI_Contains:
|
||||
isMatched = stringValue && [stringValue.lowercaseString containsString:_linguisticCondition.lowercaseString]; break;
|
||||
case FBAEMAdvertiserRuleOperatorI_NotContains:
|
||||
isMatched = !(stringValue && [stringValue.lowercaseString containsString:_linguisticCondition.lowercaseString]); break;
|
||||
case FBAEMAdvertiserRuleOperatorI_StartsWith:
|
||||
isMatched = stringValue && [stringValue.lowercaseString hasPrefix:_linguisticCondition.lowercaseString]; break;
|
||||
case FBAEMAdvertiserRuleOperatorRegexMatch:
|
||||
isMatched = stringValue && [self isRegexMatch:stringValue]; break;
|
||||
case FBAEMAdvertiserRuleOperatorEqual:
|
||||
isMatched = stringValue && [stringValue isEqualToString:_linguisticCondition]; break;
|
||||
case FBAEMAdvertiserRuleOperatorNotEqual:
|
||||
isMatched = !(stringValue && [stringValue isEqualToString:_linguisticCondition]); break;
|
||||
case FBAEMAdvertiserRuleOperatorI_IsAny:
|
||||
isMatched = stringValue && [self isAnyOf:_arrayCondition stringValue:stringValue ignoreCase:YES]; break;
|
||||
case FBAEMAdvertiserRuleOperatorI_IsNotAny:
|
||||
isMatched = !(stringValue && [self isAnyOf:_arrayCondition stringValue:stringValue ignoreCase:YES]); break;
|
||||
case FBAEMAdvertiserRuleOperatorIsAny:
|
||||
isMatched = stringValue && [self isAnyOf:_arrayCondition stringValue:stringValue ignoreCase:NO]; break;
|
||||
case FBAEMAdvertiserRuleOperatorIsNotAny:
|
||||
isMatched = !(stringValue && [self isAnyOf:_arrayCondition stringValue:stringValue ignoreCase:NO]); break;
|
||||
case FBAEMAdvertiserRuleOperatorLessThan:
|
||||
isMatched = (numericalValue != nil) && ([numericalValue compare:_numericalCondition] == NSOrderedAscending); break;
|
||||
case FBAEMAdvertiserRuleOperatorLessThanOrEqual:
|
||||
isMatched = (numericalValue != nil) && ([numericalValue compare:_numericalCondition] != NSOrderedDescending); break;
|
||||
case FBAEMAdvertiserRuleOperatorGreaterThan:
|
||||
isMatched = (numericalValue != nil) && ([numericalValue compare:_numericalCondition] == NSOrderedDescending); break;
|
||||
case FBAEMAdvertiserRuleOperatorGreaterThanOrEqual:
|
||||
isMatched = (numericalValue != nil) && ([numericalValue compare:_numericalCondition] != NSOrderedAscending); break;
|
||||
default: break;
|
||||
}
|
||||
return isMatched;
|
||||
}
|
||||
|
||||
- (BOOL)isRegexMatch:(NSString *)stringValue
|
||||
{
|
||||
if (!_linguisticCondition.length) {
|
||||
return NO;
|
||||
}
|
||||
NSError *error = nil;
|
||||
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:_linguisticCondition options:0 error:&error];
|
||||
if (!regex || error) {
|
||||
return NO;
|
||||
}
|
||||
NSRange searchedRange = NSMakeRange(0, stringValue.length);
|
||||
NSArray *matches = [regex matchesInString:stringValue options:0 range:searchedRange];
|
||||
return matches.count > 0;
|
||||
}
|
||||
|
||||
- (BOOL)isAnyOf:(NSArray<NSString *> *)arrayCondition
|
||||
stringValue:(NSString *)stringValue
|
||||
ignoreCase:(BOOL)ignoreCase
|
||||
{
|
||||
NSMutableSet<NSString *> *set = [NSMutableSet new];
|
||||
for (NSString *item in arrayCondition) {
|
||||
if (ignoreCase) {
|
||||
[set addObject:item.lowercaseString];
|
||||
} else {
|
||||
[set addObject:item];
|
||||
}
|
||||
}
|
||||
if (ignoreCase) {
|
||||
stringValue = stringValue.lowercaseString;
|
||||
}
|
||||
return [set containsObject:stringValue];
|
||||
}
|
||||
|
||||
#pragma mark - NSCoding
|
||||
|
||||
+ (BOOL)supportsSecureCoding
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (instancetype)initWithCoder:(NSCoder *)decoder
|
||||
{
|
||||
FBAEMAdvertiserRuleOperator op = [decoder decodeIntegerForKey:OPERATOR_KEY];
|
||||
NSString *paramKey = [decoder decodeObjectOfClass:NSString.class forKey:PARAMKEY_KEY];
|
||||
NSString *linguisticCondition = [decoder decodeObjectOfClass:NSString.class forKey:STRING_VALUE_KEY];
|
||||
NSNumber *numericalCondition = [decoder decodeObjectOfClass:NSNumber.class forKey:NUMBER_VALUE_KEY];
|
||||
NSArray *arrayCondition = [decoder decodeObjectOfClass:NSArray.class forKey:ARRAY_VALUE_KEY];
|
||||
return [self initWithOperator:op
|
||||
paramKey:paramKey
|
||||
linguisticCondition:linguisticCondition
|
||||
numericalCondition:numericalCondition
|
||||
arrayCondition:arrayCondition];
|
||||
}
|
||||
|
||||
- (void)encodeWithCoder:(NSCoder *)encoder
|
||||
{
|
||||
[encoder encodeInteger:_operator forKey:OPERATOR_KEY];
|
||||
[encoder encodeObject:_paramKey forKey:PARAMKEY_KEY];
|
||||
[encoder encodeObject:_linguisticCondition forKey:STRING_VALUE_KEY];
|
||||
[encoder encodeObject:_numericalCondition forKey:NUMBER_VALUE_KEY];
|
||||
[encoder encodeObject:_arrayCondition forKey:ARRAY_VALUE_KEY];
|
||||
}
|
||||
|
||||
#pragma mark - NSCopying
|
||||
|
||||
- (instancetype)copyWithZone:(NSZone *)zone
|
||||
{
|
||||
return self;
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
#if FBTEST
|
||||
|
||||
- (void)setOperator:(FBAEMAdvertiserRuleOperator)operator
|
||||
{
|
||||
_operator = operator;
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@end
|
||||
|
||||
#endif
|
||||
+66
@@ -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 "TargetConditionals.h"
|
||||
|
||||
#if !TARGET_OS_TV
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#import "FBAEMRule.h"
|
||||
#import "FBAEMAdvertiserRuleMatching.h"
|
||||
#import "FBAEMAdvertiserRuleProviding.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
NS_SWIFT_NAME(AEMConfiguration)
|
||||
@interface FBAEMConfiguration : NSObject <NSCopying, NSSecureCoding>
|
||||
|
||||
@property (nonatomic, readonly, assign) NSInteger cutoffTime;
|
||||
|
||||
/** The UNIX timestamp of config's valid date and works as a unqiue identifier of the config */
|
||||
@property (nonatomic, readonly, assign) NSInteger validFrom;
|
||||
|
||||
@property (nonatomic, readonly, copy) NSString *defaultCurrency;
|
||||
|
||||
@property (nonatomic, readonly, copy) NSString *configMode;
|
||||
|
||||
@property (nullable, nonatomic, readonly, copy) NSString *businessID;
|
||||
|
||||
@property (nullable, nonatomic, readonly, copy) id<FBAEMAdvertiserRuleMatching> matchingRule;
|
||||
|
||||
@property (nonatomic, readonly) NSArray<FBAEMRule *> *conversionValueRules;
|
||||
|
||||
@property (nonatomic, readonly) NSSet<NSString *> *eventSet;
|
||||
|
||||
@property (nonatomic, readonly) NSSet<NSString *> *currencySet;
|
||||
|
||||
+ (void)configureWithRuleProvider:(id<FBAEMAdvertiserRuleProviding>)ruleProvider;
|
||||
|
||||
- (nullable instancetype)initWithJSON:(nullable NSDictionary<NSString *, id> *)dict;
|
||||
|
||||
- (BOOL)isSameValidFrom:(NSInteger)validFrom
|
||||
businessID:(nullable NSString *)businessID;
|
||||
|
||||
- (BOOL)isSameBusinessID:(nullable NSString *)businessID;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
#endif
|
||||
+231
@@ -0,0 +1,231 @@
|
||||
// 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 "TargetConditionals.h"
|
||||
|
||||
#if !TARGET_OS_TV
|
||||
|
||||
#import "FBAEMConfiguration.h"
|
||||
|
||||
#import "FBAEMAdvertiserMultiEntryRule.h"
|
||||
#import "FBAEMAdvertiserSingleEntryRule.h"
|
||||
#import "FBCoreKitBasicsImportForAEMKit.h"
|
||||
|
||||
static NSString *const DEFAULT_CURRENCY_KEY = @"default_currency";
|
||||
static NSString *const CUTOFF_TIME_KEY = @"cutoff_time";
|
||||
static NSString *const CONVERSION_RULES_KEY = @"conversion_value_rules";
|
||||
static NSString *const VALID_FROM_KEY = @"valid_from";
|
||||
static NSString *const CONFIG_MODE_KEY = @"config_mode";
|
||||
static NSString *const CONFIG_BUSINESS_ID_KEY = @"advertiser_id";
|
||||
static NSString *const BUSINESS_ID_KEY = @"business_id";
|
||||
static NSString *const PARAM_RULE_KEY = @"param_rule";
|
||||
|
||||
static id<FBAEMAdvertiserRuleProviding> _ruleProvider;
|
||||
|
||||
@implementation FBAEMConfiguration
|
||||
|
||||
+ (void)configureWithRuleProvider:(id<FBAEMAdvertiserRuleProviding>)ruleProvider
|
||||
{
|
||||
if (self == [FBAEMConfiguration class]) {
|
||||
_ruleProvider = ruleProvider;
|
||||
}
|
||||
}
|
||||
|
||||
+ (id<FBAEMAdvertiserRuleProviding>)ruleProvider
|
||||
{
|
||||
return _ruleProvider;
|
||||
}
|
||||
|
||||
- (nullable instancetype)initWithJSON:(nullable NSDictionary<NSString *, id> *)dict
|
||||
{
|
||||
if ((self = [super init])) {
|
||||
@try {
|
||||
dict = [FBSDKTypeUtility dictionaryValue:dict];
|
||||
if (!dict) {
|
||||
return nil;
|
||||
}
|
||||
NSString *defaultCurrency = [FBSDKTypeUtility dictionary:dict objectForKey:DEFAULT_CURRENCY_KEY ofType:NSString.class];
|
||||
NSNumber *cutoffTime = [FBSDKTypeUtility dictionary:dict objectForKey:CUTOFF_TIME_KEY ofType:NSNumber.class];
|
||||
NSNumber *validFrom = [FBSDKTypeUtility dictionary:dict objectForKey:VALID_FROM_KEY ofType:NSNumber.class];
|
||||
NSString *configMode = [FBSDKTypeUtility dictionary:dict objectForKey:CONFIG_MODE_KEY ofType:NSString.class];
|
||||
NSString *businessID = [FBSDKTypeUtility dictionary:dict objectForKey:CONFIG_BUSINESS_ID_KEY ofType:NSString.class];
|
||||
NSString *paramRuleJson = [FBSDKTypeUtility dictionary:dict objectForKey:PARAM_RULE_KEY ofType:NSString.class];
|
||||
id<FBAEMAdvertiserRuleMatching> matchingRule = [FBAEMConfiguration.ruleProvider createRuleWithJson:paramRuleJson];
|
||||
NSArray<FBAEMRule *> *rules = [FBAEMConfiguration parseRules:[FBSDKTypeUtility dictionary:dict objectForKey:CONVERSION_RULES_KEY ofType:NSArray.class]];
|
||||
if (!defaultCurrency || cutoffTime == nil || validFrom == nil || !configMode || 0 == rules.count) {
|
||||
return nil;
|
||||
}
|
||||
// Advertiser Config must have param rule
|
||||
if (businessID && !matchingRule) {
|
||||
return nil;
|
||||
}
|
||||
_defaultCurrency = defaultCurrency;
|
||||
_cutoffTime = cutoffTime.integerValue;
|
||||
_validFrom = validFrom.integerValue;
|
||||
_configMode = configMode;
|
||||
_businessID = businessID;
|
||||
_matchingRule = matchingRule;
|
||||
_conversionValueRules = rules;
|
||||
_eventSet = [FBAEMConfiguration getEventSetFromRules:_conversionValueRules];
|
||||
_currencySet = [FBAEMConfiguration getCurrencySetFromRules:_conversionValueRules];
|
||||
} @catch (NSException *exception) {
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (instancetype)initWithDefaultCurrency:(NSString *)defaultCurrency
|
||||
cutoffTime:(NSInteger)cutoffTime
|
||||
validFrom:(NSInteger)validFrom
|
||||
configMode:(NSString *)configMode
|
||||
businessID:(nullable NSString *)businessID
|
||||
matchingRule:(id<FBAEMAdvertiserRuleMatching>)matchingRule
|
||||
conversionValueRules:(NSArray<FBAEMRule *> *)conversionValueRules
|
||||
{
|
||||
if ((self = [super init])) {
|
||||
_defaultCurrency = defaultCurrency;
|
||||
_cutoffTime = cutoffTime;
|
||||
_validFrom = validFrom;
|
||||
_configMode = configMode;
|
||||
_businessID = businessID;
|
||||
_matchingRule = matchingRule;
|
||||
_conversionValueRules = conversionValueRules;
|
||||
_eventSet = [FBAEMConfiguration getEventSetFromRules:_conversionValueRules];
|
||||
_currencySet = [FBAEMConfiguration getCurrencySetFromRules:_conversionValueRules];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
+ (nullable NSArray<FBAEMRule *> *)parseRules:(nullable NSArray<NSDictionary<NSString *, id> *> *)rules
|
||||
{
|
||||
if (0 == rules.count) {
|
||||
return nil;
|
||||
}
|
||||
NSMutableArray<FBAEMRule *> *parsedRules = [NSMutableArray new];
|
||||
for (NSDictionary<NSString *, id> *ruleEntry in rules) {
|
||||
FBAEMRule *rule = [[FBAEMRule alloc] initWithJSON:ruleEntry];
|
||||
if (!rule) {
|
||||
return nil;
|
||||
}
|
||||
[FBSDKTypeUtility array:parsedRules addObject:rule];
|
||||
}
|
||||
// Sort the rules in descending priority order
|
||||
[parsedRules sortUsingComparator:^NSComparisonResult (FBAEMRule *obj1, FBAEMRule *obj2) {
|
||||
if (obj1.priority < obj2.priority) {
|
||||
return NSOrderedDescending;
|
||||
}
|
||||
if (obj1.priority > obj2.priority) {
|
||||
return NSOrderedAscending;
|
||||
}
|
||||
return NSOrderedSame;
|
||||
}];
|
||||
return [parsedRules copy];
|
||||
}
|
||||
|
||||
+ (NSSet<NSString *> *)getEventSetFromRules:(NSArray<FBAEMRule *> *)rules
|
||||
{
|
||||
NSMutableSet<NSString *> *eventSet = [NSMutableSet new];
|
||||
for (FBAEMRule *rule in rules) {
|
||||
if (!rule) {
|
||||
continue;
|
||||
}
|
||||
for (FBAEMEvent *event in rule.events) {
|
||||
if (event.eventName) {
|
||||
[eventSet addObject:event.eventName];
|
||||
}
|
||||
}
|
||||
}
|
||||
return [eventSet copy];
|
||||
}
|
||||
|
||||
+ (NSSet<NSString *> *)getCurrencySetFromRules:(NSArray<FBAEMRule *> *)rules
|
||||
{
|
||||
NSMutableSet<NSString *> *currencySet = [NSMutableSet new];
|
||||
for (FBAEMRule *rule in rules) {
|
||||
if (!rule) {
|
||||
continue;
|
||||
}
|
||||
for (FBAEMEvent *event in rule.events) {
|
||||
for (NSString *currency in event.values) {
|
||||
[currencySet addObject:[currency uppercaseString]];
|
||||
}
|
||||
}
|
||||
}
|
||||
return [currencySet copy];
|
||||
}
|
||||
|
||||
- (BOOL)isSameValidFrom:(NSInteger)validFrom
|
||||
businessID:(nullable NSString *)businessID
|
||||
{
|
||||
return (_validFrom == validFrom) && [self isSameBusinessID:businessID];
|
||||
}
|
||||
|
||||
- (BOOL)isSameBusinessID:(nullable NSString *)businessID
|
||||
{
|
||||
return (_businessID && [_businessID isEqualToString:businessID])
|
||||
|| (!_businessID && !businessID);
|
||||
}
|
||||
|
||||
#pragma mark - NSCoding
|
||||
|
||||
+ (BOOL)supportsSecureCoding
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (instancetype)initWithCoder:(NSCoder *)decoder
|
||||
{
|
||||
NSString *defaultCurrency = [decoder decodeObjectOfClass:NSString.class forKey:DEFAULT_CURRENCY_KEY];
|
||||
NSInteger cutoffTime = [decoder decodeIntegerForKey:CUTOFF_TIME_KEY];
|
||||
NSInteger validFrom = [decoder decodeIntegerForKey:VALID_FROM_KEY];
|
||||
NSString *configMode = [decoder decodeObjectOfClass:NSString.class forKey:CONFIG_MODE_KEY];
|
||||
NSString *businessID = [decoder decodeObjectOfClass:NSString.class forKey:BUSINESS_ID_KEY];
|
||||
NSSet *matchingRuleClasses = [NSSet setWithArray:@[NSArray.class, FBAEMAdvertiserMultiEntryRule.class, FBAEMAdvertiserSingleEntryRule.class]];
|
||||
id<FBAEMAdvertiserRuleMatching> matchingRule = [decoder decodeObjectOfClasses:matchingRuleClasses forKey:PARAM_RULE_KEY];
|
||||
NSArray<FBAEMRule *> *rules = [decoder decodeObjectOfClasses:[NSSet setWithArray:@[NSArray.class, FBAEMRule.class, FBAEMEvent.class]] forKey:CONVERSION_RULES_KEY];
|
||||
return [self initWithDefaultCurrency:defaultCurrency
|
||||
cutoffTime:cutoffTime
|
||||
validFrom:validFrom
|
||||
configMode:configMode
|
||||
businessID:businessID
|
||||
matchingRule:matchingRule
|
||||
conversionValueRules:rules];
|
||||
}
|
||||
|
||||
- (void)encodeWithCoder:(NSCoder *)encoder
|
||||
{
|
||||
[encoder encodeObject:_defaultCurrency forKey:DEFAULT_CURRENCY_KEY];
|
||||
[encoder encodeInteger:_cutoffTime forKey:CUTOFF_TIME_KEY];
|
||||
[encoder encodeInteger:_validFrom forKey:VALID_FROM_KEY];
|
||||
[encoder encodeObject:_configMode forKey:CONFIG_MODE_KEY];
|
||||
[encoder encodeObject:_businessID forKey:BUSINESS_ID_KEY];
|
||||
[encoder encodeObject:_matchingRule forKey:PARAM_RULE_KEY];
|
||||
[encoder encodeObject:_conversionValueRules forKey:CONVERSION_RULES_KEY];
|
||||
}
|
||||
|
||||
#pragma mark - NSCopying
|
||||
|
||||
- (instancetype)copyWithZone:(NSZone *)zone
|
||||
{
|
||||
return self;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#endif
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
// Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
|
||||
//
|
||||
// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,
|
||||
// copy, modify, and distribute this software in source code or binary form for use
|
||||
// in connection with the web services and APIs provided by Facebook.
|
||||
//
|
||||
// As with any software that integrates with the Facebook platform, your use of
|
||||
// this software is subject to the Facebook Developer Principles and Policies
|
||||
// [http://developers.facebook.com/policy/]. This copyright notice shall be
|
||||
// included in all copies or substantial portions of the software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#import "TargetConditionals.h"
|
||||
|
||||
#if !TARGET_OS_TV
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface FBAEMEvent : NSObject <NSCopying, NSSecureCoding>
|
||||
|
||||
@property (nonatomic, readonly, copy) NSString *eventName;
|
||||
|
||||
@property (nullable, nonatomic, readonly, copy) NSDictionary<NSString *, NSNumber *> *values;
|
||||
|
||||
- (nullable instancetype)initWithJSON:(nullable NSDictionary<NSString *, id> *)dict;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
#endif
|
||||
+106
@@ -0,0 +1,106 @@
|
||||
// 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 "TargetConditionals.h"
|
||||
|
||||
#if !TARGET_OS_TV
|
||||
|
||||
#import "FBAEMEvent.h"
|
||||
|
||||
#import "FBCoreKitBasicsImportForAEMKit.h"
|
||||
|
||||
static NSString *const EVENT_NAME_KEY = @"event_name";
|
||||
static NSString *const VALUES_KEY = @"values";
|
||||
static NSString *const CURRENCY_KEY = @"currency";
|
||||
static NSString *const AMOUNT_KEY = @"amount";
|
||||
|
||||
@implementation FBAEMEvent
|
||||
|
||||
- (nullable instancetype)initWithJSON:(nullable NSDictionary<NSString *, id> *)dict
|
||||
{
|
||||
if ((self = [super init])) {
|
||||
dict = [FBSDKTypeUtility dictionaryValue:dict];
|
||||
if (!dict) {
|
||||
return nil;
|
||||
}
|
||||
_eventName = [FBSDKTypeUtility dictionary:dict objectForKey:EVENT_NAME_KEY ofType:NSString.class];
|
||||
// Event name is a required field
|
||||
if (!_eventName) {
|
||||
return nil;
|
||||
}
|
||||
// Values is an optional field
|
||||
NSArray<NSDictionary<NSString *, id> *> *valueEntries = [FBSDKTypeUtility dictionary:dict objectForKey:VALUES_KEY ofType:NSArray.class];
|
||||
if (valueEntries.count > 0) {
|
||||
NSMutableDictionary<NSString *, NSNumber *> *valueDict = [NSMutableDictionary new];
|
||||
for (NSDictionary<NSString *, id> *valueEntry in valueEntries) {
|
||||
NSDictionary<NSString *, id> *value = [FBSDKTypeUtility dictionaryValue:valueEntry];
|
||||
NSString *currency = [FBSDKTypeUtility dictionary:value objectForKey:CURRENCY_KEY ofType:NSString.class];
|
||||
NSNumber *amount = [FBSDKTypeUtility dictionary:value objectForKey:AMOUNT_KEY ofType:NSNumber.class];
|
||||
if (!currency || amount == nil) {
|
||||
return nil;
|
||||
}
|
||||
[FBSDKTypeUtility dictionary:valueDict setObject:amount forKey:[currency uppercaseString]];
|
||||
}
|
||||
_values = [valueDict copy];
|
||||
}
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (instancetype)initWithEventName:(NSString *)eventName
|
||||
values:(NSDictionary<NSString *, NSNumber *> *)values
|
||||
{
|
||||
if ((self = [super init])) {
|
||||
_eventName = eventName;
|
||||
_values = values;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
#pragma mark - NSCoding
|
||||
|
||||
+ (BOOL)supportsSecureCoding
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (instancetype)initWithCoder:(NSCoder *)decoder
|
||||
{
|
||||
NSString *eventName = [decoder decodeObjectOfClass:NSString.class forKey:EVENT_NAME_KEY];
|
||||
NSDictionary<NSString *, NSNumber *> *values = [decoder decodeObjectOfClass:NSDictionary.class forKey:VALUES_KEY];
|
||||
return [self initWithEventName:eventName values:values];
|
||||
}
|
||||
|
||||
- (void)encodeWithCoder:(NSCoder *)encoder
|
||||
{
|
||||
[encoder encodeObject:_eventName forKey:EVENT_NAME_KEY];
|
||||
if (_values) {
|
||||
[encoder encodeObject:_values forKey:VALUES_KEY];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - NSCopying
|
||||
|
||||
- (instancetype)copyWithZone:(NSZone *)zone
|
||||
{
|
||||
return self;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#endif
|
||||
+83
@@ -0,0 +1,83 @@
|
||||
// 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 "TargetConditionals.h"
|
||||
|
||||
#if !TARGET_OS_TV
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#import "FBAEMConfiguration.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
NS_SWIFT_NAME(AEMInvocation)
|
||||
@interface FBAEMInvocation : NSObject <NSCopying, NSSecureCoding>
|
||||
|
||||
@property (nonatomic, readonly, copy) NSString *campaignID;
|
||||
|
||||
@property (nonatomic, readonly, copy) NSString *ACSToken;
|
||||
|
||||
@property (nullable, nonatomic, readonly, copy) NSString *ACSSharedSecret;
|
||||
|
||||
@property (nullable, nonatomic, readonly, copy) NSString *ACSConfigID;
|
||||
|
||||
@property (nullable, nonatomic, readonly, copy) NSString *businessID;
|
||||
|
||||
@property (nonatomic, readonly, assign) BOOL isTestMode;
|
||||
|
||||
@property (nonatomic, readonly, assign) BOOL hasSKAN;
|
||||
|
||||
@property (nonatomic, readonly, copy) NSDate *timestamp;
|
||||
|
||||
@property (nonatomic, readonly, copy) NSString *configMode;
|
||||
|
||||
/** The unique identifier of the config, it's the same as config's validFrom */
|
||||
@property (nonatomic, readonly, assign) NSInteger configID;
|
||||
|
||||
@property (nonatomic, readonly) NSMutableSet<NSString *> *recordedEvents;
|
||||
|
||||
@property (nonatomic, readonly) NSMutableDictionary<NSString *, NSMutableDictionary *> *recordedValues;
|
||||
|
||||
@property (nonatomic, readonly, assign) NSInteger conversionValue;
|
||||
|
||||
@property (nonatomic, readonly, assign) NSInteger priority;
|
||||
|
||||
@property (nullable, nonatomic, readonly) NSDate *conversionTimestamp;
|
||||
|
||||
@property (nonatomic, assign) BOOL isAggregated;
|
||||
|
||||
+ (nullable instancetype)invocationWithAppLinkData:(nullable NSDictionary<id, id> *)applinkData;
|
||||
|
||||
- (BOOL)attributeEvent:(NSString *)event
|
||||
currency:(nullable NSString *)currency
|
||||
value:(nullable NSNumber *)value
|
||||
parameters:(nullable NSDictionary *)parameters
|
||||
configs:(nullable NSDictionary<NSString *, NSArray<FBAEMConfiguration *> *> *)configs;
|
||||
|
||||
- (BOOL)updateConversionValueWithConfigs:(nullable NSDictionary<NSString *, NSArray<FBAEMConfiguration *> *> *)configs;
|
||||
|
||||
- (BOOL)isOutOfWindowWithConfigs:(nullable NSDictionary<NSString *, NSArray<FBAEMConfiguration *> *> *)configs;
|
||||
|
||||
- (nullable NSString *)getHMAC:(NSInteger)delay;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
#endif
|
||||
+477
@@ -0,0 +1,477 @@
|
||||
// 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 "TargetConditionals.h"
|
||||
|
||||
#if !TARGET_OS_TV
|
||||
|
||||
#import "FBAEMInvocation.h"
|
||||
|
||||
#import <CommonCrypto/CommonHMAC.h>
|
||||
|
||||
#import "FBCoreKitBasicsImportForAEMKit.h"
|
||||
|
||||
#define SEC_IN_DAY 86400
|
||||
|
||||
static NSString *const CAMPAIGN_ID_KEY = @"campaign_ids";
|
||||
static NSString *const ACS_TOKEN_KEY = @"acs_token";
|
||||
static NSString *const ACS_SHARED_SECRET_KEY = @"shared_secret";
|
||||
static NSString *const ACS_CONFIG_ID_KEY = @"acs_config_id";
|
||||
static NSString *const BUSINESS_ID_KEY = @"advertiser_id";
|
||||
static NSString *const TEST_DEEPLINK_KEY = @"test_deeplink";
|
||||
static NSString *const TIMESTAMP_KEY = @"timestamp";
|
||||
static NSString *const CONFIG_MODE_KEY = @"config_mode";
|
||||
static NSString *const CONFIG_ID_KEY = @"config_id";
|
||||
static NSString *const RECORDED_EVENTS_KEY = @"recorded_events";
|
||||
static NSString *const RECORDED_VALUES_KEY = @"recorded_values";
|
||||
static NSString *const CONVERSION_VALUE_KEY = @"conversion_value";
|
||||
static NSString *const PRIORITY_KEY = @"priority";
|
||||
static NSString *const CONVERSION_TIMESTAMP_KEY = @"conversion_timestamp";
|
||||
static NSString *const IS_AGGREGATED_KEY = @"is_aggregated";
|
||||
static NSString *const HAS_SKAN_KEY = @"has_skan";
|
||||
|
||||
static NSString *const FB_CONTENT = @"fb_content";
|
||||
|
||||
typedef NSString *const FBAEMInvocationConfigMode;
|
||||
|
||||
FBAEMInvocationConfigMode FBAEMInvocationConfigDefaultMode = @"DEFAULT";
|
||||
FBAEMInvocationConfigMode FBAEMInvocationConfigBrandMode = @"BRAND";
|
||||
|
||||
@implementation FBAEMInvocation
|
||||
|
||||
+ (nullable instancetype)invocationWithAppLinkData:(nullable NSDictionary<id, id> *)applinkData
|
||||
{
|
||||
@try {
|
||||
applinkData = [FBSDKTypeUtility dictionaryValue:applinkData];
|
||||
if (!applinkData) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
NSString *campaignID = [FBSDKTypeUtility dictionary:applinkData objectForKey:CAMPAIGN_ID_KEY ofType:NSString.class];
|
||||
NSString *ACSToken = [FBSDKTypeUtility dictionary:applinkData objectForKey:ACS_TOKEN_KEY ofType:NSString.class];
|
||||
NSString *ACSSharedSecret = [FBSDKTypeUtility dictionary:applinkData objectForKey:ACS_SHARED_SECRET_KEY ofType:NSString.class];
|
||||
NSString *ACSConfigID = [FBSDKTypeUtility dictionary:applinkData objectForKey:CONFIG_ID_KEY ofType:NSString.class];
|
||||
NSString *businessID = [FBSDKTypeUtility dictionary:applinkData objectForKey:BUSINESS_ID_KEY ofType:NSString.class];
|
||||
NSNumber *isTestMode = [FBSDKTypeUtility dictionary:applinkData objectForKey:TEST_DEEPLINK_KEY ofType:NSNumber.class] ?: @NO;
|
||||
NSNumber *hasSKAN = [FBSDKTypeUtility dictionary:applinkData objectForKey:HAS_SKAN_KEY ofType:NSNumber.class] ?: @NO;
|
||||
if (campaignID == nil || ACSToken == nil) {
|
||||
return nil;
|
||||
}
|
||||
return [[FBAEMInvocation alloc] initWithCampaignID:campaignID
|
||||
ACSToken:ACSToken
|
||||
ACSSharedSecret:ACSSharedSecret
|
||||
ACSConfigID:ACSConfigID
|
||||
businessID:businessID
|
||||
isTestMode:isTestMode.boolValue
|
||||
hasSKAN:hasSKAN.boolValue];
|
||||
} @catch (NSException *exception) {
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
|
||||
- (nullable instancetype)initWithCampaignID:(NSString *)campaignID
|
||||
ACSToken:(NSString *)ACSToken
|
||||
ACSSharedSecret:(nullable NSString *)ACSSharedSecret
|
||||
ACSConfigID:(nullable NSString *)ACSConfigID
|
||||
businessID:(nullable NSString *)businessID
|
||||
isTestMode:(BOOL)isTestMode
|
||||
hasSKAN:(BOOL)hasSKAN
|
||||
{
|
||||
return [self initWithCampaignID:campaignID
|
||||
ACSToken:ACSToken
|
||||
ACSSharedSecret:ACSSharedSecret
|
||||
ACSConfigID:ACSConfigID
|
||||
businessID:businessID
|
||||
timestamp:nil
|
||||
configMode:@"DEFAULT"
|
||||
configID:-1
|
||||
recordedEvents:nil
|
||||
recordedValues:nil
|
||||
conversionValue:-1
|
||||
priority:-1
|
||||
conversionTimestamp:nil
|
||||
isAggregated:YES
|
||||
isTestMode:isTestMode
|
||||
hasSKAN:hasSKAN];
|
||||
}
|
||||
|
||||
- (nullable instancetype)initWithCampaignID:(NSString *)campaignID
|
||||
ACSToken:(NSString *)ACSToken
|
||||
ACSSharedSecret:(nullable NSString *)ACSSharedSecret
|
||||
ACSConfigID:(nullable NSString *)ACSConfigID
|
||||
businessID:(nullable NSString *)businessID
|
||||
timestamp:(nullable NSDate *)timestamp
|
||||
configMode:(NSString *)configMode
|
||||
configID:(NSInteger)configID
|
||||
recordedEvents:(nullable NSMutableSet<NSString *> *)recordedEvents
|
||||
recordedValues:(nullable NSMutableDictionary<NSString *, NSMutableDictionary *> *)recordedValues
|
||||
conversionValue:(NSInteger)conversionValue
|
||||
priority:(NSInteger)priority
|
||||
conversionTimestamp:(nullable NSDate *)conversionTimestamp
|
||||
isAggregated:(BOOL)isAggregated
|
||||
isTestMode:(BOOL)isTestMode
|
||||
hasSKAN:(BOOL)hasSKAN
|
||||
{
|
||||
if ((self = [super init])) {
|
||||
_campaignID = campaignID;
|
||||
_ACSToken = ACSToken;
|
||||
_ACSSharedSecret = ACSSharedSecret;
|
||||
_ACSConfigID = ACSConfigID;
|
||||
_businessID = businessID;
|
||||
if ([timestamp isKindOfClass:NSDate.class]) {
|
||||
_timestamp = timestamp;
|
||||
} else {
|
||||
_timestamp = [NSDate date];
|
||||
}
|
||||
_configMode = configMode;
|
||||
_configID = configID;
|
||||
if ([recordedEvents isKindOfClass:NSMutableSet.class]) {
|
||||
_recordedEvents = recordedEvents;
|
||||
} else {
|
||||
_recordedEvents = [NSMutableSet new];
|
||||
}
|
||||
if ([recordedValues isKindOfClass:NSMutableDictionary.class]) {
|
||||
_recordedValues = recordedValues;
|
||||
} else {
|
||||
_recordedValues = [NSMutableDictionary new];
|
||||
}
|
||||
_conversionValue = conversionValue;
|
||||
_priority = priority;
|
||||
_conversionTimestamp = conversionTimestamp;
|
||||
_isAggregated = isAggregated;
|
||||
_isTestMode = isTestMode;
|
||||
_hasSKAN = hasSKAN;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (BOOL)attributeEvent:(NSString *)event
|
||||
currency:(nullable NSString *)currency
|
||||
value:(nullable NSNumber *)value
|
||||
parameters:(nullable NSDictionary *)parameters
|
||||
configs:(nullable NSDictionary<NSString *, NSArray<FBAEMConfiguration *> *> *)configs
|
||||
{
|
||||
FBAEMConfiguration *config = [self _findConfig:configs];
|
||||
if ([self _isOutOfWindowWithConfig:config] || ![config.eventSet containsObject:event]) {
|
||||
return NO;
|
||||
}
|
||||
// Check advertiser rule matching
|
||||
if (config.matchingRule && ![config.matchingRule isMatchedEventParameters:[self processedParameters:parameters]]) {
|
||||
return NO;
|
||||
}
|
||||
BOOL isAttributed = NO;
|
||||
if (![_recordedEvents containsObject:event]) {
|
||||
[_recordedEvents addObject:event];
|
||||
isAttributed = YES;
|
||||
}
|
||||
// Change currency to default currency if currency is not found in currencySet
|
||||
NSString *valueCurrency = [currency uppercaseString];
|
||||
if (![config.currencySet containsObject:valueCurrency]) {
|
||||
valueCurrency = config.defaultCurrency;
|
||||
}
|
||||
if (value != nil) {
|
||||
NSMutableDictionary *mapping = [[FBSDKTypeUtility dictionary:_recordedValues objectForKey:event ofType:NSDictionary.class] mutableCopy] ?: [NSMutableDictionary new];
|
||||
NSNumber *valueInMapping = [FBSDKTypeUtility dictionary:mapping objectForKey:valueCurrency ofType:NSNumber.class] ?: [NSNumber numberWithDouble:0];
|
||||
// Overwrite values when the incoming event's value is greater than the cached one
|
||||
if (value.doubleValue > valueInMapping.doubleValue) {
|
||||
[FBSDKTypeUtility dictionary:mapping setObject:[NSNumber numberWithDouble:value.doubleValue] forKey:valueCurrency];
|
||||
[FBSDKTypeUtility dictionary:_recordedValues setObject:mapping forKey:event];
|
||||
isAttributed = YES;
|
||||
}
|
||||
}
|
||||
return isAttributed;
|
||||
}
|
||||
|
||||
- (BOOL)updateConversionValueWithConfigs:(nullable NSDictionary<NSString *, NSArray<FBAEMConfiguration *> *> *)configs
|
||||
{
|
||||
FBAEMConfiguration *config = [self _findConfig:configs];
|
||||
if (!config) {
|
||||
return NO;
|
||||
}
|
||||
// Update conversion value if a rule is matched
|
||||
for (FBAEMRule *rule in config.conversionValueRules) {
|
||||
if (rule.priority <= _priority) {
|
||||
break;
|
||||
}
|
||||
if ([rule isMatchedWithRecordedEvents:_recordedEvents recordedValues:_recordedValues]) {
|
||||
_conversionValue = rule.conversionValue;
|
||||
_priority = rule.priority;
|
||||
_conversionTimestamp = [NSDate date];
|
||||
_isAggregated = NO;
|
||||
return YES;
|
||||
}
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (BOOL)isOutOfWindowWithConfigs:(nullable NSDictionary<NSString *, NSArray<FBAEMConfiguration *> *> *)configs
|
||||
{
|
||||
FBAEMConfiguration *config = [self _findConfig:configs];
|
||||
return [self _isOutOfWindowWithConfig:config];
|
||||
}
|
||||
|
||||
- (nullable NSString *)getHMAC:(NSInteger)delay
|
||||
{
|
||||
if (!_ACSSharedSecret || !_ACSConfigID) {
|
||||
return nil;
|
||||
}
|
||||
@try {
|
||||
NSData *secretData = [self decodeBase64UrlSafeString:_ACSSharedSecret];
|
||||
if (!secretData) {
|
||||
return nil;
|
||||
}
|
||||
NSMutableData *hmac = [NSMutableData dataWithLength:CC_SHA512_DIGEST_LENGTH];
|
||||
NSString *text = [NSString stringWithFormat:@"%@|%@|%@|%@", _campaignID, @(_conversionValue), @(delay), @"server"];
|
||||
NSData *clearTextData = [text dataUsingEncoding:NSUTF8StringEncoding];
|
||||
CCHmac(kCCHmacAlgSHA512, [secretData bytes], [secretData length], [clearTextData bytes], [clearTextData length], hmac.mutableBytes);
|
||||
NSString *base64UrlSafeString = [hmac base64EncodedStringWithOptions:0];
|
||||
base64UrlSafeString = [base64UrlSafeString stringByReplacingOccurrencesOfString:@"/"
|
||||
withString:@"_"];
|
||||
base64UrlSafeString = [base64UrlSafeString stringByReplacingOccurrencesOfString:@"+"
|
||||
withString:@"-"];
|
||||
base64UrlSafeString = [base64UrlSafeString stringByReplacingOccurrencesOfString:@"="
|
||||
withString:@""];
|
||||
return base64UrlSafeString;
|
||||
} @catch (NSException *exception) {
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
|
||||
- (nullable NSData *)decodeBase64UrlSafeString:(NSString *)base64UrlSafeString
|
||||
{
|
||||
if (!base64UrlSafeString.length) {
|
||||
return nil;
|
||||
}
|
||||
NSString *base64String = [base64UrlSafeString stringByReplacingOccurrencesOfString:@"-" withString:@"+"];
|
||||
base64String = [base64String stringByReplacingOccurrencesOfString:@"_" withString:@"/"];
|
||||
base64String = [base64String stringByReplacingOccurrencesOfString:@"-" withString:@"+"];
|
||||
NSString *padding = [@"" stringByPaddingToLength:(4 - base64String.length % 4) withString:@"=" startingAtIndex:0];
|
||||
base64String = [base64String stringByAppendingString:padding];
|
||||
NSData *decodedData = [[NSData alloc] initWithBase64EncodedString:base64String options:0];
|
||||
return decodedData;
|
||||
}
|
||||
|
||||
- (nullable NSDictionary<NSString *, id> *)processedParameters:(nullable NSDictionary<NSString *, id> *)parameters
|
||||
{
|
||||
if (!parameters) {
|
||||
return parameters;
|
||||
}
|
||||
@try {
|
||||
NSMutableDictionary<NSString *, id> *result = [NSMutableDictionary dictionaryWithDictionary:parameters];
|
||||
NSString *content = [FBSDKTypeUtility dictionary:result objectForKey:FB_CONTENT ofType:NSString.class];
|
||||
if (content) {
|
||||
[FBSDKTypeUtility dictionary:result
|
||||
setObject:[FBSDKTypeUtility JSONObjectWithData:[content dataUsingEncoding:NSUTF8StringEncoding]
|
||||
options:0
|
||||
error:nil]
|
||||
forKey:FB_CONTENT];
|
||||
}
|
||||
return [result copy];
|
||||
} @catch (NSException *exception) {
|
||||
return parameters;
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)_isOutOfWindowWithConfig:(nullable FBAEMConfiguration *)config
|
||||
{
|
||||
if (!config) {
|
||||
return true;
|
||||
}
|
||||
BOOL isCutoff = [[NSDate date] timeIntervalSinceDate:_timestamp] > config.cutoffTime * SEC_IN_DAY;
|
||||
BOOL isOverLastConversionWindow = _conversionTimestamp && [[NSDate date] timeIntervalSinceDate:_conversionTimestamp] > SEC_IN_DAY;
|
||||
return isCutoff || isOverLastConversionWindow;
|
||||
}
|
||||
|
||||
- (nullable FBAEMConfiguration *)_findConfig:(nullable NSDictionary<NSString *, NSArray<FBAEMConfiguration *> *> *)configs
|
||||
{
|
||||
NSString *configMode = _businessID ? FBAEMInvocationConfigBrandMode : FBAEMInvocationConfigDefaultMode;
|
||||
NSArray<FBAEMConfiguration *> *configList = [FBSDKTypeUtility dictionary:configs objectForKey:configMode ofType:NSArray.class];
|
||||
if (0 == configList.count) {
|
||||
return nil;
|
||||
}
|
||||
if (_configID > 0) {
|
||||
for (FBAEMConfiguration *config in configList) {
|
||||
if ([config isSameValidFrom:_configID businessID:_businessID]) {
|
||||
return config;
|
||||
}
|
||||
}
|
||||
return nil;
|
||||
} else {
|
||||
FBAEMConfiguration *config = nil;
|
||||
for (FBAEMConfiguration *c in [configList reverseObjectEnumerator]) {
|
||||
if (c.validFrom <= _timestamp.timeIntervalSince1970 && [c isSameBusinessID:_businessID]) {
|
||||
config = c;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!config) {
|
||||
return nil;
|
||||
}
|
||||
[self _setConfig:config];
|
||||
return config;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)_setConfig:(FBAEMConfiguration *)config
|
||||
{
|
||||
_configID = config.validFrom;
|
||||
_configMode = config.configMode;
|
||||
}
|
||||
|
||||
#pragma mark - NSCoding
|
||||
|
||||
+ (BOOL)supportsSecureCoding
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (instancetype)initWithCoder:(NSCoder *)decoder
|
||||
{
|
||||
NSString *campaignID = [decoder decodeObjectOfClass:NSString.class forKey:CAMPAIGN_ID_KEY];
|
||||
NSString *ACSToken = [decoder decodeObjectOfClass:NSString.class forKey:ACS_TOKEN_KEY];
|
||||
NSString *ACSSharedSecret = [decoder decodeObjectOfClass:NSString.class forKey:ACS_SHARED_SECRET_KEY];
|
||||
NSString *ACSConfigID = [decoder decodeObjectOfClass:NSString.class forKey:ACS_CONFIG_ID_KEY];
|
||||
NSString *businessID = [decoder decodeObjectOfClass:NSString.class forKey:BUSINESS_ID_KEY];
|
||||
NSDate *timestamp = [decoder decodeObjectOfClass:NSDate.class forKey:TIMESTAMP_KEY];
|
||||
NSString *configMode = [decoder decodeObjectOfClass:NSString.class forKey:CONFIG_MODE_KEY];
|
||||
NSInteger configID = [decoder decodeIntegerForKey:CONFIG_ID_KEY];
|
||||
NSMutableSet<NSString *> *recordedEvents = [decoder decodeObjectOfClass:NSMutableSet.class forKey:RECORDED_EVENTS_KEY];
|
||||
NSMutableDictionary<NSString *, NSMutableDictionary *> *recordedValues = [decoder decodeObjectOfClass:NSMutableDictionary.class forKey:RECORDED_VALUES_KEY];
|
||||
NSInteger conversionValue = [decoder decodeIntegerForKey:CONVERSION_VALUE_KEY];
|
||||
NSInteger priority = [decoder decodeIntegerForKey:PRIORITY_KEY];
|
||||
NSDate *conversionTimestamp = [decoder decodeObjectOfClass:NSDate.class forKey:CONVERSION_TIMESTAMP_KEY];
|
||||
BOOL isAggregated = [decoder decodeBoolForKey:IS_AGGREGATED_KEY];
|
||||
BOOL hasSKAN = [decoder decodeBoolForKey:HAS_SKAN_KEY];
|
||||
return [self initWithCampaignID:campaignID
|
||||
ACSToken:ACSToken
|
||||
ACSSharedSecret:ACSSharedSecret
|
||||
ACSConfigID:ACSConfigID
|
||||
businessID:businessID
|
||||
timestamp:timestamp
|
||||
configMode:configMode
|
||||
configID:configID
|
||||
recordedEvents:recordedEvents
|
||||
recordedValues:recordedValues
|
||||
conversionValue:conversionValue
|
||||
priority:priority
|
||||
conversionTimestamp:conversionTimestamp
|
||||
isAggregated:isAggregated
|
||||
isTestMode:NO
|
||||
hasSKAN:hasSKAN];
|
||||
}
|
||||
|
||||
- (void)encodeWithCoder:(NSCoder *)encoder
|
||||
{
|
||||
[encoder encodeObject:_campaignID forKey:CAMPAIGN_ID_KEY];
|
||||
[encoder encodeObject:_ACSToken forKey:ACS_TOKEN_KEY];
|
||||
[encoder encodeObject:_ACSSharedSecret forKey:ACS_SHARED_SECRET_KEY];
|
||||
[encoder encodeObject:_ACSConfigID forKey:ACS_CONFIG_ID_KEY];
|
||||
[encoder encodeObject:_businessID forKey:BUSINESS_ID_KEY];
|
||||
[encoder encodeObject:_timestamp forKey:TIMESTAMP_KEY];
|
||||
[encoder encodeObject:_configMode forKey:CONFIG_MODE_KEY];
|
||||
[encoder encodeInteger:_configID forKey:CONFIG_ID_KEY];
|
||||
[encoder encodeObject:_recordedEvents forKey:RECORDED_EVENTS_KEY];
|
||||
[encoder encodeObject:_recordedValues forKey:RECORDED_VALUES_KEY];
|
||||
[encoder encodeInteger:_conversionValue forKey:CONVERSION_VALUE_KEY];
|
||||
[encoder encodeInteger:_priority forKey:PRIORITY_KEY];
|
||||
[encoder encodeObject:_conversionTimestamp forKey:CONVERSION_TIMESTAMP_KEY];
|
||||
[encoder encodeBool:_isAggregated forKey:IS_AGGREGATED_KEY];
|
||||
[encoder encodeBool:_hasSKAN forKey:HAS_SKAN_KEY];
|
||||
}
|
||||
|
||||
#pragma mark - NSCopying
|
||||
|
||||
- (instancetype)copyWithZone:(NSZone *)zone
|
||||
{
|
||||
return self;
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
#if FBTEST
|
||||
|
||||
- (void)setRecordedEvents:(NSMutableSet<NSString *> *)recordedEvents
|
||||
{
|
||||
_recordedEvents = recordedEvents;
|
||||
}
|
||||
|
||||
- (void)setRecordedValues:(NSMutableDictionary<NSString *, NSMutableDictionary *> *)recordedValues
|
||||
{
|
||||
_recordedValues = recordedValues;
|
||||
}
|
||||
|
||||
- (void)setPriority:(NSInteger)priority
|
||||
{
|
||||
_priority = priority;
|
||||
}
|
||||
|
||||
- (void)setConfigID:(NSInteger)configID
|
||||
{
|
||||
_configID = configID;
|
||||
}
|
||||
|
||||
- (void)setBusinessID:(NSString *_Nullable)businessID
|
||||
{
|
||||
_businessID = businessID;
|
||||
}
|
||||
|
||||
- (void)setConversionTimestamp:(NSDate *_Nonnull)conversionTimestamp
|
||||
{
|
||||
_conversionTimestamp = conversionTimestamp;
|
||||
}
|
||||
|
||||
- (void)setConversionValue:(NSInteger)conversionValue
|
||||
{
|
||||
_conversionValue = conversionValue;
|
||||
}
|
||||
|
||||
- (void)setCampaignID:(NSString *_Nonnull)campaignID
|
||||
{
|
||||
_campaignID = campaignID;
|
||||
}
|
||||
|
||||
- (void)setACSSharedSecret:(NSString *_Nullable)ACSSharedSecret
|
||||
{
|
||||
_ACSSharedSecret = ACSSharedSecret;
|
||||
}
|
||||
|
||||
- (void)setACSConfigID:(NSString *_Nullable)ACSConfigID
|
||||
{
|
||||
_ACSConfigID = ACSConfigID;
|
||||
}
|
||||
|
||||
- (void)reset
|
||||
{
|
||||
_timestamp = [NSDate date];
|
||||
_configMode = @"DEFAULT";
|
||||
_configID = -1;
|
||||
_businessID = nil;
|
||||
_recordedEvents = [NSMutableSet new];
|
||||
_recordedValues = [NSMutableDictionary new];
|
||||
_conversionValue = -1;
|
||||
_priority = -1;
|
||||
_conversionTimestamp = [NSDate date];
|
||||
_isAggregated = YES;
|
||||
_hasSKAN = NO;
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@end
|
||||
|
||||
#endif
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
// 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.
|
||||
|
||||
#define FBAEMKit_VERSION_STRING @"11.2.1"
|
||||
#define FBSDK_DEFAULT_GRAPH_API_VERSION @"v11.0"
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
// Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
|
||||
//
|
||||
// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,
|
||||
// copy, modify, and distribute this software in source code or binary form for use
|
||||
// in connection with the web services and APIs provided by Facebook.
|
||||
//
|
||||
// As with any software that integrates with the Facebook platform, your use of
|
||||
// this software is subject to the Facebook Developer Principles and Policies
|
||||
// [http://developers.facebook.com/policy/]. This copyright notice shall be
|
||||
// included in all copies or substantial portions of the software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#import "TargetConditionals.h"
|
||||
|
||||
#if !TARGET_OS_TV
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "FBAEMNetworking.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
NS_SWIFT_NAME(AEMNetworker)
|
||||
@interface FBAEMNetworker : NSObject <FBAEMNetworking, NSURLSessionDataDelegate>
|
||||
|
||||
- (void)startGraphRequestWithGraphPath:(NSString *)graphPath
|
||||
parameters:(NSDictionary *)parameters
|
||||
tokenString:(nullable NSString *)tokenString
|
||||
HTTPMethod:(nullable NSString *)method
|
||||
completion:(FBGraphRequestCompletion)completion;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
#endif
|
||||
+156
@@ -0,0 +1,156 @@
|
||||
// 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 "TargetConditionals.h"
|
||||
|
||||
#if !TARGET_OS_TV
|
||||
|
||||
#import "FBAEMNetworker.h"
|
||||
|
||||
#import "FBAEMKitVersions.h"
|
||||
#import "FBAEMRequestBody.h"
|
||||
#import "FBCoreKitBasicsImportForAEMKit.h"
|
||||
|
||||
#define kNewline @"\r\n"
|
||||
|
||||
static NSString *const kSDK = @"ios";
|
||||
static NSString *const kUserAgentBase = @"FBiOSAEM";
|
||||
|
||||
@implementation FBAEMNetworker
|
||||
|
||||
static NSString *const FB_GRAPH_API_ENDPOINT = @"https://graph.facebook.com/v11.0/";
|
||||
static NSString *const FB_GRAPH_API_CONTENT_TYPE = @"application/json";
|
||||
NSErrorDomain const FBAEMErrorDomain = @"com.facebook.aemkit";
|
||||
|
||||
- (void)startGraphRequestWithGraphPath:(NSString *)graphPath
|
||||
parameters:(NSDictionary *)parameters
|
||||
tokenString:(nullable NSString *)tokenString
|
||||
HTTPMethod:(nullable NSString *)method
|
||||
completion:(FBGraphRequestCompletion)completion
|
||||
{
|
||||
NSURL *url = [NSURL URLWithString:[FB_GRAPH_API_ENDPOINT stringByAppendingString:graphPath]];
|
||||
|
||||
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:60.0];
|
||||
|
||||
[request setHTTPMethod:method];
|
||||
[request setValue:[self userAgent] forHTTPHeaderField:@"User-Agent"];
|
||||
[request setValue:FB_GRAPH_API_CONTENT_TYPE forHTTPHeaderField:@"Content-Type"];
|
||||
[request setHTTPShouldHandleCookies:NO];
|
||||
|
||||
// add parameters to body
|
||||
FBAEMRequestBody *body = [FBAEMRequestBody new];
|
||||
|
||||
NSMutableDictionary<NSString *, id> *params = [NSMutableDictionary dictionaryWithDictionary:parameters];
|
||||
[FBSDKTypeUtility dictionary:params setObject:@"json" forKey:@"format"];
|
||||
[FBSDKTypeUtility dictionary:params setObject:kSDK forKey:@"sdk"];
|
||||
[FBSDKTypeUtility dictionary:params setObject:@"false" forKey:@"include_headers"];
|
||||
|
||||
[self appendAttachments:params toBody:body addFormData:[method isEqual:@"POST"]];
|
||||
|
||||
if ([request.HTTPMethod isEqualToString:@"POST"]) {
|
||||
request.HTTPBody = body.compressedData;
|
||||
[request setValue:@"gzip" forHTTPHeaderField:@"Content-Encoding"];
|
||||
} else {
|
||||
request.HTTPBody = body.data;
|
||||
}
|
||||
|
||||
FBSDKURLSession *session = [[FBSDKURLSession alloc] initWithDelegate:self delegateQueue:[NSOperationQueue currentQueue]];
|
||||
|
||||
[session executeURLRequest:request completionHandler:^(NSData *responseData, NSURLResponse *response, NSError *error) {
|
||||
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
|
||||
NSDictionary *result = [self parseJSONResponse:responseData error:&error statusCode:httpResponse.statusCode];
|
||||
completion(result, error);
|
||||
}];
|
||||
}
|
||||
|
||||
- (NSDictionary *)parseJSONResponse:(NSData *)data
|
||||
error:(NSError **)error
|
||||
statusCode:(NSInteger)statusCode
|
||||
{
|
||||
NSString *responseUTF8 = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
|
||||
id response = [self parseJSONOrOtherwise:responseUTF8 error:error];
|
||||
NSDictionary *result;
|
||||
|
||||
if (responseUTF8 == nil) {
|
||||
NSString *base64Data = data.length != 0 ? [data base64EncodedStringWithOptions:0] : @"";
|
||||
if (base64Data != nil) {
|
||||
NSLog(@"fb_response_invalid_utf8");
|
||||
}
|
||||
}
|
||||
|
||||
if (!response) {
|
||||
if ((error != NULL) && (*error == nil)) {
|
||||
*error = [[NSError alloc] initWithDomain:FBAEMErrorDomain code:statusCode userInfo:nil];
|
||||
}
|
||||
} else if ([response isKindOfClass:[NSDictionary class]]) {
|
||||
result = response;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
- (id)parseJSONOrOtherwise:(NSString *)unsafeString
|
||||
error:(NSError **)error
|
||||
{
|
||||
id parsed = nil;
|
||||
NSString *const utf8 = FBSDK_CAST_TO_CLASS_OR_NIL(unsafeString, NSString);
|
||||
if (!(*error) && utf8) {
|
||||
parsed = [FBSDKBasicUtility objectForJSONString:utf8 error:error];
|
||||
}
|
||||
return parsed;
|
||||
}
|
||||
|
||||
- (void)appendAttachments:(NSDictionary *)attachments
|
||||
toBody:(FBAEMRequestBody *)body
|
||||
addFormData:(BOOL)addFormData
|
||||
{
|
||||
[FBSDKTypeUtility dictionary:attachments enumerateKeysAndObjectsUsingBlock:^(id key, id value, BOOL *stop) {
|
||||
value = [FBSDKBasicUtility convertRequestValue:value];
|
||||
if ([value isKindOfClass:[NSString class]]) {
|
||||
if (addFormData) {
|
||||
[body appendWithKey:key formValue:(NSString *)value];
|
||||
}
|
||||
} else {
|
||||
NSString *msg = [NSString stringWithFormat:@"Unsupported attachment:%@, skipping.", value];
|
||||
NSLog(@"%@", msg);
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
- (NSString *)userAgent
|
||||
{
|
||||
static NSString *agent = nil;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
agent = [NSString stringWithFormat:@"%@.%@", kUserAgentBase, FBAEMKit_VERSION_STRING];
|
||||
});
|
||||
if (@available(iOS 13.0, *)) {
|
||||
SEL selector = NSSelectorFromString(@"isMacCatalystApp");
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
|
||||
if (selector && [NSProcessInfo.processInfo respondsToSelector:selector] && [NSProcessInfo.processInfo performSelector:selector]) {
|
||||
#pragma clang diagnostic pop
|
||||
return [NSString stringWithFormat:@"%@/%@", agent, @"macOS"];
|
||||
}
|
||||
}
|
||||
return agent;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#endif
|
||||
+674
@@ -0,0 +1,674 @@
|
||||
// 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 "TargetConditionals.h"
|
||||
|
||||
#if !TARGET_OS_TV
|
||||
|
||||
#import "FBAEMReporter.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#import "FBAEMAdvertiserRuleFactory.h"
|
||||
#import "FBAEMConfiguration.h"
|
||||
#import "FBAEMInvocation.h"
|
||||
#import "FBAEMNetworker.h"
|
||||
#import "FBCoreKitBasicsImportForAEMKit.h"
|
||||
|
||||
#define FB_AEM_CONFIG_TIME_OUT 86400
|
||||
|
||||
typedef void (^FBAEMReporterBlock)(NSError *);
|
||||
|
||||
static NSString *const BUSINESS_ID_KEY = @"advertiser_id";
|
||||
static NSString *const BUSINESS_IDS_KEY = @"advertiser_ids";
|
||||
static NSString *const AL_APPLINK_DATA_KEY = @"al_applink_data";
|
||||
static NSString *const CAMPAIGN_ID_KEY = @"campaign_id";
|
||||
static NSString *const CONVERSION_DATA_KEY = @"conversion_data";
|
||||
static NSString *const CONSUMPTION_HOUR_KEY = @"consumption_hour";
|
||||
static NSString *const TOKEN_KEY = @"token";
|
||||
static NSString *const HMAC_KEY = @"hmac";
|
||||
static NSString *const CONFIG_ID_KEY = @"config_id";
|
||||
static NSString *const DELAY_FLOW_KEY = @"delay_flow";
|
||||
|
||||
static NSString *const FBAEMConfigurationKey = @"com.facebook.sdk:FBSDKAEMConfiguration";
|
||||
static NSString *const FBAEMReporterKey = @"com.facebook.sdk:FBSDKAEMReporter";
|
||||
static NSString *const FBAEMReporterFileName = @"FBSDKAEMReportData.report";
|
||||
static NSString *const FBAEMConfigFileName = @"FBSDKAEMReportData.config";
|
||||
static NSString *const FBAEMHTTPMethodGET = @"GET";
|
||||
static NSString *const FBAEMHTTPMethodPOST = @"POST";
|
||||
|
||||
static BOOL g_isAEMReportEnabled = NO;
|
||||
static BOOL g_isLoadingConfiguration = NO;
|
||||
static dispatch_queue_t g_serialQueue;
|
||||
static NSString *g_reportFile;
|
||||
static NSString *g_configFile;
|
||||
static NSMutableDictionary<NSString *, NSMutableArray<FBAEMConfiguration *> *> *g_configs;
|
||||
static NSMutableArray<FBAEMInvocation *> *g_invocations;
|
||||
static NSDate *g_configRefreshTimestamp;
|
||||
static NSMutableArray<FBAEMReporterBlock> *g_completionBlocks;
|
||||
static _Nullable id<FBAEMNetworking> _networker = nil;
|
||||
static _Nullable id<FBSKAdNetworkReporting> _reporter = nil;
|
||||
static NSString *_appId;
|
||||
|
||||
@implementation FBAEMReporter
|
||||
|
||||
static char *const dispatchQueueLabel = "com.facebook.appevents.AEM.FBAEMReporter";
|
||||
|
||||
+ (void)configureWithNetworker:(nullable id<FBAEMNetworking>)networker
|
||||
appID:(NSString *)appID
|
||||
{
|
||||
[self configureWithNetworker:networker appID:appID reporter:nil];
|
||||
}
|
||||
|
||||
+ (void)configureWithNetworker:(nullable id<FBAEMNetworking>)networker
|
||||
appID:(NSString *)appID
|
||||
reporter:(nullable id<FBSKAdNetworkReporting>)reporter
|
||||
{
|
||||
if (self == [FBAEMReporter class]) {
|
||||
_networker = networker;
|
||||
_appId = appID;
|
||||
_reporter = reporter;
|
||||
}
|
||||
}
|
||||
|
||||
+ (id<FBAEMNetworking>)networker
|
||||
{
|
||||
return _networker;
|
||||
}
|
||||
|
||||
+ (id<FBSKAdNetworkReporting>)reporter
|
||||
{
|
||||
return _reporter;
|
||||
}
|
||||
|
||||
+ (void)enable
|
||||
{
|
||||
if (@available(iOS 14.0, *)) {
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
[FBAEMConfiguration configureWithRuleProvider:[FBAEMAdvertiserRuleFactory new]];
|
||||
g_reportFile = [FBSDKBasicUtility persistenceFilePath:FBAEMReporterFileName];
|
||||
g_configFile = [FBSDKBasicUtility persistenceFilePath:FBAEMConfigFileName];
|
||||
g_completionBlocks = [NSMutableArray new];
|
||||
if (!g_serialQueue) {
|
||||
g_serialQueue = dispatch_queue_create(dispatchQueueLabel, DISPATCH_QUEUE_SERIAL);
|
||||
}
|
||||
[self dispatchOnQueue:g_serialQueue block:^() {
|
||||
g_configs = [self _loadConfigs];
|
||||
g_invocations = [self _loadReportData];
|
||||
}];
|
||||
[self _loadConfigurationWithBlock:^(NSError *error) {
|
||||
if (error) {
|
||||
return;
|
||||
}
|
||||
[self _sendAggregationRequest];
|
||||
[self _clearCache];
|
||||
}];
|
||||
// If developers forget to call configureWithNetworker:appID:
|
||||
// or pass nil for networker,
|
||||
// we use default networker in FBAEMKit
|
||||
if (!_networker) {
|
||||
_networker = [FBAEMNetworker new];
|
||||
}
|
||||
// If developers forget to call configureWithNetworker:appID:,
|
||||
// we throw warning here
|
||||
if (!_appId) {
|
||||
NSLog(@"App ID is not set up correctly, please call configureWithNetworker:appID: and pass correct FB app ID");
|
||||
return;
|
||||
}
|
||||
g_isAEMReportEnabled = YES;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
+ (void)handleURL:(NSURL *)url
|
||||
{
|
||||
if (!g_isAEMReportEnabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
FBAEMInvocation *invocation = [self parseURL:url];
|
||||
if (!invocation) {
|
||||
return;
|
||||
}
|
||||
if (invocation.isTestMode) {
|
||||
[self _sendDebuggingRequest:invocation];
|
||||
return;
|
||||
}
|
||||
|
||||
[self _appendAndSaveInvocation:invocation];
|
||||
}
|
||||
|
||||
+ (nullable FBAEMInvocation *)parseURL:(NSURL *)url
|
||||
{
|
||||
if (!url) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
NSDictionary<NSString *, NSString *> *params = [FBSDKBasicUtility dictionaryWithQueryString:url.query];
|
||||
NSString *applinkDataString = params[AL_APPLINK_DATA_KEY];
|
||||
if (!applinkDataString) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
NSDictionary<id, id> *applinkData = [FBSDKTypeUtility dictionaryValue:[FBSDKBasicUtility objectForJSONString:applinkDataString error:NULL]];
|
||||
if (!applinkData) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
return [FBAEMInvocation invocationWithAppLinkData:applinkData];
|
||||
}
|
||||
|
||||
+ (void)recordAndUpdateEvent:(NSString *)event
|
||||
currency:(nullable NSString *)currency
|
||||
value:(nullable NSNumber *)value
|
||||
parameters:(nullable NSDictionary *)parameters
|
||||
{
|
||||
if (@available(iOS 14.0, *)) {
|
||||
if (!g_isAEMReportEnabled || 0 == event.length) {
|
||||
return;
|
||||
}
|
||||
[self _loadConfigurationWithBlock:^(NSError *error) {
|
||||
if (0 == g_configs.count || 0 == g_invocations.count) {
|
||||
return;
|
||||
}
|
||||
|
||||
FBAEMInvocation *attributedInvocation = [self _attributedInvocation:g_invocations Event:event currency:currency value:value parameters:parameters configs:g_configs];
|
||||
if (attributedInvocation) {
|
||||
if ([attributedInvocation updateConversionValueWithConfigs:g_configs]) {
|
||||
[self _sendAggregationRequest];
|
||||
}
|
||||
[self _saveReportData];
|
||||
}
|
||||
}];
|
||||
}
|
||||
}
|
||||
|
||||
+ (nullable FBAEMInvocation *)_attributedInvocation:(NSArray<FBAEMInvocation *> *)invocations
|
||||
Event:(NSString *)event
|
||||
currency:(nullable NSString *)currency
|
||||
value:(nullable NSNumber *)value
|
||||
parameters:(nullable NSDictionary *)parameters
|
||||
configs:(NSDictionary<NSString *, NSMutableArray<FBAEMConfiguration *> *> *)configs
|
||||
{
|
||||
BOOL isGeneralInvocationVisited = NO;
|
||||
FBAEMInvocation *attributedInvocation = nil;
|
||||
for (FBAEMInvocation *invocation in [invocations reverseObjectEnumerator]) {
|
||||
if ([self _isDoubleCounting:invocation event:event]) {
|
||||
break;
|
||||
}
|
||||
if (!invocation.businessID && isGeneralInvocationVisited) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ([invocation attributeEvent:event currency:currency value:value parameters:parameters configs:configs]) {
|
||||
attributedInvocation = invocation;
|
||||
break;
|
||||
}
|
||||
if (!invocation.businessID) {
|
||||
isGeneralInvocationVisited = YES;
|
||||
}
|
||||
}
|
||||
return attributedInvocation;
|
||||
}
|
||||
|
||||
+ (BOOL)_isDoubleCounting:(FBAEMInvocation *)invocation
|
||||
event:(NSString *)event
|
||||
{
|
||||
// We consider it as double counting if following conditions meet simultaneously
|
||||
// 1. The field hasSKAN is true
|
||||
// 2. The conversion happens before SKAdNetwork cutoff
|
||||
// 3. The event is also being reported by SKAdNetwork
|
||||
return invocation.hasSKAN
|
||||
&& ![_reporter shouldCutoff]
|
||||
&& [_reporter isReportingEvent:event];
|
||||
}
|
||||
|
||||
+ (void)_appendAndSaveInvocation:(FBAEMInvocation *)invocation
|
||||
{
|
||||
[self dispatchOnQueue:g_serialQueue block:^() {
|
||||
[FBSDKTypeUtility array:g_invocations addObject:invocation];
|
||||
[self _saveReportData];
|
||||
}];
|
||||
}
|
||||
|
||||
+ (void)_loadConfigurationWithBlock:(FBAEMReporterBlock)block
|
||||
{
|
||||
[self dispatchOnQueue:g_serialQueue block:^() {
|
||||
[FBSDKTypeUtility array:g_completionBlocks addObject:block];
|
||||
// Executes blocks if there is cache
|
||||
if (![self _shouldRefresh]) {
|
||||
for (FBAEMReporterBlock executionBlock in g_completionBlocks) {
|
||||
executionBlock(nil);
|
||||
}
|
||||
[g_completionBlocks removeAllObjects];
|
||||
return;
|
||||
}
|
||||
if (g_isLoadingConfiguration) {
|
||||
return;
|
||||
}
|
||||
g_isLoadingConfiguration = YES;
|
||||
|
||||
[self.networker startGraphRequestWithGraphPath:[NSString stringWithFormat:@"%@/aem_conversion_configs", _appId]
|
||||
parameters:[self _requestParameters]
|
||||
tokenString:nil
|
||||
HTTPMethod:FBAEMHTTPMethodGET
|
||||
completion:^(id _Nullable result, NSError *_Nullable error) {
|
||||
[self dispatchOnQueue:g_serialQueue block:^() {
|
||||
if (error) {
|
||||
for (FBAEMReporterBlock executionBlock in g_completionBlocks) {
|
||||
executionBlock(error);
|
||||
}
|
||||
[g_completionBlocks removeAllObjects];
|
||||
g_isLoadingConfiguration = NO;
|
||||
return;
|
||||
}
|
||||
NSDictionary<NSString *, id> *json = [FBSDKTypeUtility dictionaryValue:result];
|
||||
if (json) {
|
||||
g_configRefreshTimestamp = [NSDate date];
|
||||
[self _addConfigs:[FBSDKTypeUtility dictionary:json objectForKey:@"data" ofType:NSArray.class]];
|
||||
for (FBAEMReporterBlock executionBlock in g_completionBlocks) {
|
||||
executionBlock(nil);
|
||||
}
|
||||
[g_completionBlocks removeAllObjects];
|
||||
} else {
|
||||
NSLog(@"Received invalid AEM config");
|
||||
}
|
||||
g_isLoadingConfiguration = NO;
|
||||
}];
|
||||
}];
|
||||
}];
|
||||
}
|
||||
|
||||
+ (NSDictionary<NSString *, id> *)_requestParameters
|
||||
{
|
||||
NSMutableDictionary<NSString *, id> *params = [NSMutableDictionary new];
|
||||
// append business ids to the request params
|
||||
NSMutableArray<NSString *> *businessIDs = [NSMutableArray new];
|
||||
for (FBAEMInvocation *invocation in g_invocations) {
|
||||
[FBSDKTypeUtility array:businessIDs addObject:invocation.businessID];
|
||||
}
|
||||
NSString *businessIDsString = [FBSDKBasicUtility JSONStringForObject:businessIDs error:nil invalidObjectHandler:nil];
|
||||
[FBSDKTypeUtility dictionary:params setObject:businessIDsString forKey:BUSINESS_IDS_KEY];
|
||||
return [params copy];
|
||||
}
|
||||
|
||||
+ (BOOL)_isConfigRefreshTimestampValid
|
||||
{
|
||||
return g_configRefreshTimestamp && [[NSDate date] timeIntervalSinceDate:g_configRefreshTimestamp] < FB_AEM_CONFIG_TIME_OUT;
|
||||
}
|
||||
|
||||
+ (BOOL)_shouldRefresh
|
||||
{
|
||||
// Refresh if there exists invocation which has business ID
|
||||
for (FBAEMInvocation *invocation in g_invocations) {
|
||||
if (invocation.businessID) {
|
||||
return YES;
|
||||
}
|
||||
}
|
||||
// Refresh if timestamp is expired or cached config is empty
|
||||
return (![self _isConfigRefreshTimestampValid]) || (0 == g_configs.count);
|
||||
}
|
||||
|
||||
#pragma mark - Deeplink debugging methods
|
||||
|
||||
+ (void)_sendDebuggingRequest:(FBAEMInvocation *)invocation
|
||||
{
|
||||
NSMutableArray<NSDictionary *> *params = [NSMutableArray new];
|
||||
[FBSDKTypeUtility array:params addObject:[self _debuggingRequestParameters:invocation]];
|
||||
if (0 == params.count) {
|
||||
return;
|
||||
}
|
||||
@try {
|
||||
NSData *jsonData = [FBSDKTypeUtility dataWithJSONObject:params options:0 error:nil];
|
||||
if (jsonData) {
|
||||
NSString *reports = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
|
||||
|
||||
[self.networker startGraphRequestWithGraphPath:[NSString stringWithFormat:@"%@/aem_conversions", _appId]
|
||||
parameters:@{@"aem_conversions" : reports}
|
||||
tokenString:nil
|
||||
HTTPMethod:FBAEMHTTPMethodPOST
|
||||
completion:^(id _Nullable result, NSError *_Nullable error) {
|
||||
if (error) {
|
||||
NSLog(@"Fail to send AEM debugging request with error: %@", error);
|
||||
}
|
||||
}];
|
||||
}
|
||||
} @catch (NSException *exception) {
|
||||
NSLog(@"Fail to send AEM debugging request");
|
||||
}
|
||||
}
|
||||
|
||||
+ (NSDictionary<NSString *, id> *)_debuggingRequestParameters:(FBAEMInvocation *)invocation
|
||||
{
|
||||
NSMutableDictionary<NSString *, id> *conversionParams = [NSMutableDictionary new];
|
||||
[FBSDKTypeUtility dictionary:conversionParams setObject:invocation.campaignID forKey:CAMPAIGN_ID_KEY];
|
||||
[FBSDKTypeUtility dictionary:conversionParams setObject:@(0) forKey:CONVERSION_DATA_KEY];
|
||||
[FBSDKTypeUtility dictionary:conversionParams setObject:@(0) forKey:CONSUMPTION_HOUR_KEY];
|
||||
[FBSDKTypeUtility dictionary:conversionParams setObject:invocation.ACSToken forKey:TOKEN_KEY];
|
||||
[FBSDKTypeUtility dictionary:conversionParams setObject:@"server" forKey:DELAY_FLOW_KEY];
|
||||
|
||||
return [conversionParams copy];
|
||||
}
|
||||
|
||||
#pragma mark - Background methods
|
||||
|
||||
+ (NSMutableDictionary<NSString *, NSMutableArray<FBAEMConfiguration *> *> *)_loadConfigs
|
||||
{
|
||||
if (@available(iOS 11.0, *)) {
|
||||
NSData *cachedConfig = [NSData dataWithContentsOfFile:g_configFile options:NSDataReadingMappedIfSafe error:nil];
|
||||
if ([cachedConfig isKindOfClass:NSData.class]) {
|
||||
NSSet *classes = [NSSet setWithArray:@[
|
||||
NSMutableDictionary.class,
|
||||
NSMutableArray.class,
|
||||
FBAEMConfiguration.class,
|
||||
FBAEMRule.class,
|
||||
FBAEMEvent.class]];
|
||||
NSDictionary<NSString *, NSMutableArray<FBAEMConfiguration *> *> *cache = [FBSDKTypeUtility dictionaryValue:[NSKeyedUnarchiver unarchivedObjectOfClasses:classes fromData:cachedConfig error:nil]];
|
||||
if (cache) {
|
||||
return [cache mutableCopy];
|
||||
}
|
||||
}
|
||||
}
|
||||
return [NSMutableDictionary new];
|
||||
}
|
||||
|
||||
+ (void)_saveConfigs
|
||||
{
|
||||
if (!g_configs) {
|
||||
return;
|
||||
}
|
||||
if (@available(iOS 11.0, *)) {
|
||||
NSData *cache = [NSKeyedArchiver archivedDataWithRootObject:g_configs requiringSecureCoding:NO error:nil];
|
||||
if (cache && g_configFile) {
|
||||
[cache writeToFile:g_configFile atomically:YES];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+ (void)_addConfigs:(nullable NSArray<NSDictionary *> *)configs
|
||||
{
|
||||
if (0 == configs.count) {
|
||||
return;
|
||||
}
|
||||
for (NSDictionary *config in configs) {
|
||||
[self _addConfig:[[FBAEMConfiguration alloc] initWithJSON:config]];
|
||||
}
|
||||
[self _saveConfigs];
|
||||
}
|
||||
|
||||
+ (void)_addConfig:(nullable FBAEMConfiguration *)config
|
||||
{
|
||||
if (!config.configMode) {
|
||||
return;
|
||||
}
|
||||
NSMutableArray<FBAEMConfiguration *> *configs = [FBSDKTypeUtility dictionary:g_configs objectForKey:config.configMode ofType:NSMutableArray.class];
|
||||
// Remove the config in the array that has the same "validFrom" and "businessID" as the added config
|
||||
NSMutableArray<FBAEMConfiguration *> *res = [NSMutableArray new];
|
||||
for (FBAEMConfiguration *c in configs) {
|
||||
if ([config isSameValidFrom:c.validFrom businessID:c.businessID]) {
|
||||
continue;
|
||||
}
|
||||
[FBSDKTypeUtility array:res addObject:c];
|
||||
}
|
||||
[FBSDKTypeUtility array:res addObject:config];
|
||||
[FBSDKTypeUtility dictionary:g_configs setObject:res forKey:config.configMode];
|
||||
// Sort the configs via "validFrom"
|
||||
[res sortUsingComparator:^NSComparisonResult (FBAEMConfiguration *obj1, FBAEMConfiguration *obj2) {
|
||||
if (obj1.validFrom > obj2.validFrom) {
|
||||
return NSOrderedDescending;
|
||||
}
|
||||
if (obj1.validFrom < obj2.validFrom) {
|
||||
return NSOrderedAscending;
|
||||
}
|
||||
return NSOrderedSame;
|
||||
}];
|
||||
}
|
||||
|
||||
+ (NSMutableArray<FBAEMInvocation *> *)_loadReportData
|
||||
{
|
||||
if (@available(iOS 11.0, *)) {
|
||||
NSData *cachedReportData = [NSData dataWithContentsOfFile:g_reportFile options:NSDataReadingMappedIfSafe error:nil];
|
||||
if ([cachedReportData isKindOfClass:NSData.class]) {
|
||||
NSArray<FBAEMInvocation *> *cache = [FBSDKTypeUtility arrayValue:[NSKeyedUnarchiver unarchivedObjectOfClasses:[NSSet setWithArray:@[NSArray.class, FBAEMInvocation.class]] fromData:cachedReportData error:nil]];
|
||||
if (cache) {
|
||||
return [cache mutableCopy];
|
||||
}
|
||||
}
|
||||
}
|
||||
return [NSMutableArray new];
|
||||
}
|
||||
|
||||
+ (void)_saveReportData
|
||||
{
|
||||
if (@available(iOS 11.0, *)) {
|
||||
NSData *cache = [NSKeyedArchiver archivedDataWithRootObject:g_invocations requiringSecureCoding:NO error:nil];
|
||||
if (cache && g_reportFile) {
|
||||
[cache writeToFile:g_reportFile atomically:YES];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+ (void)_sendAggregationRequest
|
||||
{
|
||||
NSMutableArray<NSDictionary *> *params = [NSMutableArray new];
|
||||
NSMutableArray<FBAEMInvocation *> *aggregatedInvocations = [NSMutableArray new];
|
||||
for (FBAEMInvocation *invocation in g_invocations) {
|
||||
if (!invocation.isAggregated) {
|
||||
[FBSDKTypeUtility array:params addObject:[self _aggregationRequestParameters:invocation]];
|
||||
[FBSDKTypeUtility array:aggregatedInvocations addObject:invocation];
|
||||
}
|
||||
}
|
||||
if (0 == params.count) {
|
||||
return;
|
||||
}
|
||||
@try {
|
||||
NSData *jsonData = [FBSDKTypeUtility dataWithJSONObject:params options:0 error:nil];
|
||||
if (jsonData) {
|
||||
NSString *reports = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
|
||||
|
||||
[self.networker startGraphRequestWithGraphPath:[NSString stringWithFormat:@"%@/aem_conversions", _appId]
|
||||
parameters:@{@"aem_conversions" : reports}
|
||||
tokenString:nil
|
||||
HTTPMethod:FBAEMHTTPMethodPOST
|
||||
completion:^(id _Nullable result, NSError *_Nullable error) {
|
||||
if (error) {
|
||||
return;
|
||||
}
|
||||
|
||||
[self dispatchOnQueue:g_serialQueue block:^() {
|
||||
for (FBAEMInvocation *invocation in aggregatedInvocations) {
|
||||
invocation.isAggregated = YES;
|
||||
}
|
||||
[self _saveReportData];
|
||||
}];
|
||||
}];
|
||||
}
|
||||
} @catch (NSException *exception) {
|
||||
NSLog(@"Fail to send AEM reports");
|
||||
}
|
||||
}
|
||||
|
||||
+ (NSDictionary<NSString *, id> *)_aggregationRequestParameters:(FBAEMInvocation *)invocation
|
||||
{
|
||||
NSInteger delay = 24 + arc4random_uniform(24);
|
||||
NSMutableDictionary<NSString *, id> *conversionParams = [NSMutableDictionary new];
|
||||
[FBSDKTypeUtility dictionary:conversionParams setObject:invocation.campaignID forKey:CAMPAIGN_ID_KEY];
|
||||
[FBSDKTypeUtility dictionary:conversionParams setObject:@(invocation.conversionValue) forKey:CONVERSION_DATA_KEY];
|
||||
[FBSDKTypeUtility dictionary:conversionParams setObject:@(delay) forKey:CONSUMPTION_HOUR_KEY];
|
||||
[FBSDKTypeUtility dictionary:conversionParams setObject:invocation.ACSToken forKey:TOKEN_KEY];
|
||||
[FBSDKTypeUtility dictionary:conversionParams setObject:@"server" forKey:DELAY_FLOW_KEY];
|
||||
[FBSDKTypeUtility dictionary:conversionParams setObject:invocation.ACSConfigID forKey:CONFIG_ID_KEY];
|
||||
[FBSDKTypeUtility dictionary:conversionParams setObject:[invocation getHMAC:delay] forKey:HMAC_KEY];
|
||||
[FBSDKTypeUtility dictionary:conversionParams setObject:invocation.businessID forKey:BUSINESS_ID_KEY];
|
||||
|
||||
return [conversionParams copy];
|
||||
}
|
||||
|
||||
+ (void)dispatchOnQueue:(dispatch_queue_t)queue block:(dispatch_block_t)block
|
||||
{
|
||||
if (block != nil) {
|
||||
if (strcmp(dispatch_queue_get_label(queue), dispatchQueueLabel) == 0) {
|
||||
dispatch_async(queue, block);
|
||||
} else {
|
||||
block();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+ (void)_clearCache
|
||||
{
|
||||
// step 1: clear aggregated invocations that are outside attribution window
|
||||
[self _clearInvocations];
|
||||
// step 2: clear old configs that are not used anymore and keep the most recent config
|
||||
[self _clearConfigs];
|
||||
}
|
||||
|
||||
+ (void)_clearConfigs
|
||||
{
|
||||
BOOL shouldSaveCache = NO;
|
||||
if (g_configs.count > 0) {
|
||||
NSMutableDictionary<NSString *, NSMutableArray<FBAEMConfiguration *> *> *configs = [NSMutableDictionary new];
|
||||
for (NSString *key in g_configs) {
|
||||
NSMutableArray<FBAEMConfiguration *> *oldConfigurations = [FBSDKTypeUtility dictionary:g_configs objectForKey:key ofType:NSMutableArray.class];
|
||||
NSMutableArray<FBAEMConfiguration *> *newConfigurations = [NSMutableArray new];
|
||||
|
||||
// Removes the last of the old configurations and stores it so it can be
|
||||
// added to the array-to-save
|
||||
FBAEMConfiguration *lastConfiguration = oldConfigurations.lastObject;
|
||||
[oldConfigurations removeLastObject];
|
||||
|
||||
for (FBAEMConfiguration *oldConfiguration in oldConfigurations) {
|
||||
if (![self _isUsingConfig:oldConfiguration forInvocations:g_invocations]) {
|
||||
shouldSaveCache = YES;
|
||||
continue;
|
||||
}
|
||||
[FBSDKTypeUtility array:newConfigurations addObject:oldConfiguration];
|
||||
}
|
||||
|
||||
[FBSDKTypeUtility array:newConfigurations addObject:lastConfiguration];
|
||||
[FBSDKTypeUtility dictionary:configs setObject:newConfigurations forKey:key];
|
||||
}
|
||||
g_configs = configs;
|
||||
}
|
||||
if (shouldSaveCache) {
|
||||
[self _saveConfigs];
|
||||
}
|
||||
}
|
||||
|
||||
+ (void)_clearInvocations
|
||||
{
|
||||
BOOL isInvocationCacheUpdated = NO;
|
||||
if (g_invocations.count > 0) {
|
||||
NSMutableArray<FBAEMInvocation *> *res = [NSMutableArray new];
|
||||
for (FBAEMInvocation *invocation in g_invocations) {
|
||||
if ([invocation isOutOfWindowWithConfigs:g_configs] && invocation.isAggregated) {
|
||||
isInvocationCacheUpdated = YES;
|
||||
continue;
|
||||
}
|
||||
[FBSDKTypeUtility array:res addObject:invocation];
|
||||
}
|
||||
g_invocations = res;
|
||||
}
|
||||
if (isInvocationCacheUpdated) {
|
||||
[self _saveReportData];
|
||||
}
|
||||
}
|
||||
|
||||
+ (BOOL)_isUsingConfig:(FBAEMConfiguration *)config
|
||||
forInvocations:(NSArray<FBAEMInvocation *> *)invocations
|
||||
{
|
||||
for (FBAEMInvocation *invocation in invocations) {
|
||||
if ([config isSameValidFrom:invocation.configID businessID:invocation.businessID]) {
|
||||
return YES;
|
||||
}
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
#pragma mark - Testability
|
||||
|
||||
#if DEBUG
|
||||
#if FBTEST
|
||||
|
||||
+ (NSMutableDictionary<NSString *, NSMutableArray<FBAEMConfiguration *> *> *)configs
|
||||
{
|
||||
return g_configs;
|
||||
}
|
||||
|
||||
+ (void)setConfigs:(NSMutableDictionary<NSString *, NSMutableArray<FBAEMConfiguration *> *> *)configs
|
||||
{
|
||||
g_configs = configs;
|
||||
}
|
||||
|
||||
+ (void)setInvocations:(NSMutableArray<FBAEMInvocation *> *)invocations
|
||||
{
|
||||
g_invocations = invocations;
|
||||
}
|
||||
|
||||
+ (NSMutableArray<FBAEMInvocation *> *)invocations
|
||||
{
|
||||
return g_invocations;
|
||||
}
|
||||
|
||||
+ (void)setIsEnabled:(BOOL)enabled
|
||||
{
|
||||
g_isAEMReportEnabled = enabled;
|
||||
}
|
||||
|
||||
+ (BOOL)isEnabled
|
||||
{
|
||||
return g_isAEMReportEnabled;
|
||||
}
|
||||
|
||||
+ (void)setCompletionBlocks:(NSMutableArray<FBAEMReporterBlock> *)completionBlocks
|
||||
{
|
||||
g_completionBlocks = completionBlocks;
|
||||
}
|
||||
|
||||
+ (void)setQueue:(nullable dispatch_queue_t)queue
|
||||
{
|
||||
g_serialQueue = queue;
|
||||
}
|
||||
|
||||
+ (void)setTimestamp:(NSDate *)timestamp
|
||||
{
|
||||
g_configRefreshTimestamp = timestamp;
|
||||
}
|
||||
|
||||
+ (void)setIsLoadingConfiguration:(BOOL)loading
|
||||
{
|
||||
g_isLoadingConfiguration = loading;
|
||||
}
|
||||
|
||||
+ (NSString *)reportFilePath
|
||||
{
|
||||
return g_reportFile;
|
||||
}
|
||||
|
||||
+ (void)setReportFilePath:(NSString *)path
|
||||
{
|
||||
g_reportFile = path;
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@end
|
||||
|
||||
#endif
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
|
||||
// Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
|
||||
//
|
||||
// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,
|
||||
// copy, modify, and distribute this software in source code or binary form for use
|
||||
// in connection with the web services and APIs provided by Facebook.
|
||||
//
|
||||
// As with any software that integrates with the Facebook platform, your use of
|
||||
// this software is subject to the Facebook Developer Principles and Policies
|
||||
// [http://developers.facebook.com/policy/]. This copyright notice shall be
|
||||
// included in all copies or substantial portions of the software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#import "TargetConditionals.h"
|
||||
|
||||
#if !TARGET_OS_TV
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_SWIFT_NAME(RequestBody)
|
||||
@interface FBAEMRequestBody : NSObject
|
||||
|
||||
@property (nonatomic, retain, readonly) NSData *data;
|
||||
|
||||
- (void)appendWithKey:(NSString *)key
|
||||
formValue:(NSString *)value;
|
||||
|
||||
- (NSData *)compressedData;
|
||||
|
||||
@end
|
||||
|
||||
#endif
|
||||
+116
@@ -0,0 +1,116 @@
|
||||
// Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
|
||||
//
|
||||
// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,
|
||||
// copy, modify, and distribute this software in source code or binary form for use
|
||||
// in connection with the web services and APIs provided by Facebook.
|
||||
//
|
||||
// As with any software that integrates with the Facebook platform, your use of
|
||||
// this software is subject to the Facebook Developer Principles and Policies
|
||||
// [http://developers.facebook.com/policy/]. This copyright notice shall be
|
||||
// included in all copies or substantial portions of the software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#import "TargetConditionals.h"
|
||||
|
||||
#if !TARGET_OS_TV
|
||||
|
||||
#import "FBAEMRequestBody.h"
|
||||
|
||||
#import "FBCoreKitBasicsImportForAEMKit.h"
|
||||
|
||||
#define kNewline @"\r\n"
|
||||
|
||||
typedef void (^AEMCodeBlock)(void);
|
||||
|
||||
@implementation FBAEMRequestBody
|
||||
{
|
||||
NSMutableData *_data;
|
||||
NSMutableDictionary *_json;
|
||||
}
|
||||
|
||||
- (instancetype)init
|
||||
{
|
||||
if ((self = [super init])) {
|
||||
_data = [NSMutableData new];
|
||||
_json = [NSMutableDictionary dictionary];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)appendUTF8:(NSString *)utf8
|
||||
{
|
||||
if (!_data.length) {
|
||||
NSString *headerUTF8 = [NSString stringWithFormat:@"--%@", kNewline];
|
||||
NSData *headerData = [headerUTF8 dataUsingEncoding:NSUTF8StringEncoding];
|
||||
[_data appendData:headerData];
|
||||
}
|
||||
NSData *data = [utf8 dataUsingEncoding:NSUTF8StringEncoding];
|
||||
[_data appendData:data];
|
||||
}
|
||||
|
||||
- (void)appendWithKey:(NSString *)key
|
||||
formValue:(NSString *)value
|
||||
{
|
||||
[self _appendWithKey:key filename:nil contentType:nil contentBlock:^{
|
||||
[self appendUTF8:value];
|
||||
}];
|
||||
if (key && value) {
|
||||
[FBSDKTypeUtility dictionary:_json setObject:value forKey:key];
|
||||
}
|
||||
}
|
||||
|
||||
- (NSData *)data
|
||||
{
|
||||
NSData *jsonData;
|
||||
if (_json.allKeys.count > 0) {
|
||||
jsonData = [FBSDKTypeUtility dataWithJSONObject:_json options:0 error:nil];
|
||||
} else {
|
||||
jsonData = [NSData data];
|
||||
}
|
||||
|
||||
return jsonData;
|
||||
}
|
||||
|
||||
- (void)_appendWithKey:(NSString *)key
|
||||
filename:(NSString *)filename
|
||||
contentType:(NSString *)contentType
|
||||
contentBlock:(AEMCodeBlock)contentBlock
|
||||
{
|
||||
NSMutableArray *disposition = [NSMutableArray new];
|
||||
[FBSDKTypeUtility array:disposition addObject:@"Content-Disposition: form-data"];
|
||||
if (key) {
|
||||
[FBSDKTypeUtility array:disposition addObject:[[NSString alloc] initWithFormat:@"name=\"%@\"", key]];
|
||||
}
|
||||
if (filename) {
|
||||
[FBSDKTypeUtility array:disposition addObject:[[NSString alloc] initWithFormat:@"filename=\"%@\"", filename]];
|
||||
}
|
||||
[self appendUTF8:[[NSString alloc] initWithFormat:@"%@%@", [disposition componentsJoinedByString:@"; "], kNewline]];
|
||||
if (contentType) {
|
||||
[self appendUTF8:[[NSString alloc] initWithFormat:@"Content-Type: %@%@", contentType, kNewline]];
|
||||
}
|
||||
[self appendUTF8:kNewline];
|
||||
if (contentBlock != NULL) {
|
||||
contentBlock();
|
||||
}
|
||||
[self appendUTF8:[[NSString alloc] initWithFormat:@"%@", kNewline]];
|
||||
}
|
||||
|
||||
- (NSData *)compressedData
|
||||
{
|
||||
if (!self.data.length) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
return [FBSDKBasicUtility gzip:self.data];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#endif
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
// 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 "TargetConditionals.h"
|
||||
|
||||
#if !TARGET_OS_TV
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#import "FBAEMEvent.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface FBAEMRule : NSObject <NSCopying, NSSecureCoding>
|
||||
|
||||
@property (nonatomic) NSInteger conversionValue;
|
||||
|
||||
@property (nonatomic) NSInteger priority;
|
||||
|
||||
@property (nonatomic, copy) NSArray<FBAEMEvent *> *events;
|
||||
|
||||
- (nullable instancetype)initWithJSON:(nullable NSDictionary<NSString *, id> *)dict;
|
||||
|
||||
- (BOOL)isMatchedWithRecordedEvents:(nullable NSSet<NSString *> *)recordedEvents
|
||||
recordedValues:(nullable NSDictionary<NSString *, NSDictionary *> *)recordedValues;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
#endif
|
||||
+144
@@ -0,0 +1,144 @@
|
||||
// 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 "TargetConditionals.h"
|
||||
|
||||
#if !TARGET_OS_TV
|
||||
|
||||
#import "FBAEMRule.h"
|
||||
|
||||
#import "FBCoreKitBasicsImportForAEMKit.h"
|
||||
|
||||
static NSString *const CONVERSION_VALUE_KEY = @"conversion_value";
|
||||
static NSString *const PRIORITY_KEY = @"priority";
|
||||
static NSString *const EVENTS_KEY = @"events";
|
||||
|
||||
@implementation FBAEMRule
|
||||
|
||||
- (nullable instancetype)initWithJSON:(nullable NSDictionary<NSString *, id> *)dict
|
||||
{
|
||||
if ((self = [super init])) {
|
||||
dict = [FBSDKTypeUtility dictionaryValue:dict];
|
||||
if (!dict) {
|
||||
return nil;
|
||||
}
|
||||
NSNumber *conversionValue = [FBSDKTypeUtility dictionary:dict objectForKey:CONVERSION_VALUE_KEY ofType:NSNumber.class];
|
||||
NSNumber *priority = [FBSDKTypeUtility dictionary:dict objectForKey:PRIORITY_KEY ofType:NSNumber.class];
|
||||
NSArray<FBAEMEvent *> *events = [FBAEMRule parseEvents:[FBSDKTypeUtility dictionary:dict objectForKey:EVENTS_KEY ofType:NSArray.class]];
|
||||
if (conversionValue == nil || priority == nil || 0 == events.count) {
|
||||
return nil;
|
||||
}
|
||||
_conversionValue = conversionValue.integerValue;
|
||||
_priority = priority.integerValue;
|
||||
_events = events;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (instancetype)initWithConversionValue:(NSInteger)conversionValue
|
||||
priority:(NSInteger)priority
|
||||
events:(NSArray<FBAEMEvent *> *)events
|
||||
{
|
||||
if ((self = [super init])) {
|
||||
_conversionValue = conversionValue;
|
||||
_priority = priority;
|
||||
_events = events;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (BOOL)isMatchedWithRecordedEvents:(nullable NSSet<NSString *> *)recordedEvents
|
||||
recordedValues:(nullable NSDictionary<NSString *, NSDictionary *> *)recordedValues
|
||||
{
|
||||
for (FBAEMEvent *event in self.events) {
|
||||
// Check if event name matches
|
||||
if (![recordedEvents containsObject:event.eventName]) {
|
||||
return NO;
|
||||
}
|
||||
// Check if event value matches when values is not nil
|
||||
if (event.values) {
|
||||
NSDictionary<NSString *, NSNumber *> *recordedEventValues = [FBSDKTypeUtility dictionary:recordedValues objectForKey:event.eventName ofType:NSDictionary.class];
|
||||
if (![self _isMatchedWithValues:event.values recordedEventValues:recordedEventValues]) {
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (BOOL)_isMatchedWithValues:(NSDictionary<NSString *, NSNumber *> *)values
|
||||
recordedEventValues:(nullable NSDictionary<NSString *, NSNumber *> *)recordedEventValues
|
||||
{
|
||||
for (NSString *currency in values) {
|
||||
NSNumber *valueInMapping = [FBSDKTypeUtility dictionary:values objectForKey:currency ofType:NSNumber.class];
|
||||
NSNumber *value = [FBSDKTypeUtility dictionary:recordedEventValues objectForKey:currency ofType:NSNumber.class];
|
||||
if (value.doubleValue >= valueInMapping.doubleValue) {
|
||||
return YES;
|
||||
}
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
+ (nullable NSArray<FBAEMEvent *> *)parseEvents:(nullable NSArray<NSDictionary<NSString *, id> *> *)events
|
||||
{
|
||||
if (0 == events.count) {
|
||||
return nil;
|
||||
}
|
||||
NSMutableArray<FBAEMEvent *> *parsedEvents = [NSMutableArray new];
|
||||
for (NSDictionary<NSString *, id> *eventEntry in events) {
|
||||
FBAEMEvent *event = [[FBAEMEvent alloc] initWithJSON:eventEntry];
|
||||
if (!event) {
|
||||
return nil;
|
||||
}
|
||||
[FBSDKTypeUtility array:parsedEvents addObject:event];
|
||||
}
|
||||
return [parsedEvents copy];
|
||||
}
|
||||
|
||||
#pragma mark - NSCoding
|
||||
|
||||
+ (BOOL)supportsSecureCoding
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (instancetype)initWithCoder:(NSCoder *)decoder
|
||||
{
|
||||
NSInteger conversionValue = [decoder decodeIntegerForKey:CONVERSION_VALUE_KEY];
|
||||
NSInteger priority = [decoder decodeIntegerForKey:PRIORITY_KEY];
|
||||
NSArray<FBAEMEvent *> *events = [decoder decodeObjectOfClasses:[NSSet setWithArray:@[NSArray.class, FBAEMEvent.class]] forKey:EVENTS_KEY];
|
||||
return [self initWithConversionValue:conversionValue priority:priority events:events];
|
||||
}
|
||||
|
||||
- (void)encodeWithCoder:(NSCoder *)encoder
|
||||
{
|
||||
[encoder encodeInteger:_conversionValue forKey:CONVERSION_VALUE_KEY];
|
||||
[encoder encodeInteger:_priority forKey:PRIORITY_KEY];
|
||||
[encoder encodeObject:_events forKey:EVENTS_KEY];
|
||||
}
|
||||
|
||||
#pragma mark - NSCopying
|
||||
|
||||
- (instancetype)copyWithZone:(NSZone *)zone
|
||||
{
|
||||
return self;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,25 @@
|
||||
// Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
|
||||
//
|
||||
// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,
|
||||
// copy, modify, and distribute this software in source code or binary form for use
|
||||
// in connection with the web services and APIs provided by Facebook.
|
||||
//
|
||||
// As with any software that integrates with the Facebook platform, your use of
|
||||
// this software is subject to the Facebook Developer Principles and Policies
|
||||
// [http://developers.facebook.com/policy/]. This copyright notice shall be
|
||||
// included in all copies or substantial portions of the software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
// TODO: This needs to be renamed once BUCK does not include CoreKit Internal Headers
|
||||
|
||||
#if defined FBSDK_SWIFT_PACKAGE
|
||||
@import FBSDKCoreKit_Basics;
|
||||
#else
|
||||
#import <FBSDKCoreKit_Basics/FBSDKCoreKit_Basics.h>
|
||||
#endif
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
// Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
|
||||
//
|
||||
// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,
|
||||
// copy, modify, and distribute this software in source code or binary form for use
|
||||
// in connection with the web services and APIs provided by Facebook.
|
||||
//
|
||||
// As with any software that integrates with the Facebook platform, your use of
|
||||
// this software is subject to the Facebook Developer Principles and Policies
|
||||
// [http://developers.facebook.com/policy/]. This copyright notice shall be
|
||||
// included in all copies or substantial portions of the software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
// This deserves some explanation.
|
||||
// Cocoapods - we define FBAEMKit as a subspec so to import it we need to use
|
||||
// the name of the module produced by the podspec which is FBSDKCoreKit. To be able
|
||||
// to reference it as <FBAEMKit> we need to publish a separate pod.
|
||||
// Because of the way files in the subspec are made available to the pod, we do not need
|
||||
// to use the bracket import syntax.
|
||||
//
|
||||
// BUCK - we define FBAEMKit as a separate library so we must import it as
|
||||
// <FBAEMKit>
|
||||
//
|
||||
// Xcodeproj - we define FBAEMKit as a distinct module with its own project
|
||||
// so that we can import it as <FBAEMKit>
|
||||
//
|
||||
// Swift Package Manager - it can be imported with `@import FBAEMKit` which allows us to reference
|
||||
// public headers without bracket import syntax.
|
||||
|
||||
#import "TargetConditionals.h"
|
||||
|
||||
#if !TARGET_OS_TV
|
||||
|
||||
#import "FBAEMNetworking.h"
|
||||
#import "FBAEMReporter.h"
|
||||
#import "FBSKAdNetworkReporting.h"
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,42 @@
|
||||
// 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 "TargetConditionals.h"
|
||||
|
||||
#if !TARGET_OS_TV
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
typedef void (^FBGraphRequestCompletion)(id _Nullable result, NSError *_Nullable error);
|
||||
|
||||
NS_SWIFT_NAME(AEMNetworking)
|
||||
@protocol FBAEMNetworking
|
||||
|
||||
- (void)startGraphRequestWithGraphPath:(NSString *)graphPath
|
||||
parameters:(NSDictionary *)parameters
|
||||
tokenString:(nullable NSString *)tokenString
|
||||
HTTPMethod:(nullable NSString *)method
|
||||
completion:(FBGraphRequestCompletion)completion;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,95 @@
|
||||
// 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 "TargetConditionals.h"
|
||||
|
||||
#if !TARGET_OS_TV
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "FBAEMNetworking.h"
|
||||
#import "FBSKAdNetworkReporting.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
NS_SWIFT_NAME(AEMReporter)
|
||||
@interface FBAEMReporter : NSObject
|
||||
|
||||
/**
|
||||
|
||||
Configure networker used for calling Facebook AEM Graph API endpoint
|
||||
and Facebook App ID
|
||||
|
||||
This function should be called in application(_:open:options:) from ApplicationDelegate
|
||||
and BEFORE [FBAEMReporter enable] function
|
||||
|
||||
@param networker An optional networker conforms to FBAEMNetworking which handles Graph API request
|
||||
@param appID The Facebook app ID
|
||||
*/
|
||||
+ (void)configureWithNetworker:(nullable id<FBAEMNetworking>)networker
|
||||
appID:(NSString *)appID;
|
||||
|
||||
/**
|
||||
|
||||
Configure networker used for calling Facebook AEM Graph API endpoint
|
||||
and Facebook App ID
|
||||
|
||||
This function should be called in application(_:open:options:) from ApplicationDelegate
|
||||
and BEFORE [FBAEMReporter enable] function. We will use SKAdNetwork reporter to prevent
|
||||
double counting.
|
||||
|
||||
@param networker An optional networker conforms to FBAEMNetworking which handles Graph API request
|
||||
@param appID The Facebook app ID
|
||||
@param reporter The SKAdNetwork repoter
|
||||
*/
|
||||
+ (void)configureWithNetworker:(nullable id<FBAEMNetworking>)networker
|
||||
appID:(NSString *)appID
|
||||
reporter:(nullable id<FBSKAdNetworkReporting>)reporter;
|
||||
|
||||
/**
|
||||
|
||||
Enable AEM reporting
|
||||
|
||||
This function should be called in application(_:open:options:) from ApplicationDelegate
|
||||
*/
|
||||
+ (void)enable;
|
||||
|
||||
/**
|
||||
|
||||
Handle deeplink
|
||||
|
||||
This function should be called in application(_:open:options:) from ApplicationDelegate
|
||||
*/
|
||||
+ (void)handleURL:(NSURL *)url;
|
||||
|
||||
/**
|
||||
|
||||
Calculate the conversion value for the app event based on the AEM configuration
|
||||
|
||||
This function should be called when you log any in-app events
|
||||
*/
|
||||
+ (void)recordAndUpdateEvent:(NSString *)event
|
||||
currency:(nullable NSString *)currency
|
||||
value:(nullable NSNumber *)value
|
||||
parameters:(nullable NSDictionary *)parameters
|
||||
NS_SWIFT_NAME(recordAndUpdate(event:currency:value:parameters:));
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,38 @@
|
||||
// Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
|
||||
//
|
||||
// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,
|
||||
// copy, modify, and distribute this software in source code or binary form for use
|
||||
// in connection with the web services and APIs provided by Facebook.
|
||||
//
|
||||
// As with any software that integrates with the Facebook platform, your use of
|
||||
// this software is subject to the Facebook Developer Principles and Policies
|
||||
// [http://developers.facebook.com/policy/]. This copyright notice shall be
|
||||
// included in all copies or substantial portions of the software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#import "TargetConditionals.h"
|
||||
|
||||
#if !TARGET_OS_TV
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
NS_SWIFT_NAME(SKAdNetworkReporting)
|
||||
@protocol FBSKAdNetworkReporting
|
||||
|
||||
- (BOOL)shouldCutoff;
|
||||
|
||||
- (BOOL)isReportingEvent:(NSString *)event;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user