If you find yourself in a situation you must obtain the IDFA in new iOS14 but you are not ready for new Xcode12 this is a hopefully legal way of getting this.
This method is not new and works thanks to obj-c dynamic features :). I am no one to recommend this code for apps that goes throught the AppStore. Probably it might pass Apple's review. Anyway, this approach is definetely good for investigations, prototypes, etc.
// HackyTrackingManager.h
@interface HackyTrackingManager: NSObject {
}
+(void)requestIdfa:(void(^)(BOOL granted, NSString* idfaUUID))completion;
@end
// HackyTrackingManager.m
#import AdSupport/AdSupport.h
#import "dlfcn.h"
// Declare interfaces of ATTrackingManager and ATTrackingManagerAuthorizationStatus to trick the compiler
NS_ASSUME_NONNULL_BEGIN
typedef NS_ENUM(NSUInteger, ATTrackingManagerAuthorizationStatus) {
ATTrackingManagerAuthorizationStatusNotDetermined = 0,
ATTrackingManagerAuthorizationStatusRestricted,
ATTrackingManagerAuthorizationStatusDenied,
ATTrackingManagerAuthorizationStatusAuthorized
} NS_SWIFT_NAME(ATTrackingManager.AuthorizationStatus);
@interface ATTrackingManager : NSObject
@property (class, nonatomic, readon ly, assign) ATTrackingManagerAuthorizationStatus trackingAuthorizationStatus;
+ (void)requestTrackingAuthorizationWithCompletionHandler:(void(^)(ATTrackingManagerAuthorizationStatus status))completion;
@end
NS_ASSUME_NONNULL_END
// Implement the trick
@implementation HackyTrackingManager
+(void)requestIdfa:(void(^)(BOOL granted, NSString* idfaUUID))completion {
// Attempt to use iOS14's ATTrackingManager and for that we need to (dinamically) load AppTrackingTransparency
dlopen("/Library/Frameworks/AppTrackingTransparency.framework/AppTrackingTransparency", RTLD_LAZY);
Class tm = NSClassFromString(@"ATTrackingManager");
if (tm) {
// iOS14 and later
[tm requestTrackingAuthorizationWithCompletionHandler:^(ATTrackingManagerAuthorizationStatus status) {
ASIdentifierManager *im = [ASIdentifierManager sharedManager];
completion(status == ATTrackingManagerAuthorizationStatusAuthorized, im.advertisingIdentifier.UUIDString);
}];
} else {
// iOS13 and prior
ASIdentifierManager *im = [ASIdentifierManager sharedManager];
completion([im isAdvertisingTrackingEnabled], im.advertisingIdentifier.UUIDString);
}
}
Explanation
First, since Xcode11 does not know anything about iOS14 SDK we need some @interfaces for ATTrackingManager
and ATTrackingManagerAuthorizationStatus
that tricks the compiler. The real trick about this is I don't provide @implementation for ATTrackingManager
because the real implementation is already inside iOS14 AppTrackingTransparency.framework.
Second, we need to use ATTrackingManager
and in order to do so we need to get the class dinamically using NSClassFromString
and since Xcode11 does not have iOS14 SDK at compile time we need to load new framework AppTrackingTransparency at runtime by ourselves using dlopen
. This will ensure NSClassFromString(@"ATTrackingManager")
succeeds in iOS14.
Third, we check ATTrackingManager
is there. In iOS14 this succeeds so we use requestTrackingAuthorizationWithCompletionHandler
. Inside the block we can use get the status and use AdSupport.framework classes to get the IDFA. In iOS13 and prior OSes this will fail so we go inside the else
and directly use AdSupport.framework classes.
I hope it helps
0 comments :
Post a Comment