Skip to content

Instantly share code, notes, and snippets.

@guthyerrz
Created August 3, 2023 21:09
Show Gist options
  • Save guthyerrz/1a54dbdb3dd4b8189fb1898f156f7a89 to your computer and use it in GitHub Desktop.
Save guthyerrz/1a54dbdb3dd4b8189fb1898f156f7a89 to your computer and use it in GitHub Desktop.
Classes to circunvent the problem of SKAN V4 bein zerod out by the +[AAAttribution attributionTokenWithError:] method as presented by this article https://www.singular.net/blog/skan-4-cv-reset-bug/
//
// WLSConversionValueUtils.h
// Unity-iPhone
//
// Created by Guthyerrz Silva on 03/08/23.
//
#ifndef WLSSKAdNetworkCVUtils_h
#define WLSSKAdNetworkCVUtils_h
#import <StoreKit/SKAdNetwork.h>
typedef NS_ENUM(NSInteger, WLSSKANCoarseConversionValue) {
WLSSKANCoarseConversionValueLow = 0,
WLSSKANCoarseConversionValueMedium,
WLSSKANCoarseConversionValueHigh,
} ;
@interface WLSConversionValueUtils : NSObject
+ (void)sendUpdatedConversionValue:(NSInteger)conversionValue
coarseConversionValue:(WLSSKANCoarseConversionValue)coarseConversionValue
lockWindow:(BOOL)lockWindow
completionHandler:(void (^)(NSError *error))completionHandler;
@end
#endif /* WLSSKAdNetworkUtils_h */
//
// WLSConversionValueUtils.m
// Unity-iPhone
//
// Created by Guthyerrz Silva on 03/08/23.
//
#import <Foundation/Foundation.h>
#import "WLSConversionValueUtils.h"
#import <objc/runtime.h>
#import <StoreKit/SKAdNetwork.h>
#define CV_KEY @"WLSSKAdNetworkCVUtils_CV_KEY"
#define COARSE_CV_KEY @"WLSSKAdNetworkCVUtils_COARSE_CV_KEY"
#define LOCK_WINDOW_KEY @"WLSSKAdNetworkCVUtils_LOCK_WINDOW_KEY"
@implementation WLSConversionValueUtils
static NSInteger conversionValue = 0;
static WLSSKANCoarseConversionValue coarseCV = WLSSKANCoarseConversionValueLow;
static BOOL lockWindow = false;
+ (void)load {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
[WLSConversionValueUtils loadVariables];
Class originalClass = [SKAdNetwork class];
Class newClass = [self class];
SEL swizzledSelector = @selector(wlsUpdatePostbackConversionValue:coarseValue:lockWindow:completionHandler:);
SEL originalSelector = @selector(updatePostbackConversionValue:coarseValue:lockWindow:completionHandler:);
Method originalMethod = class_getClassMethod(originalClass, originalSelector);
Method swizzledMethod = class_getClassMethod(newClass, swizzledSelector);
method_exchangeImplementations(originalMethod,swizzledMethod);
swizzledSelector = @selector(wlsUpdatePostbackConversionValue:coarseValue:completionHandler:);
originalSelector = @selector(updatePostbackConversionValue:coarseValue:completionHandler:);
originalMethod = class_getClassMethod(originalClass, originalSelector);
swizzledMethod = class_getClassMethod(newClass, swizzledSelector);
method_exchangeImplementations(originalMethod,swizzledMethod);
swizzledSelector = @selector(wlsUpdatePostbackConversionValue:completionHandler:);
originalSelector = @selector(updatePostbackConversionValue:completionHandler:);
originalMethod = class_getClassMethod(originalClass, originalSelector);
swizzledMethod = class_getClassMethod(newClass, swizzledSelector);
method_exchangeImplementations(originalMethod,swizzledMethod);
swizzledSelector = @selector(wlsUpdateConversionValue:);
originalSelector = @selector(updateConversionValue:);
originalMethod = class_getClassMethod(originalClass, originalSelector);
swizzledMethod = class_getClassMethod(newClass, swizzledSelector);
method_exchangeImplementations(originalMethod,swizzledMethod);
});
}
+(void)sendUpdatedConversionValue:(NSInteger)conversionValue
coarseConversionValue:(WLSSKANCoarseConversionValue)coarse
lockWindow:(BOOL)lockWindow
completionHandler:(void (^)(NSError *))completionHandler{
[WLSConversionValueUtils saveConversionValue:conversionValue
coarseConversionValue:coarse
lockWindow:lockWindow];
if (@available(iOS 16.1, *)) {
SKAdNetworkCoarseConversionValue coarseCV = [WLSConversionValueUtils mapToSKAdNetworkCoarseCV:coarse];
[WLSConversionValueUtils wlsUpdatePostbackConversionValue:conversionValue
coarseValue:coarseCV
lockWindow:lockWindow
completionHandler:completionHandler];
} else if(@available (iOS 15.4,*)) {
[WLSConversionValueUtils wlsUpdatePostbackConversionValue:conversionValue
completionHandler:completionHandler];
} else if(@available (iOS 14.0,*)){
[WLSConversionValueUtils wlsUpdateConversionValue:conversionValue];
}
}
+ (void)wlsUpdatePostbackConversionValue:(NSInteger)fineValue coarseValue:(SKAdNetworkCoarseConversionValue)coarseValue lockWindow:(BOOL)lock completionHandler:(nullable void (^)(NSError *__nullable error))completion API_AVAILABLE(ios(16.1)){
SKAdNetworkCoarseConversionValue coarse = [WLSConversionValueUtils mapToSKAdNetworkCoarseCV:coarseCV];
[WLSConversionValueUtils wlsUpdatePostbackConversionValue:conversionValue coarseValue:coarse lockWindow:lockWindow completionHandler:completion];
}
+ (void)wlsUpdatePostbackConversionValue:(NSInteger)fineValue completionHandler:(nullable void (^)(NSError *__nullable error))completion API_AVAILABLE(ios(15.4)){
[WLSConversionValueUtils wlsUpdatePostbackConversionValue:conversionValue completionHandler:completion];
}
+ (void)wlsUpdateConversionValue:(NSInteger)fineValue API_DEPRECATED("Use updatePostbackConversionValue:completionHandler: instead", ios(14.0, 15.4)){
[WLSConversionValueUtils wlsUpdateConversionValue:conversionValue];
}
+ (void)wlsUpdatePostbackConversionValue:(NSInteger)fineValue coarseValue:(SKAdNetworkCoarseConversionValue)coarseValue completionHandler:(nullable void (^)(NSError *__nullable error))completion API_AVAILABLE(ios(16.1)){
SKAdNetworkCoarseConversionValue coarse = [WLSConversionValueUtils mapToSKAdNetworkCoarseCV:coarseCV];
[WLSConversionValueUtils wlsUpdatePostbackConversionValue:conversionValue coarseValue:coarse completionHandler:completion];
}
+(void) loadVariables{
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
conversionValue = [userDefaults integerForKey:CV_KEY];
coarseCV = (WLSSKANCoarseConversionValue) [userDefaults integerForKey:COARSE_CV_KEY];
lockWindow = [userDefaults boolForKey:LOCK_WINDOW_KEY];
}
+(void)saveConversionValue:(NSInteger)fineValue
coarseConversionValue:(WLSSKANCoarseConversionValue)coarse
lockWindow:(BOOL)lk{
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
[userDefaults setInteger:fineValue forKey:CV_KEY];
[userDefaults setInteger:coarse forKey:COARSE_CV_KEY];
[userDefaults setBool:lk forKey:LOCK_WINDOW_KEY];
conversionValue = fineValue;
coarseCV = coarse;
lockWindow = lk;
}
+ (SKAdNetworkCoarseConversionValue)mapToSKAdNetworkCoarseCV:(WLSSKANCoarseConversionValue)coarseConversionValue API_AVAILABLE(ios(16.0)){
SKAdNetworkCoarseConversionValue coarseCV = SKAdNetworkCoarseConversionValueLow;
switch (coarseConversionValue) {
case WLSSKANCoarseConversionValueMedium:
coarseCV = SKAdNetworkCoarseConversionValueMedium;
break;
case WLSSKANCoarseConversionValueHigh:
coarseCV = SKAdNetworkCoarseConversionValueHigh;
break;
default:
//Use SKAdNetworkCoarseConversionValueLow (for WLSSKANCoarseConversionValueLow or any other value)
break;
}
return coarseCV;
}
@end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment