// // AdjustUnity.mm // Adjust SDK // // Created by Pedro Silva (@nonelse) on 27th March 2014. // Copyright © 2012-2018 Adjust GmbH. All rights reserved. // #import "Adjust.h" #import "ADJEvent.h" #import "ADJConfig.h" #import "AdjustUnity.h" #import "AdjustUnityAppDelegate.h" #import "AdjustUnityDelegate.h" @implementation AdjustUnity #pragma mark - Object lifecycle methods + (void)load { // Swizzle AppDelegate on the load. It should be done as early as possible. [AdjustUnityAppDelegate swizzleAppDelegateCallbacks]; } @end #pragma mark - Helper C methods // Method for converting JSON stirng parameters into NSArray object. NSArray* convertArrayParameters(const char* cStringJsonArrayParameters) { if (cStringJsonArrayParameters == NULL) { return nil; } NSError *error = nil; NSArray *arrayParameters = nil; NSString *stringJsonArrayParameters = [NSString stringWithUTF8String:cStringJsonArrayParameters]; if (stringJsonArrayParameters != nil) { NSData *dataJson = [stringJsonArrayParameters dataUsingEncoding:NSUTF8StringEncoding]; arrayParameters = [NSJSONSerialization JSONObjectWithData:dataJson options:0 error:&error]; } if (error != nil) { NSString *errorMessage = @"Failed to parse json parameters!"; NSLog(@"%@", errorMessage); } return arrayParameters; } BOOL isStringValid(const char* cString) { if (cString == NULL) { return false; } NSString *objcString = [NSString stringWithUTF8String:cString]; if (objcString == nil) { return false; } if ([objcString isEqualToString:@"ADJ_INVALID"]) { return false; } return true; } void addValueOrEmpty(NSMutableDictionary *dictionary, NSString *key, NSObject *value) { if (nil != value) { if ([value isKindOfClass:[NSString class]]) { [dictionary setObject:[NSString stringWithFormat:@"%@", value] forKey:key]; } else if ([value isKindOfClass:[NSNumber class]]) { [dictionary setObject:[NSString stringWithFormat:@"%@", [((NSNumber *)value) stringValue]] forKey:key]; } else { [dictionary setObject:@"" forKey:key]; } } else { [dictionary setObject:@"" forKey:key]; } } #pragma mark - Publicly available C methods extern "C" { void _AdjustLaunchApp(const char* appToken, const char* environment, const char* sdkPrefix, const char* userAgent, const char* defaultTracker, const char* externalDeviceId, const char* urlStrategy, const char* sceneName, int allowSuppressLogLevel, int logLevel, int isDeviceKnown, int eventBuffering, int sendInBackground, int allowAdServicesInfoReading, int allowIdfaReading, int deactivateSkAdNetworkHandling, int linkMeEnabled, int needsCost, int coppaCompliant, int readDeviceInfoOnce, int64_t secretId, int64_t info1, int64_t info2, int64_t info3, int64_t info4, double delayStart, int attConsentWaitingInterval, int launchDeferredDeeplink, int isAttributionCallbackImplemented, int isEventSuccessCallbackImplemented, int isEventFailureCallbackImplemented, int isSessionSuccessCallbackImplemented, int isSessionFailureCallbackImplemented, int isDeferredDeeplinkCallbackImplemented, int isConversionValueUpdatedCallbackImplemented, int isSkad4ConversionValueUpdatedCallbackImplemented) { NSString *stringAppToken = isStringValid(appToken) == true ? [NSString stringWithUTF8String:appToken] : nil; NSString *stringEnvironment = isStringValid(environment) == true ? [NSString stringWithUTF8String:environment] : nil; NSString *stringSdkPrefix = isStringValid(sdkPrefix) == true ? [NSString stringWithUTF8String:sdkPrefix] : nil; NSString *stringUserAgent = isStringValid(userAgent) == true ? [NSString stringWithUTF8String:userAgent] : nil; NSString *stringDefaultTracker = isStringValid(defaultTracker) == true ? [NSString stringWithUTF8String:defaultTracker] : nil; NSString *stringExternalDeviceId = isStringValid(externalDeviceId) == true ? [NSString stringWithUTF8String:externalDeviceId] : nil; NSString *stringUrlStrategy = isStringValid(urlStrategy) == true ? [NSString stringWithUTF8String:urlStrategy] : nil; NSString *stringSceneName = isStringValid(sceneName) == true ? [NSString stringWithUTF8String:sceneName] : nil; ADJConfig *adjustConfig; if (allowSuppressLogLevel != -1) { adjustConfig = [ADJConfig configWithAppToken:stringAppToken environment:stringEnvironment allowSuppressLogLevel:(BOOL)allowSuppressLogLevel]; } else { adjustConfig = [ADJConfig configWithAppToken:stringAppToken environment:stringEnvironment]; } // Set SDK prefix. [adjustConfig setSdkPrefix:stringSdkPrefix]; // Check if user has selected to implement any of the callbacks. if (isAttributionCallbackImplemented || isEventSuccessCallbackImplemented || isEventFailureCallbackImplemented || isSessionSuccessCallbackImplemented || isSessionFailureCallbackImplemented || isDeferredDeeplinkCallbackImplemented || isConversionValueUpdatedCallbackImplemented || isSkad4ConversionValueUpdatedCallbackImplemented) { [adjustConfig setDelegate: [AdjustUnityDelegate getInstanceWithSwizzleOfAttributionCallback:isAttributionCallbackImplemented eventSuccessCallback:isEventSuccessCallbackImplemented eventFailureCallback:isEventFailureCallbackImplemented sessionSuccessCallback:isSessionSuccessCallbackImplemented sessionFailureCallback:isSessionFailureCallbackImplemented deferredDeeplinkCallback:isDeferredDeeplinkCallbackImplemented conversionValueUpdatedCallback:isConversionValueUpdatedCallbackImplemented skad4ConversionValueUpdatedCallback:isSkad4ConversionValueUpdatedCallbackImplemented shouldLaunchDeferredDeeplink:launchDeferredDeeplink withAdjustUnitySceneName:stringSceneName]]; } // Log level. if (logLevel != -1) { [adjustConfig setLogLevel:(ADJLogLevel)logLevel]; } // Event buffering. if (eventBuffering != -1) { [adjustConfig setEventBufferingEnabled:(BOOL)eventBuffering]; } // Send in background. if (sendInBackground != -1) { [adjustConfig setSendInBackground:(BOOL)sendInBackground]; } // Allow AdServices info reading. if (allowAdServicesInfoReading != -1) { [adjustConfig setAllowAdServicesInfoReading:(BOOL)allowAdServicesInfoReading]; } // Deactivate default SKAdNetwork handling. if (deactivateSkAdNetworkHandling != -1) { [adjustConfig deactivateSKAdNetworkHandling]; } // Allow IDFA reading. if (allowIdfaReading != -1) { [adjustConfig setAllowIdfaReading:(BOOL)allowIdfaReading]; } // Enable LinkMe feature. if (linkMeEnabled != -1) { [adjustConfig setLinkMeEnabled:(BOOL)linkMeEnabled]; } // Device known. if (isDeviceKnown != -1) { [adjustConfig setIsDeviceKnown:(BOOL)isDeviceKnown]; } // Delay start. if (delayStart != -1) { [adjustConfig setDelayStart:delayStart]; } // ATT dialog delay. if (attConsentWaitingInterval != -1) { [adjustConfig setAttConsentWaitingInterval:attConsentWaitingInterval]; } // Cost data in attribution callback. if (needsCost != -1) { [adjustConfig setNeedsCost:(BOOL)needsCost]; } // COPPA compliance. if (coppaCompliant != -1) { [adjustConfig setCoppaCompliantEnabled:(BOOL)coppaCompliant]; } // Read device info just once. if (readDeviceInfoOnce != -1) { [adjustConfig setReadDeviceInfoOnceEnabled:(BOOL)readDeviceInfoOnce]; } // User agent. if (stringUserAgent != nil) { [adjustConfig setUserAgent:stringUserAgent]; } // Default tracker. if (stringDefaultTracker != nil) { [adjustConfig setDefaultTracker:stringDefaultTracker]; } // External device identifier. if (stringExternalDeviceId != nil) { [adjustConfig setExternalDeviceId:stringExternalDeviceId]; } // URL strategy. if (stringUrlStrategy != nil) { if ([stringUrlStrategy isEqualToString:@"china"]) { [adjustConfig setUrlStrategy:ADJUrlStrategyChina]; } else if ([stringUrlStrategy isEqualToString:@"india"]) { [adjustConfig setUrlStrategy:ADJUrlStrategyIndia]; } else if ([stringUrlStrategy isEqualToString:@"cn"]) { [adjustConfig setUrlStrategy:ADJUrlStrategyCn]; } else if ([stringUrlStrategy isEqualToString:@"cn-only"]) { [adjustConfig setUrlStrategy:ADJUrlStrategyCnOnly]; } else if ([stringUrlStrategy isEqualToString:@"data-residency-eu"]) { [adjustConfig setUrlStrategy:ADJDataResidencyEU]; } else if ([stringUrlStrategy isEqualToString:@"data-residency-tr"]) { [adjustConfig setUrlStrategy:ADJDataResidencyTR]; } else if ([stringUrlStrategy isEqualToString:@"data-residency-us"]) { [adjustConfig setUrlStrategy:ADJDataResidencyUS]; } } // App secret. if (secretId != -1 && info1 != -1 && info2 != -1 && info3 != -1 && info4 != 1) { [adjustConfig setAppSecret:secretId info1:info1 info2:info2 info3:info3 info4:info4]; } // Start the SDK. [Adjust appDidLaunch:adjustConfig]; [Adjust trackSubsessionStart]; } void _AdjustTrackEvent(const char* eventToken, double revenue, const char* currency, const char* receipt, const char* receiptBase64, const char* productId, const char* transactionId, const char* callbackId, int isReceiptSet, const char* jsonCallbackParameters, const char* jsonPartnerParameters) { NSString *stringEventToken = isStringValid(eventToken) == true ? [NSString stringWithUTF8String:eventToken] : nil; ADJEvent *event = [ADJEvent eventWithEventToken:stringEventToken]; // Revenue and currency. if (revenue != -1 && currency != NULL) { NSString *stringCurrency = [NSString stringWithUTF8String:currency]; [event setRevenue:revenue currency:stringCurrency]; } // Callback parameters. NSArray *arrayCallbackParameters = convertArrayParameters(jsonCallbackParameters); if (arrayCallbackParameters != nil) { NSUInteger count = [arrayCallbackParameters count]; for (int i = 0; i < count;) { NSString *key = arrayCallbackParameters[i++]; NSString *value = arrayCallbackParameters[i++]; [event addCallbackParameter:key value:value]; } } NSArray *arrayPartnerParameters = convertArrayParameters(jsonPartnerParameters); if (arrayPartnerParameters != nil) { NSUInteger count = [arrayPartnerParameters count]; for (int i = 0; i < count;) { NSString *key = arrayPartnerParameters[i++]; NSString *value = arrayPartnerParameters[i++]; [event addPartnerParameter:key value:value]; } } // Transaction ID. if (transactionId != NULL) { NSString *stringTransactionId = [NSString stringWithUTF8String:transactionId]; [event setTransactionId:stringTransactionId]; } // Product ID. if (productId != NULL) { NSString *stringProductId = [NSString stringWithUTF8String:productId]; [event setProductId:stringProductId]; } // Receipt. if (receipt != NULL) { NSString *stringReceipt = [NSString stringWithUTF8String:receipt]; [event setReceipt:[stringReceipt dataUsingEncoding:NSUTF8StringEncoding]]; } // Base64 encoded receipt. if (receiptBase64 != NULL) { // If both (receipt and receiptBase64) set, receiptBase64 will be used. NSString *stringReceiptBase64 = [NSString stringWithUTF8String:receiptBase64]; NSData *decodedData = [[NSData alloc] initWithBase64EncodedString:stringReceiptBase64 options:0]; [event setReceipt:decodedData]; } // Callback ID. if (callbackId != NULL) { NSString *stringCallbackId = [NSString stringWithUTF8String:callbackId]; [event setCallbackId:stringCallbackId]; } // Receipt (legacy). // if ([[NSNumber numberWithInt:isReceiptSet] boolValue]) { // NSString *stringReceipt = nil; // NSString *stringTransactionId = nil; // if (receipt != NULL) { // stringReceipt = [NSString stringWithUTF8String:receipt]; // } // if (transactionId != NULL) { // stringTransactionId = [NSString stringWithUTF8String:transactionId]; // } // [event setReceipt:[stringReceipt dataUsingEncoding:NSUTF8StringEncoding] transactionId:stringTransactionId]; // } // Track event. [Adjust trackEvent:event]; } void _AdjustTrackSubsessionStart() { [Adjust trackSubsessionStart]; } void _AdjustTrackSubsessionEnd() { [Adjust trackSubsessionEnd]; } void _AdjustSetEnabled(int enabled) { BOOL bEnabled = (BOOL)enabled; [Adjust setEnabled:bEnabled]; } int _AdjustIsEnabled() { BOOL isEnabled = [Adjust isEnabled]; int iIsEnabled = (int)isEnabled; return iIsEnabled; } void _AdjustSetOfflineMode(int enabled) { BOOL bEnabled = (BOOL)enabled; [Adjust setOfflineMode:bEnabled]; } void _AdjustSetDeviceToken(const char* deviceToken) { if (deviceToken != NULL) { NSString *stringDeviceToken = [NSString stringWithUTF8String:deviceToken]; [Adjust setPushToken:stringDeviceToken]; } } void _AdjustAppWillOpenUrl(const char* url) { if (url != NULL) { NSString *stringUrl = [NSString stringWithUTF8String:url]; NSURL *nsUrl; if ([NSString instancesRespondToSelector:@selector(stringByAddingPercentEncodingWithAllowedCharacters:)]) { nsUrl = [NSURL URLWithString:[stringUrl stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLFragmentAllowedCharacterSet]]]; } else { #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wdeprecated-declarations" nsUrl = [NSURL URLWithString:[stringUrl stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]; } #pragma clang diagnostic pop [Adjust appWillOpenUrl:nsUrl]; } } char* _AdjustGetIdfa() { NSString *idfa = [Adjust idfa]; if (nil == idfa) { return NULL; } const char* idfaCString = [idfa UTF8String]; if (NULL == idfaCString) { return NULL; } char* idfaCStringCopy = strdup(idfaCString); return idfaCStringCopy; } char* _AdjustGetIdfv() { NSString *idfv = [Adjust idfv]; if (nil == idfv) { return NULL; } const char* idfvCString = [idfv UTF8String]; if (NULL == idfvCString) { return NULL; } char* idfvCStringCopy = strdup(idfvCString); return idfvCStringCopy; } char* _AdjustGetAdid() { NSString *adid = [Adjust adid]; if (nil == adid) { return NULL; } const char* adidCString = [adid UTF8String]; if (NULL == adidCString) { return NULL; } char* adidCStringCopy = strdup(adidCString); return adidCStringCopy; } char* _AdjustGetSdkVersion() { NSString *sdkVersion = [Adjust sdkVersion]; if (nil == sdkVersion) { return NULL; } const char* sdkVersionCString = [sdkVersion UTF8String]; if (NULL == sdkVersionCString) { return NULL; } char* sdkVersionCStringCopy = strdup(sdkVersionCString); return sdkVersionCStringCopy; } char* _AdjustGetAttribution() { ADJAttribution *attribution = [Adjust attribution]; if (nil == attribution) { return NULL; } NSMutableDictionary *dictionary = [NSMutableDictionary dictionary]; addValueOrEmpty(dictionary, @"trackerToken", attribution.trackerToken); addValueOrEmpty(dictionary, @"trackerName", attribution.trackerName); addValueOrEmpty(dictionary, @"network", attribution.network); addValueOrEmpty(dictionary, @"campaign", attribution.campaign); addValueOrEmpty(dictionary, @"creative", attribution.creative); addValueOrEmpty(dictionary, @"adgroup", attribution.adgroup); addValueOrEmpty(dictionary, @"clickLabel", attribution.clickLabel); addValueOrEmpty(dictionary, @"adid", attribution.adid); addValueOrEmpty(dictionary, @"costType", attribution.costType); addValueOrEmpty(dictionary, @"costAmount", attribution.costAmount); addValueOrEmpty(dictionary, @"costCurrency", attribution.costCurrency); NSData *dataAttribution = [NSJSONSerialization dataWithJSONObject:dictionary options:0 error:nil]; NSString *stringAttribution = [[NSString alloc] initWithBytes:[dataAttribution bytes] length:[dataAttribution length] encoding:NSUTF8StringEncoding]; const char* attributionCString = [stringAttribution UTF8String]; char* attributionCStringCopy = strdup(attributionCString); return attributionCStringCopy; } void _AdjustSendFirstPackages() { [Adjust sendFirstPackages]; } void _AdjustGdprForgetMe() { [Adjust gdprForgetMe]; } void _AdjustDisableThirdPartySharing() { [Adjust disableThirdPartySharing]; } void _AdjustAddSessionPartnerParameter(const char* key, const char* value) { if (key != NULL && value != NULL) { NSString *stringKey = [NSString stringWithUTF8String:key]; NSString *stringValue = [NSString stringWithUTF8String:value]; [Adjust addSessionPartnerParameter:stringKey value:stringValue]; } } void _AdjustAddSessionCallbackParameter(const char* key, const char* value) { if (key != NULL && value != NULL) { NSString *stringKey = [NSString stringWithUTF8String:key]; NSString *stringValue = [NSString stringWithUTF8String:value]; [Adjust addSessionCallbackParameter:stringKey value:stringValue]; } } void _AdjustRemoveSessionPartnerParameter(const char* key) { if (key != NULL) { NSString *stringKey = [NSString stringWithUTF8String:key]; [Adjust removeSessionPartnerParameter:stringKey]; } } void _AdjustRemoveSessionCallbackParameter(const char* key) { if (key != NULL) { NSString *stringKey = [NSString stringWithUTF8String:key]; [Adjust removeSessionCallbackParameter:stringKey]; } } void _AdjustResetSessionPartnerParameters() { [Adjust resetSessionPartnerParameters]; } void _AdjustResetSessionCallbackParameters() { [Adjust resetSessionCallbackParameters]; } void _AdjustTrackAdRevenue(const char* source, const char* payload) { if (source != NULL && payload != NULL) { NSString *stringSource = [NSString stringWithUTF8String:source]; NSString *stringPayload = [NSString stringWithUTF8String:payload]; NSData *dataPayload = [stringPayload dataUsingEncoding:NSUTF8StringEncoding]; [Adjust trackAdRevenue:stringSource payload:dataPayload]; } } void _AdjustTrackAdRevenueNew(const char* source, double revenue, const char* currency, int adImpressionsCount, const char* adRevenueNetwork, const char* adRevenueUnit, const char* adRevenuePlacement, const char* jsonCallbackParameters, const char* jsonPartnerParameters) { NSString *stringSource = isStringValid(source) == true ? [NSString stringWithUTF8String:source] : nil; ADJAdRevenue *adRevenue = [[ADJAdRevenue alloc] initWithSource:stringSource]; // Revenue and currency. if (revenue != -1 && currency != NULL) { NSString *stringCurrency = [NSString stringWithUTF8String:currency]; [adRevenue setRevenue:revenue currency:stringCurrency]; } // Ad impressions count. if (adImpressionsCount != -1) { [adRevenue setAdImpressionsCount:adImpressionsCount]; } // Ad revenue network. if (adRevenueNetwork != NULL) { NSString *stringAdRevenueNetwork = [NSString stringWithUTF8String:adRevenueNetwork]; [adRevenue setAdRevenueNetwork:stringAdRevenueNetwork]; } // Ad revenue unit. if (adRevenueUnit != NULL) { NSString *stringAdRevenueUnit = [NSString stringWithUTF8String:adRevenueUnit]; [adRevenue setAdRevenueUnit:stringAdRevenueUnit]; } // Ad revenue placement. if (adRevenuePlacement != NULL) { NSString *stringAdRevenuePlacement = [NSString stringWithUTF8String:adRevenuePlacement]; [adRevenue setAdRevenuePlacement:stringAdRevenuePlacement]; } // Callback parameters. NSArray *arrayCallbackParameters = convertArrayParameters(jsonCallbackParameters); if (arrayCallbackParameters != nil) { NSUInteger count = [arrayCallbackParameters count]; for (int i = 0; i < count;) { NSString *key = arrayCallbackParameters[i++]; NSString *value = arrayCallbackParameters[i++]; [adRevenue addCallbackParameter:key value:value]; } } NSArray *arrayPartnerParameters = convertArrayParameters(jsonPartnerParameters); if (arrayPartnerParameters != nil) { NSUInteger count = [arrayPartnerParameters count]; for (int i = 0; i < count;) { NSString *key = arrayPartnerParameters[i++]; NSString *value = arrayPartnerParameters[i++]; [adRevenue addPartnerParameter:key value:value]; } } // Track ad revenue. [Adjust trackAdRevenue:adRevenue]; } void _AdjustTrackAppStoreSubscription(const char* price, const char* currency, const char* transactionId, const char* receipt, const char* billingStore, const char* transactionDate, const char* salesRegion, const char* jsonCallbackParameters, const char* jsonPartnerParameters) { // Mandatory fields. NSDecimalNumber *mPrice; NSString *mCurrency; NSString *mTransactionId; NSData *mReceipt; NSString *mBillingStore; // Price. if (price != NULL) { mPrice = [NSDecimalNumber decimalNumberWithString:[NSString stringWithUTF8String:price]]; } // Currency. if (currency != NULL) { mCurrency = [NSString stringWithUTF8String:currency]; } // Transaction ID. if (transactionId != NULL) { mTransactionId = [NSString stringWithUTF8String:transactionId]; } // Receipt. if (receipt != NULL) { mReceipt = [[NSString stringWithUTF8String:receipt] dataUsingEncoding:NSUTF8StringEncoding]; } // Billing store (not used ATM, maybe in the future). if (billingStore != NULL) { mBillingStore = [NSString stringWithUTF8String:billingStore]; } ADJSubscription *subscription = [[ADJSubscription alloc] initWithPrice:mPrice currency:mCurrency transactionId:mTransactionId andReceipt:mReceipt]; // Optional fields. // Transaction date. if (transactionDate != NULL) { NSTimeInterval transactionDateInterval = [[NSString stringWithUTF8String:transactionDate] doubleValue] / 1000.0; NSDate *oTransactionDate = [NSDate dateWithTimeIntervalSince1970:transactionDateInterval]; [subscription setTransactionDate:oTransactionDate]; } // Sales region. if (salesRegion != NULL) { NSString *oSalesRegion = [NSString stringWithUTF8String:salesRegion]; [subscription setSalesRegion:oSalesRegion]; } // Callback parameters. NSArray *arrayCallbackParameters = convertArrayParameters(jsonCallbackParameters); if (arrayCallbackParameters != nil) { NSUInteger count = [arrayCallbackParameters count]; for (int i = 0; i < count;) { NSString *key = arrayCallbackParameters[i++]; NSString *value = arrayCallbackParameters[i++]; [subscription addCallbackParameter:key value:value]; } } // Partner parameters. NSArray *arrayPartnerParameters = convertArrayParameters(jsonPartnerParameters); if (arrayPartnerParameters != nil) { NSUInteger count = [arrayPartnerParameters count]; for (int i = 0; i < count;) { NSString *key = arrayPartnerParameters[i++]; NSString *value = arrayPartnerParameters[i++]; [subscription addPartnerParameter:key value:value]; } } // Track subscription. [Adjust trackSubscription:subscription]; } void _AdjustTrackThirdPartySharing(int enabled, const char* jsonGranularOptions, const char* jsonPartnerSharingSettings) { NSNumber *nEnabled = enabled >= 0 ? [NSNumber numberWithInt:enabled] : nil; ADJThirdPartySharing *adjustThirdPartySharing = [[ADJThirdPartySharing alloc] initWithIsEnabledNumberBool:nEnabled]; NSArray *arrayGranularOptions = convertArrayParameters(jsonGranularOptions); if (arrayGranularOptions != nil) { NSUInteger count = [arrayGranularOptions count]; for (int i = 0; i < count;) { NSString *partnerName = arrayGranularOptions[i++]; NSString *granularOptions = arrayGranularOptions[i++]; // granularOptions is now NSString which pretty much contains array of partner key-value pairs if (granularOptions != nil) { NSData *dataJson = [granularOptions dataUsingEncoding:NSUTF8StringEncoding]; NSArray *partnerGranularOptions = [NSJSONSerialization JSONObjectWithData:dataJson options:0 error:nil]; if (partnerGranularOptions != nil) { // in here we have partner and key-value pair for it for (int j = 0; j < [partnerGranularOptions count];) { [adjustThirdPartySharing addGranularOption:partnerName key:partnerGranularOptions[j++] value:partnerGranularOptions[j++]]; } } } } } NSArray *arrayPartnerSharingSettings = convertArrayParameters(jsonPartnerSharingSettings); if (arrayPartnerSharingSettings != nil) { NSUInteger count = [arrayPartnerSharingSettings count]; for (int i = 0; i < count;) { NSString *partnerName = arrayPartnerSharingSettings[i++]; NSString *sharingSettings = arrayPartnerSharingSettings[i++]; // sharingSettings is now NSString which pretty much contains array of partner key-value pairs if (sharingSettings != nil) { NSData *dataJson = [sharingSettings dataUsingEncoding:NSUTF8StringEncoding]; NSArray *partnerSharingSettings = [NSJSONSerialization JSONObjectWithData:dataJson options:0 error:nil]; if (partnerSharingSettings != nil) { // in here we have partner and key-value pair for it for (int j = 0; j < [partnerSharingSettings count];) { [adjustThirdPartySharing addPartnerSharingSetting:partnerName key:partnerSharingSettings[j++] value:[partnerSharingSettings[j++] boolValue]]; } } } } } [Adjust trackThirdPartySharing:adjustThirdPartySharing]; } void _AdjustTrackMeasurementConsent(int enabled) { BOOL bEnabled = (BOOL)enabled; [Adjust trackMeasurementConsent:bEnabled]; } void _AdjustRequestTrackingAuthorizationWithCompletionHandler(const char* sceneName) { NSString *stringSceneName = isStringValid(sceneName) == true ? [NSString stringWithUTF8String:sceneName] : nil; if (stringSceneName == nil) { return; } [Adjust requestTrackingAuthorizationWithCompletionHandler:^(NSUInteger status) { NSString *stringStatus = [NSString stringWithFormat:@"%tu", status]; const char* charStatus = [stringStatus UTF8String]; UnitySendMessage([stringSceneName UTF8String], "GetAuthorizationStatus", charStatus); }]; } void _AdjustUpdateConversionValue(int conversionValue) { [Adjust updateConversionValue:conversionValue]; } void _AdjustUpdateConversionValueWithCallback(int conversionValue, const char* sceneName) { NSString *stringSceneName = isStringValid(sceneName) == true ? [NSString stringWithUTF8String:sceneName] : nil; [Adjust updatePostbackConversionValue:conversionValue completionHandler:^(NSError * _Nullable error) { if (stringSceneName == nil) { return; } NSString *errorString = [error description]; const char* errorChar = [errorString UTF8String]; UnitySendMessage([stringSceneName UTF8String], "GetNativeSkadCompletionDelegate", errorChar); }]; } void _AdjustUpdateConversionValueWithCallbackSkad4(int conversionValue, const char* coarseValue, int lockWindow, const char* sceneName) { NSString *stringSceneName = isStringValid(sceneName) == true ? [NSString stringWithUTF8String:sceneName] : nil; if (coarseValue != NULL) { NSString *stringCoarseValue = [NSString stringWithUTF8String:coarseValue]; BOOL bLockWindow = (BOOL)lockWindow; [Adjust updatePostbackConversionValue:conversionValue coarseValue:stringCoarseValue lockWindow:bLockWindow completionHandler:^(NSError * _Nullable error) { if (stringSceneName == nil) { return; } NSString *errorString = [error description]; const char* errorChar = [errorString UTF8String]; UnitySendMessage([stringSceneName UTF8String], "GetNativeSkad4CompletionDelegate", errorChar); }]; } } void _AdjustCheckForNewAttStatus() { [Adjust checkForNewAttStatus]; } int _AdjustGetAppTrackingAuthorizationStatus() { return [Adjust appTrackingAuthorizationStatus]; } char* _AdjustGetLastDeeplink() { NSURL *lastDeeplink = [Adjust lastDeeplink]; if (nil == lastDeeplink) { return NULL; } NSString *lastDeeplinkString = [lastDeeplink absoluteString]; if (nil == lastDeeplinkString) { return NULL; } const char* lastDeeplinkCString = [lastDeeplinkString UTF8String]; if (NULL == lastDeeplinkCString) { return NULL; } char* lastDeeplinkCStringCopy = strdup(lastDeeplinkCString); return lastDeeplinkCStringCopy; } void _AdjustVerifyAppStorePurchase(const char* transactionId, const char* productId, const char* receipt, const char* sceneName) { // Mandatory fields. NSString *strTransactionId; NSString *strProductId; NSData *dataReceipt; NSString *strSceneName; // Transaction ID. if (transactionId != NULL) { strTransactionId = [NSString stringWithUTF8String:transactionId]; } // Product ID. if (productId != NULL) { strProductId = [NSString stringWithUTF8String:productId]; } // Receipt. if (receipt != NULL) { NSString *stringReceiptBase64 = [NSString stringWithUTF8String:receipt]; dataReceipt = [[NSData alloc] initWithBase64EncodedString:stringReceiptBase64 options:0]; } // Scene name. strSceneName = isStringValid(sceneName) == true ? [NSString stringWithUTF8String:sceneName] : nil; // Verify the purchase. ADJPurchase *purchase = [[ADJPurchase alloc] initWithTransactionId:strTransactionId productId:strProductId andReceipt:dataReceipt]; [Adjust verifyPurchase:purchase completionHandler:^(ADJPurchaseVerificationResult * _Nonnull verificationResult) { if (strSceneName == nil) { return; } if (verificationResult == nil) { return; } NSMutableDictionary *dictionary = [NSMutableDictionary dictionary]; addValueOrEmpty(dictionary, @"verificationStatus", verificationResult.verificationStatus); addValueOrEmpty(dictionary, @"code", [NSString stringWithFormat:@"%d", verificationResult.code]); addValueOrEmpty(dictionary, @"message", verificationResult.message); NSData *dataVerificationInfo = [NSJSONSerialization dataWithJSONObject:dictionary options:0 error:nil]; NSString *strVerificationInfo = [[NSString alloc] initWithBytes:[dataVerificationInfo bytes] length:[dataVerificationInfo length] encoding:NSUTF8StringEncoding]; const char* verificationInfoCString = [strVerificationInfo UTF8String]; UnitySendMessage([strSceneName UTF8String], "GetNativeVerificationInfo", verificationInfoCString); }]; } void _AdjustProcessDeeplink(const char* url, const char* sceneName) { NSString *strSceneName = isStringValid(sceneName) == true ? [NSString stringWithUTF8String:sceneName] : nil; if (url != NULL) { NSString *stringUrl = [NSString stringWithUTF8String:url]; NSURL *nsUrl; if ([NSString instancesRespondToSelector:@selector(stringByAddingPercentEncodingWithAllowedCharacters:)]) { nsUrl = [NSURL URLWithString:[stringUrl stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLFragmentAllowedCharacterSet]]]; } else { #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wdeprecated-declarations" nsUrl = [NSURL URLWithString:[stringUrl stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]; } #pragma clang diagnostic pop [Adjust processDeeplink:nsUrl completionHandler:^(NSString * _Nonnull resolvedLink) { if (strSceneName == nil) { return; } if (resolvedLink == nil) { return; } const char* resolvedLinkCString = [resolvedLink UTF8String]; UnitySendMessage([strSceneName UTF8String], "GetNativeResolvedLink", resolvedLinkCString); }]; } } void _AdjustSetTestOptions(const char* overwriteUrl, const char* extraPath, long timerIntervalInMilliseconds, long timerStartInMilliseconds, long sessionIntervalInMilliseconds, long subsessionIntervalInMilliseconds, int teardown, int deleteState, int noBackoffWait, int adServicesFrameworkEnabled, int attStatus, const char *idfa) { AdjustTestOptions *testOptions = [[AdjustTestOptions alloc] init]; NSString *stringOverwriteUrl = isStringValid(overwriteUrl) == true ? [NSString stringWithUTF8String:overwriteUrl] : nil; if (stringOverwriteUrl != nil) { [testOptions setUrlOverwrite:stringOverwriteUrl]; } NSString *stringExtraPath = isStringValid(extraPath) == true ? [NSString stringWithUTF8String:extraPath] : nil; if (stringExtraPath != nil && [stringExtraPath length] > 0) { [testOptions setExtraPath:stringExtraPath]; } NSString *stringIdfa = isStringValid(idfa) == true ? [NSString stringWithUTF8String:idfa] : nil; if (stringIdfa != nil && [stringIdfa length] > 0) { [testOptions setIdfa:stringIdfa]; } testOptions.timerIntervalInMilliseconds = [NSNumber numberWithLong:timerIntervalInMilliseconds]; testOptions.timerStartInMilliseconds = [NSNumber numberWithLong:timerStartInMilliseconds]; testOptions.sessionIntervalInMilliseconds = [NSNumber numberWithLong:sessionIntervalInMilliseconds]; testOptions.subsessionIntervalInMilliseconds = [NSNumber numberWithLong:subsessionIntervalInMilliseconds]; testOptions.attStatusInt = [NSNumber numberWithInt:attStatus]; if (teardown != -1) { [AdjustUnityDelegate teardown]; [testOptions setTeardown:(BOOL)teardown]; } if (deleteState != -1) { [testOptions setDeleteState:(BOOL)deleteState]; } if (noBackoffWait != -1) { [testOptions setNoBackoffWait:(BOOL)noBackoffWait]; } if (adServicesFrameworkEnabled != -1) { [testOptions setAdServicesFrameworkEnabled:(BOOL)adServicesFrameworkEnabled]; } [Adjust setTestOptions:testOptions]; } }