From dce00c3d9c62b422489f1a14036f995afb603822 Mon Sep 17 00:00:00 2001 From: AppLovin-Mobile-Engineering Date: Mon, 22 Jul 2024 01:13:46 -0700 Subject: [PATCH] demoapp/bump_applovin_plugin_6.6.0 --- DemoApp/Assets/MaxSdk/AppLovin.meta | 5 +- DemoApp/Assets/MaxSdk/AppLovin/Editor.meta | 5 +- .../MaxSdk/AppLovin/Editor/Dependencies.xml | 4 +- DemoApp/Assets/MaxSdk/AppLovin/Plugins.meta | 5 +- .../MaxSdk/AppLovin/Plugins/Android.meta | 5 +- .../Android/applovin-max-unity-plugin.aar | Bin 76527 -> 43699 bytes .../Assets/MaxSdk/AppLovin/Plugins/iOS.meta | 5 +- .../AppLovin/Plugins/iOS/MAUnityAdManager.h | 4 +- .../AppLovin/Plugins/iOS/MAUnityAdManager.m | 42 +- .../AppLovin/Plugins/iOS/MAUnityPlugin.mm | 1063 ++++++++--------- DemoApp/Assets/MaxSdk/Prefabs.meta | 5 +- DemoApp/Assets/MaxSdk/Resources.meta | 5 +- DemoApp/Assets/MaxSdk/Resources/Images.meta | 5 +- DemoApp/Assets/MaxSdk/Scripts.meta | 5 +- .../Editor/AppLovinInitialize.cs | 10 +- .../Editor/AppLovinIntegrationManager.cs | 207 ++-- .../AppLovinIntegrationManagerWindow.cs | 65 +- .../Editor/AppLovinPostProcessAndroid.cs | 211 +++- .../Editor/AppLovinPostProcessiOS.cs | 334 +++--- .../Editor/AppLovinPreProcess.cs | 8 +- .../Editor/AppLovinPreProcessAndroid.cs | 141 --- DemoApp/Assets/MaxSdk/Scripts/MaxSdk.cs | 2 +- .../Assets/MaxSdk/Scripts/MaxSdkAndroid.cs | 95 +- DemoApp/Assets/MaxSdk/Scripts/MaxSdkBase.cs | 7 - .../MaxSdk/Scripts/MaxSdkUnityEditor.cs | 149 +-- DemoApp/Assets/MaxSdk/Scripts/MaxSdkiOS.cs | 132 +- .../MaxSdk/Scripts/MaxSegmentCollection.cs | 91 ++ ...a.cs.meta => MaxSegmentCollection.cs.meta} | 4 +- .../Assets/MaxSdk/Scripts/MaxTargetingData.cs | 142 --- .../Assets/MaxSdk/Scripts/MaxUserSegment.cs | 31 - .../MaxSdk/Scripts/MaxUserSegment.cs.meta | 14 - 31 files changed, 1209 insertions(+), 1592 deletions(-) create mode 100644 DemoApp/Assets/MaxSdk/Scripts/MaxSegmentCollection.cs rename DemoApp/Assets/MaxSdk/Scripts/{MaxTargetingData.cs.meta => MaxSegmentCollection.cs.meta} (69%) delete mode 100644 DemoApp/Assets/MaxSdk/Scripts/MaxTargetingData.cs delete mode 100644 DemoApp/Assets/MaxSdk/Scripts/MaxUserSegment.cs delete mode 100644 DemoApp/Assets/MaxSdk/Scripts/MaxUserSegment.cs.meta diff --git a/DemoApp/Assets/MaxSdk/AppLovin.meta b/DemoApp/Assets/MaxSdk/AppLovin.meta index 6b43b8f..898ec82 100644 --- a/DemoApp/Assets/MaxSdk/AppLovin.meta +++ b/DemoApp/Assets/MaxSdk/AppLovin.meta @@ -1,8 +1,5 @@ fileFormatVersion: 2 -guid: 34ab87748b3194154872145878ac2f1a -labels: -- al_max -- al_max_export_path-MaxSdk/AppLovin +guid: b35618a52c39d44acb9a664fd126d088 folderAsset: yes DefaultImporter: externalObjects: {} diff --git a/DemoApp/Assets/MaxSdk/AppLovin/Editor.meta b/DemoApp/Assets/MaxSdk/AppLovin/Editor.meta index 00149b6..93849a3 100644 --- a/DemoApp/Assets/MaxSdk/AppLovin/Editor.meta +++ b/DemoApp/Assets/MaxSdk/AppLovin/Editor.meta @@ -1,8 +1,5 @@ fileFormatVersion: 2 -guid: 85906f7a1338143339217b5e3e0b2071 -labels: -- al_max -- al_max_export_path-MaxSdk/AppLovin/Editor +guid: 7748a264370f84658948d02578b0258e folderAsset: yes DefaultImporter: externalObjects: {} diff --git a/DemoApp/Assets/MaxSdk/AppLovin/Editor/Dependencies.xml b/DemoApp/Assets/MaxSdk/AppLovin/Editor/Dependencies.xml index b3d8a7f..15f3595 100644 --- a/DemoApp/Assets/MaxSdk/AppLovin/Editor/Dependencies.xml +++ b/DemoApp/Assets/MaxSdk/AppLovin/Editor/Dependencies.xml @@ -1,9 +1,9 @@ - + - + diff --git a/DemoApp/Assets/MaxSdk/AppLovin/Plugins.meta b/DemoApp/Assets/MaxSdk/AppLovin/Plugins.meta index 074e52f..c6a65e5 100644 --- a/DemoApp/Assets/MaxSdk/AppLovin/Plugins.meta +++ b/DemoApp/Assets/MaxSdk/AppLovin/Plugins.meta @@ -1,8 +1,5 @@ fileFormatVersion: 2 -guid: bfdb65ad22ad247f1b008b818dd0c0cd -labels: -- al_max -- al_max_export_path-MaxSdk/AppLovin/Plugins +guid: dabd6e29359984561a3e2ffdf84505ee folderAsset: yes DefaultImporter: externalObjects: {} diff --git a/DemoApp/Assets/MaxSdk/AppLovin/Plugins/Android.meta b/DemoApp/Assets/MaxSdk/AppLovin/Plugins/Android.meta index dc0fdd5..1e4d90a 100644 --- a/DemoApp/Assets/MaxSdk/AppLovin/Plugins/Android.meta +++ b/DemoApp/Assets/MaxSdk/AppLovin/Plugins/Android.meta @@ -1,8 +1,5 @@ fileFormatVersion: 2 -guid: 9c0c3eb356aba459bac73f146806ea24 -labels: -- al_max -- al_max_export_path-MaxSdk/AppLovin/Plugins/Android +guid: 256c985e22a29411eb0001b67f088f11 folderAsset: yes DefaultImporter: externalObjects: {} diff --git a/DemoApp/Assets/MaxSdk/AppLovin/Plugins/Android/applovin-max-unity-plugin.aar b/DemoApp/Assets/MaxSdk/AppLovin/Plugins/Android/applovin-max-unity-plugin.aar index a9d7ad8fb52ccdb8128532093eb2282a5f27762c..8ce54e790ad2d6a873bc2fec9d17e05744724b1a 100644 GIT binary patch delta 42817 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 diff --git a/DemoApp/Assets/MaxSdk/AppLovin/Plugins/iOS.meta b/DemoApp/Assets/MaxSdk/AppLovin/Plugins/iOS.meta index 2fcc609..9d22b84 100644 --- a/DemoApp/Assets/MaxSdk/AppLovin/Plugins/iOS.meta +++ b/DemoApp/Assets/MaxSdk/AppLovin/Plugins/iOS.meta @@ -1,8 +1,5 @@ fileFormatVersion: 2 -guid: f71194dd18cd847de88d610ecb794428 -labels: -- al_max -- al_max_export_path-MaxSdk/AppLovin/Plugins/iOS +guid: f531d9362702740229d174299a59e30f folderAsset: yes DefaultImporter: externalObjects: {} diff --git a/DemoApp/Assets/MaxSdk/AppLovin/Plugins/iOS/MAUnityAdManager.h b/DemoApp/Assets/MaxSdk/AppLovin/Plugins/iOS/MAUnityAdManager.h index f5a250e..debdd3c 100644 --- a/DemoApp/Assets/MaxSdk/AppLovin/Plugins/iOS/MAUnityAdManager.h +++ b/DemoApp/Assets/MaxSdk/AppLovin/Plugins/iOS/MAUnityAdManager.h @@ -12,7 +12,7 @@ typedef void (*ALUnityBackgroundCallback)(const char* args); @interface MAUnityAdManager : NSObject -- (ALSdk *)initializeSdkWithSettings:(ALSdkSettings *)settings backgroundCallback:(ALUnityBackgroundCallback)unityBackgroundCallback andCompletionHandler:(ALSdkInitializationCompletionHandler)completionHandler; +- (void)initializeSdkWithConfiguration:(ALSdkInitializationConfiguration *)initConfig andCompletionHandler:(ALSdkInitializationCompletionHandler)completionHandler; - (void)createBannerWithAdUnitIdentifier:(nullable NSString *)adUnitIdentifier atPosition:(nullable NSString *)bannerPosition; - (void)createBannerWithAdUnitIdentifier:(nullable NSString *)adUnitIdentifier x:(CGFloat)xOffset y:(CGFloat)yOffset; @@ -92,6 +92,8 @@ typedef void (*ALUnityBackgroundCallback)(const char* args); + (NSString *)serializeParameters:(NSDictionary *)dict; + (NSDictionary *)deserializeParameters:(nullable NSString *)serialized; ++ (void)setUnityBackgroundCallback:(ALUnityBackgroundCallback)unityBackgroundCallback; + /** * Creates an instance of @c MAUnityAdManager if needed and returns the singleton instance. */ diff --git a/DemoApp/Assets/MaxSdk/AppLovin/Plugins/iOS/MAUnityAdManager.m b/DemoApp/Assets/MaxSdk/AppLovin/Plugins/iOS/MAUnityAdManager.m index 36c28d2..8cd0437 100644 --- a/DemoApp/Assets/MaxSdk/AppLovin/Plugins/iOS/MAUnityAdManager.m +++ b/DemoApp/Assets/MaxSdk/AppLovin/Plugins/iOS/MAUnityAdManager.m @@ -5,8 +5,6 @@ #import "MAUnityAdManager.h" -#define VERSION @"6.5.2" - #define KEY_WINDOW [UIApplication sharedApplication].keyWindow #define DEVICE_SPECIFIC_ADVIEW_AD_FORMAT ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) ? MAAdFormat.leader : MAAdFormat.banner #define IS_VERTICAL_BANNER_POSITION(_POS) ( [@"center_left" isEqual: adViewPosition] || [@"center_right" isEqual: adViewPosition] ) @@ -193,29 +191,19 @@ + (MAUnityAdManager *)shared return shared; } ++ (void)setUnityBackgroundCallback:(ALUnityBackgroundCallback)unityBackgroundCallback +{ + backgroundCallback = unityBackgroundCallback; +} + #pragma mark - Plugin Initialization -- (ALSdk *)initializeSdkWithSettings:(ALSdkSettings *)settings - backgroundCallback:(ALUnityBackgroundCallback)unityBackgroundCallback - andCompletionHandler:(ALSdkInitializationCompletionHandler)completionHandler +- (void)initializeSdkWithConfiguration:(ALSdkInitializationConfiguration *)initConfig andCompletionHandler:(ALSdkInitializationCompletionHandler)completionHandler; { - backgroundCallback = unityBackgroundCallback; - NSDictionary *infoDict = [[NSBundle mainBundle] infoDictionary]; - NSString *sdkKey = infoDict[@"AppLovinSdkKey"]; - if ( [sdkKey al_isValidString] ) - { - self.sdk = [ALSdk sharedWithKey: sdkKey settings: settings]; - } - else - { - self.sdk = [ALSdk sharedWithSettings: settings]; - } - - [self.sdk setPluginVersion: [@"Max-Unity-" stringByAppendingString: VERSION]]; - self.sdk.mediationProvider = @"max"; - [self.sdk initializeSdkWithCompletionHandler:^(ALSdkConfiguration *configuration) - { + self.sdk = [ALSdk shared]; + [self.sdk initializeWithConfiguration: initConfig completionHandler:^(ALSdkConfiguration *configuration) { dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + // Note: internal state should be updated first completionHandler( configuration ); @@ -231,8 +219,6 @@ - (ALSdk *)initializeSdkWithSettings:(ALSdkSettings *)settings @"isTestModeEnabled" : @([configuration isTestModeEnabled])}]; }); }]; - - return self.sdk; } #pragma mark - Banners @@ -1029,16 +1015,6 @@ - (void)didCollapseAd:(MAAd *)ad }); } -- (void)didStartRewardedVideoForAd:(MAAd *)ad -{ - // This event is not forwarded -} - -- (void)didCompleteRewardedVideoForAd:(MAAd *)ad -{ - // This event is not forwarded -} - - (void)didRewardUserForAd:(MAAd *)ad withReward:(MAReward *)reward { dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ diff --git a/DemoApp/Assets/MaxSdk/AppLovin/Plugins/iOS/MAUnityPlugin.mm b/DemoApp/Assets/MaxSdk/AppLovin/Plugins/iOS/MAUnityPlugin.mm index 7ca2561..d5f161d 100644 --- a/DemoApp/Assets/MaxSdk/AppLovin/Plugins/iOS/MAUnityPlugin.mm +++ b/DemoApp/Assets/MaxSdk/AppLovin/Plugins/iOS/MAUnityPlugin.mm @@ -8,6 +8,7 @@ #import "MAUnityAdManager.h" +#define VERSION @"6.6.0" #define NSSTRING(_X) ( (_X != NULL) ? [NSString stringWithCString: _X encoding: NSStringEncodingConversionAllowLossy].al_stringByTrimmingWhitespace : nil) @interface NSString (ALUtils) @@ -15,72 +16,72 @@ @interface NSString (ALUtils) @property (assign, readonly, getter=al_isValidString) BOOL al_validString; @end +@interface ALSdkInitializationConfigurationBuilder (ALUtils) +- (void)setSdkKey:(NSString *)sdkKey; +@end + // When native code plugin is implemented in .mm / .cpp file, then functions // should be surrounded with extern "C" block to conform C function naming rules extern "C" { static NSString *const TAG = @"MAUnityPlugin"; - + static NSString *const KeySdkKey = @"SdkKey"; + UIView* UnityGetGLView(); + NSString *getSdkKeyFromAppLovinSettingsPlist(); + static ALSdkInitializationConfigurationBuilder *_initConfigurationBuilder; static ALSdk *_sdk; static MAUnityAdManager *_adManager; - static bool _isPluginInitialized = false; + static bool _isSdkInitialized = false; - static ALSdkConfiguration *_sdkConfiguration; - - // Store these values if pub attempts to set it before calling _MaxInitializeSdk() - static NSString *_userIdentifierToSet; - static NSString *_userSegmentNameToSet; - static NSArray *_testDeviceIdentifiersToSet; - static NSNumber *_mutedToSet; - static NSNumber *_verboseLoggingToSet; - static NSNumber *_creativeDebuggerEnabledToSet; - static NSNumber *_exceptionHandlerEnabledToSet; - static NSNumber *_locationCollectionEnabledToSet; - static NSNumber *_targetingYearOfBirth; - static NSString *_targetingGender; - static NSNumber *_targetingMaximumAdContentRating; - static NSString *_targetingEmail; - static NSString *_targetingPhoneNumber; - static NSArray *_targetingKeywords; - static NSArray *_targetingInterests; - static NSMutableDictionary *_extraParametersToSet = [NSMutableDictionary dictionary]; - static NSObject *_extraParametersToSetLock = [[NSObject alloc] init]; + static bool _initializeSdkCalled = false; // Helper method to create C string copy static const char * cStringCopy(NSString *string); // Helper method to log errors void logUninitializedAccessError(const char *callingMethod); - int getConsentStatusValue(NSNumber *consentStatus) + ALSdkInitializationConfigurationBuilder *getInitConfigurationBuilder() { - if ( consentStatus ) + if ( !_initConfigurationBuilder ) { - return consentStatus.intValue; - } - else - { - return -1; + _initConfigurationBuilder = [ALSdkInitializationConfiguration builderWithSdkKey: getSdkKeyFromAppLovinSettingsPlist()]; } + + return _initConfigurationBuilder; } - - bool isPluginInitialized() + + ALSdk *getSdk() { - return _isPluginInitialized; + if ( !_sdk ) + { + _sdk = [ALSdk shared]; + } + + return _sdk; } - bool isReadyToInteractWithSdk() + MAUnityAdManager *getAdManager() { - return isPluginInitialized() && _sdk; + if ( !_adManager ) + { + _adManager = [MAUnityAdManager shared]; + } + + return _adManager; } - - void maybeInitializePlugin() + + int getConsentStatusValue(NSNumber *consentStatus) { - if ( isPluginInitialized() ) return; - - _adManager = [MAUnityAdManager shared]; - _isPluginInitialized = true; + if ( consentStatus ) + { + return consentStatus.intValue; + } + else + { + return -1; + } } id getLocalExtraParameterValue(const char *json) @@ -115,217 +116,87 @@ id getLocalExtraParameterValue(const char *json) return array; } - - void setPendingExtraParametersIfNeeded(ALSdkSettings *settings) + + NSString *getSdkKeyFromAppLovinSettingsPlist() { - NSDictionary *extraParameters; - @synchronized ( _extraParametersToSetLock ) - { - if ( _extraParametersToSet.count <= 0 ) return; - - extraParameters = [NSDictionary dictionaryWithDictionary: _extraParametersToSet]; - [_extraParametersToSet removeAllObjects]; - } + NSString *settingsPlistResourceURL = [NSBundle.mainBundle pathForResource: @"AppLovin-Settings" ofType: @"plist"]; + NSDictionary *sdkSettingsFromPlist = settingsPlistResourceURL ? [[NSDictionary alloc] initWithContentsOfFile: settingsPlistResourceURL] : @{}; - for ( NSString *key in extraParameters.allKeys ) - { - [settings setExtraParameterForKey: key value: extraParameters[key]]; - } + return [sdkSettingsFromPlist al_stringForKey: KeySdkKey]; } - - ALSdkSettings * generateSDKSettings(const char *serializedAdUnitIdentifiers, const char *serializedMetaData) - { - ALSdkSettings *settings = [[ALSdkSettings alloc] init]; - - setPendingExtraParametersIfNeeded( settings ); - - if ( _testDeviceIdentifiersToSet ) - { - settings.testDeviceAdvertisingIdentifiers = _testDeviceIdentifiersToSet; - _testDeviceIdentifiersToSet = nil; - } - - if ( _mutedToSet != nil) - { - settings.muted = _mutedToSet.boolValue; - _mutedToSet = nil; - } - - if ( _verboseLoggingToSet != nil ) - { - settings.verboseLoggingEnabled = _verboseLoggingToSet.boolValue; - _verboseLoggingToSet = nil; - } - if ( _creativeDebuggerEnabledToSet != nil ) - { - settings.creativeDebuggerEnabled = _creativeDebuggerEnabledToSet.boolValue; - _creativeDebuggerEnabledToSet = nil; - } - - if ( _exceptionHandlerEnabledToSet != nil ) - { - settings.exceptionHandlerEnabled = _exceptionHandlerEnabledToSet.boolValue; - _exceptionHandlerEnabledToSet = nil; - } - - if ( _locationCollectionEnabledToSet != nil ) - { - settings.locationCollectionEnabled = _locationCollectionEnabledToSet.boolValue; - _locationCollectionEnabledToSet = nil; - } - - settings.initializationAdUnitIdentifiers = [[NSString stringWithUTF8String: serializedAdUnitIdentifiers] componentsSeparatedByString: @","]; + MASegmentCollection *getSegmentCollection(const char *collectionJson) + { + MASegmentCollectionBuilder *segmentCollectionBuilder = [MASegmentCollection builder]; - NSDictionary *unityMetaData = [MAUnityAdManager deserializeParameters: [NSString stringWithUTF8String: serializedMetaData]]; + NSDictionary *jsonDict = [MAUnityAdManager deserializeParameters: [NSString stringWithUTF8String: collectionJson]]; - // Set the meta data to settings. - NSMutableDictionary *metaDataDict = [settings valueForKey: @"metaData"]; - for ( NSString *key in unityMetaData ) + NSArray *segmentsArray = jsonDict[@"segments"]; + for (NSDictionary *segmentDict in segmentsArray) { - metaDataDict[key] = unityMetaData[key]; + NSNumber *key = segmentDict[@"key"]; + NSArray *valuesArray = segmentDict[@"values"]; + NSMutableArray *values = [NSMutableArray array]; + for (NSNumber *value in valuesArray) + { + [values addObject:value]; + } + + MASegment *segment = [[MASegment alloc] initWithKey:key values:values]; + [segmentCollectionBuilder addSegment:segment]; } - return settings; + return [segmentCollectionBuilder build]; } - ALGender getAppLovinGender(NSString *genderString) + void _MaxSetBackgroundCallback(ALUnityBackgroundCallback backgroundCallback) { - if ( [@"F" al_isEqualToStringIgnoringCase: genderString] ) - { - return ALGenderFemale; - } - else if ( [@"M" al_isEqualToStringIgnoringCase: genderString] ) - { - return ALGenderMale; - } - else if ( [@"O" al_isEqualToStringIgnoringCase: genderString] ) - { - return ALGenderOther; - } - - return ALGenderUnknown; + [MAUnityAdManager setUnityBackgroundCallback: backgroundCallback]; } - ALAdContentRating getAppLovinAdContentRating(int maximumAdContentRating) - { - if ( maximumAdContentRating == 1 ) - { - return ALAdContentRatingAllAudiences; - } - else if ( maximumAdContentRating == 2 ) - { - return ALAdContentRatingEveryoneOverTwelve; - } - else if ( maximumAdContentRating == 3 ) - { - return ALAdContentRatingMatureAudiences; - } - - return ALAdContentRatingNone; - } - void _MaxSetSdkKey(const char *sdkKey) { - maybeInitializePlugin(); - if (!sdkKey) return; NSString *sdkKeyStr = [NSString stringWithUTF8String: sdkKey]; - - NSDictionary *infoDict = [[NSBundle mainBundle] infoDictionary]; - [infoDict setValue: sdkKeyStr forKey: @"AppLovinSdkKey"]; + [getInitConfigurationBuilder() setSdkKey: sdkKeyStr]; } - void _MaxInitializeSdk(const char *serializedAdUnitIdentifiers, const char *serializedMetaData, ALUnityBackgroundCallback backgroundCallback) + void _MaxInitializeSdk(const char *serializedAdUnitIdentifiers, const char *serializedMetaData) { - maybeInitializePlugin(); - - _sdk = [_adManager initializeSdkWithSettings: generateSDKSettings(serializedAdUnitIdentifiers, serializedMetaData) - backgroundCallback: backgroundCallback - andCompletionHandler:^(ALSdkConfiguration *configuration) { - _sdkConfiguration = configuration; - _isSdkInitialized = true; - }]; - - if ( _userIdentifierToSet ) - { - _sdk.userIdentifier = _userIdentifierToSet; - _userIdentifierToSet = nil; - } - - if ( _userSegmentNameToSet ) - { - _sdk.userSegment.name = _userSegmentNameToSet; - _userSegmentNameToSet = nil; - } + ALSdkInitializationConfigurationBuilder *initConfigurationBuilder = getInitConfigurationBuilder(); + initConfigurationBuilder.mediationProvider = @"max"; + initConfigurationBuilder.pluginVersion = [@"Max-Unity-" stringByAppendingString: VERSION]; + initConfigurationBuilder.adUnitIdentifiers = [[NSString stringWithUTF8String: serializedAdUnitIdentifiers] componentsSeparatedByString: @","]; - if ( _targetingYearOfBirth != nil ) - { - _sdk.targetingData.yearOfBirth = _targetingYearOfBirth.intValue <= 0 ? nil : _targetingYearOfBirth; - _targetingYearOfBirth = nil; - } + [getSdk().settings setExtraParameterForKey: @"applovin_unity_metadata" value: NSSTRING(serializedMetaData)]; - if ( _targetingGender ) - { - _sdk.targetingData.gender = getAppLovinGender(_targetingGender); - _targetingGender = nil; - } + ALSdkInitializationConfiguration *initConfig = [initConfigurationBuilder build]; - if ( _targetingMaximumAdContentRating != nil ) - { - _sdk.targetingData.maximumAdContentRating = getAppLovinAdContentRating(_targetingMaximumAdContentRating.intValue); - _targetingMaximumAdContentRating = nil; - } - - if ( _targetingEmail ) - { - _sdk.targetingData.email = _targetingEmail; - _targetingEmail = nil; - } - - if ( _targetingPhoneNumber ) - { - _sdk.targetingData.phoneNumber = _targetingPhoneNumber; - _targetingPhoneNumber = nil; - } - - if ( _targetingKeywords ) - { - _sdk.targetingData.keywords = _targetingKeywords; - _targetingKeywords = nil; - } + [getAdManager() initializeSdkWithConfiguration: initConfig andCompletionHandler:^(ALSdkConfiguration *configuration) { + _isSdkInitialized = true; + }]; - if ( _targetingInterests ) - { - _sdk.targetingData.interests = _targetingInterests; - _targetingInterests = nil; - } + _initializeSdkCalled = true; } bool _MaxIsInitialized() { - return _isPluginInitialized && _isSdkInitialized; + return _isSdkInitialized; } const char * _MaxGetAvailableMediatedNetworks() { - if ( !_sdk ) - { - NSLog(@"[%@] Failed to get available mediated networks - please ensure the AppLovin MAX Unity Plugin has been initialized by calling 'MaxSdk.InitializeSdk();'!", TAG); - return cStringCopy(@""); - } - - NSArray *availableMediatedNetworks = [_sdk availableMediatedNetworks]; + NSArray *availableMediatedNetworks = [getSdk() availableMediatedNetworks]; // Create array of serialized network strings NSMutableArray *> *serializedNetworks = [NSMutableArray arrayWithCapacity: availableMediatedNetworks.count]; for ( MAMediatedNetworkInfo *mediatedNetwork in availableMediatedNetworks ) { NSDictionary *mediatedNetworkDictionary = @{@"name" : mediatedNetwork.name, - @"adapterClassName" : mediatedNetwork.adapterClassName, - @"adapterVersion" : mediatedNetwork.adapterVersion, - @"sdkVersion" : mediatedNetwork.sdkVersion}; + @"adapterClassName" : mediatedNetwork.adapterClassName, + @"adapterVersion" : mediatedNetwork.adapterVersion, + @"sdkVersion" : mediatedNetwork.sdkVersion}; [serializedNetworks addObject: mediatedNetworkDictionary]; } @@ -335,24 +206,24 @@ bool _MaxIsInitialized() void _MaxShowMediationDebugger() { - if ( !_sdk ) + if ( !_initializeSdkCalled ) { NSLog(@"[%@] Failed to show mediation debugger - please ensure the AppLovin MAX Unity Plugin has been initialized by calling 'MaxSdk.InitializeSdk();'!", TAG); return; } - [_sdk showMediationDebugger]; + [getSdk() showMediationDebugger]; } void _MaxShowCreativeDebugger() { - if ( !_sdk ) + if ( !_initializeSdkCalled ) { NSLog(@"[%@] Failed to show creative debugger - please ensure the AppLovin MAX Unity Plugin has been initialized by calling 'MaxSdk.InitializeSdk();'!", TAG); return; } - [_sdk showCreativeDebugger]; + [getSdk() showCreativeDebugger]; } void _MaxShowConsentDialog() @@ -362,153 +233,45 @@ void _MaxShowConsentDialog() int _MaxConsentDialogState() { - if (!isPluginInitialized()) return ALConsentDialogStateUnknown; + if ( !_isSdkInitialized ) return ALConsentDialogStateUnknown; - return (int) _sdkConfiguration.consentDialogState; + return (int) getSdk().configuration.consentDialogState; } void _MaxSetUserId(const char *userId) { - if ( _sdk ) - { - _sdk.userIdentifier = NSSTRING(userId); - } - else - { - _userIdentifierToSet = NSSTRING(userId); - } - } - - void _MaxSetUserSegmentField(const char *serializedKey, const char *serializedValue) - { - // NSString *key = NSSTRING(serializedKey); // To be ignored until we add more properties - NSString *value = NSSTRING(serializedValue); - - if ( _sdk ) - { - _sdk.userSegment.name = value; - } - else - { - _userSegmentNameToSet = value; - } - } - - void _MaxSetTargetingDataYearOfBirth(const int yearOfBirth) - { - if ( !_sdk ) - { - _targetingYearOfBirth = @(yearOfBirth); - return; - } - - _sdk.targetingData.yearOfBirth = yearOfBirth <= 0 ? nil : @(yearOfBirth); - } - - void _MaxSetTargetingDataGender(char *gender) - { - if ( !_sdk ) - { - _targetingGender = NSSTRING(gender); - return; - } - - NSString *genderString = NSSTRING(gender); - _sdk.targetingData.gender = getAppLovinGender(genderString); + getSdk().settings.userIdentifier = NSSTRING(userId); } - void _MaxSetTargetingDataMaximumAdContentRating(const int maximumAdContentRating) + void _MaxSetSegmentCollection(const char *collectionJson) { - if ( !_sdk ) - { - _targetingMaximumAdContentRating = @(maximumAdContentRating); - return; - } - - _sdk.targetingData.maximumAdContentRating = getAppLovinAdContentRating(maximumAdContentRating); - } - - void _MaxSetTargetingDataEmail(char *email) - { - if ( !_sdk ) + if ( _initializeSdkCalled ) { - _targetingEmail = NSSTRING(email); + NSLog(@"[%@] Segment collection must be set before MAX SDK is initialized", TAG); return; } - _sdk.targetingData.email = NSSTRING(email); - } - - void _MaxSetTargetingDataPhoneNumber(char *phoneNumber) - { - if ( !_sdk ) - { - _targetingPhoneNumber = NSSTRING(phoneNumber); - return; - } - - _sdk.targetingData.phoneNumber = NSSTRING(phoneNumber); - } - - void _MaxSetTargetingDataKeywords(char **keywords, int size) - { - NSArray *keywordsArray = keywords ? toStringArray(keywords, size) : nil; - if ( !_sdk ) - { - _targetingKeywords = keywordsArray; - return; - } - - _sdk.targetingData.keywords = keywordsArray; - } - - void _MaxSetTargetingDataInterests(char **interests, int size) - { - NSArray *interestsArray = interests ? toStringArray(interests, size) : nil; - if ( !_sdk ) - { - _targetingInterests = interestsArray; - return; - } - - _sdk.targetingData.interests = interestsArray; - } - - void _MaxClearAllTargetingData() - { - if ( !_sdk ) - { - _targetingYearOfBirth = nil; - _targetingGender = nil; - _targetingMaximumAdContentRating = nil; - _targetingEmail = nil; - _targetingPhoneNumber = nil; - _targetingKeywords = nil; - _targetingInterests = nil; - return; - } - - [_sdk.targetingData clearAll]; + getInitConfigurationBuilder().segmentCollection = getSegmentCollection(collectionJson); } const char * _MaxGetSdkConfiguration() { - if ( !_sdk ) + if ( !_initializeSdkCalled ) { logUninitializedAccessError("_MaxGetSdkConfiguration"); return cStringCopy(@""); } - NSString *consentFlowUserGeographyStr = @(_sdk.configuration.consentFlowUserGeography).stringValue; - NSString *consentDialogStateStr = @(_sdk.configuration.consentDialogState).stringValue; - NSString *appTrackingStatus = @(_sdk.configuration.appTrackingTransparencyStatus).stringValue; // Deliberately name it `appTrackingStatus` to be a bit more generic (in case Android introduces a similar concept) + NSString *consentFlowUserGeographyStr = @(getSdk().configuration.consentFlowUserGeography).stringValue; + NSString *consentDialogStateStr = @(getSdk().configuration.consentDialogState).stringValue; + NSString *appTrackingStatus = @(getSdk().configuration.appTrackingTransparencyStatus).stringValue; // Deliberately name it `appTrackingStatus` to be a bit more generic (in case Android introduces a similar concept) return cStringCopy([MAUnityAdManager serializeParameters: @{@"consentFlowUserGeography" : consentFlowUserGeographyStr, @"consentDialogState" : consentDialogStateStr, - @"countryCode" : _sdk.configuration.countryCode, + @"countryCode" : getSdk().configuration.countryCode, @"appTrackingStatus" : appTrackingStatus, - @"isSuccessfullyInitialized" : @([_sdk isInitialized]), - @"isTestModeEnabled" : @([_sdk.configuration isTestModeEnabled])}]); + @"isSuccessfullyInitialized" : @([getSdk() isInitialized]), + @"isTestModeEnabled" : @([getSdk().configuration isTestModeEnabled])}]); } void _MaxSetHasUserConsent(bool hasUserConsent) @@ -558,463 +321,693 @@ bool _MaxIsDoNotSellSet() void _MaxCreateBanner(const char *adUnitIdentifier, const char *bannerPosition) { - if (!isPluginInitialized()) return; + if ( !_initializeSdkCalled ) + { + logUninitializedAccessError("_MaxCreateBanner"); + return; + } - [_adManager createBannerWithAdUnitIdentifier: NSSTRING(adUnitIdentifier) atPosition: NSSTRING(bannerPosition)]; + [getAdManager() createBannerWithAdUnitIdentifier: NSSTRING(adUnitIdentifier) atPosition: NSSTRING(bannerPosition)]; } void _MaxCreateBannerXY(const char *adUnitIdentifier, const float x, const float y) { - if (!isPluginInitialized()) return; + if ( !_initializeSdkCalled ) + { + logUninitializedAccessError("_MaxCreateBannerXY"); + return; + } - [_adManager createBannerWithAdUnitIdentifier: NSSTRING(adUnitIdentifier) x: x y: y]; + [getAdManager() createBannerWithAdUnitIdentifier: NSSTRING(adUnitIdentifier) x: x y: y]; } void _MaxLoadBanner(const char *adUnitIdentifier) { - if (!isPluginInitialized()) return; - - [_adManager loadBannerWithAdUnitIdentifier: NSSTRING(adUnitIdentifier)]; + if ( !_initializeSdkCalled ) + { + logUninitializedAccessError("_MaxLoadBanner"); + return; + } + + [getAdManager() loadBannerWithAdUnitIdentifier: NSSTRING(adUnitIdentifier)]; } void _MaxSetBannerBackgroundColor(const char *adUnitIdentifier, const char *hexColorCode) { - if (!isPluginInitialized()) return; + if ( !_initializeSdkCalled ) + { + logUninitializedAccessError("_MaxSetBannerBackgroundColor"); + return; + } - [_adManager setBannerBackgroundColorForAdUnitIdentifier: NSSTRING(adUnitIdentifier) hexColorCode: NSSTRING(hexColorCode)]; + [getAdManager() setBannerBackgroundColorForAdUnitIdentifier: NSSTRING(adUnitIdentifier) hexColorCode: NSSTRING(hexColorCode)]; } void _MaxSetBannerPlacement(const char *adUnitIdentifier, const char *placement) { - [_adManager setBannerPlacement: NSSTRING(placement) forAdUnitIdentifier: NSSTRING(adUnitIdentifier)]; + if ( !_initializeSdkCalled ) + { + logUninitializedAccessError("_MaxSetBannerPlacement"); + return; + } + + [getAdManager() setBannerPlacement: NSSTRING(placement) forAdUnitIdentifier: NSSTRING(adUnitIdentifier)]; } void _MaxStartBannerAutoRefresh(const char *adUnitIdentifier) { - if (!isPluginInitialized()) return; + if ( !_initializeSdkCalled ) + { + logUninitializedAccessError("_MaxStartBannerAutoRefresh"); + return; + } - [_adManager startBannerAutoRefreshForAdUnitIdentifier: NSSTRING(adUnitIdentifier)]; + [getAdManager() startBannerAutoRefreshForAdUnitIdentifier: NSSTRING(adUnitIdentifier)]; } void _MaxStopBannerAutoRefresh(const char *adUnitIdentifier) { - if (!isPluginInitialized()) return; + if ( !_initializeSdkCalled ) + { + logUninitializedAccessError("_MaxStopBannerAutoRefresh"); + return; + } - [_adManager stopBannerAutoRefreshForAdUnitIdentifier: NSSTRING(adUnitIdentifier)]; + [getAdManager() stopBannerAutoRefreshForAdUnitIdentifier: NSSTRING(adUnitIdentifier)]; } void _MaxSetBannerExtraParameter(const char *adUnitIdentifier, const char *key, const char *value) { - [_adManager setBannerExtraParameterForAdUnitIdentifier: NSSTRING(adUnitIdentifier) - key: NSSTRING(key) - value: NSSTRING(value)]; + if ( !_initializeSdkCalled ) + { + logUninitializedAccessError("_MaxSetBannerExtraParameter"); + return; + } + + [getAdManager() setBannerExtraParameterForAdUnitIdentifier: NSSTRING(adUnitIdentifier) + key: NSSTRING(key) + value: NSSTRING(value)]; } void _MaxSetBannerLocalExtraParameter(const char *adUnitIdentifier, const char *key, MAUnityRef value) { - if ( !isReadyToInteractWithSdk() ) + if ( !_initializeSdkCalled ) { logUninitializedAccessError("_MaxSetBannerLocalExtraParameter"); + return; } - [_adManager setBannerLocalExtraParameterForAdUnitIdentifier: NSSTRING(adUnitIdentifier) - key: NSSTRING(key) - value: (__bridge id) value]; + [getAdManager() setBannerLocalExtraParameterForAdUnitIdentifier: NSSTRING(adUnitIdentifier) + key: NSSTRING(key) + value: (__bridge id) value]; } void _MaxSetBannerLocalExtraParameterJSON(const char *adUnitIdentifier, const char *key, const char *json) { - if ( !isReadyToInteractWithSdk() ) + if ( !_initializeSdkCalled ) { logUninitializedAccessError("_MaxSetBannerLocalExtraParameter"); + return; } id value = getLocalExtraParameterValue(json); - [_adManager setBannerLocalExtraParameterForAdUnitIdentifier: NSSTRING(adUnitIdentifier) - key: NSSTRING(key) - value: value]; + [getAdManager() setBannerLocalExtraParameterForAdUnitIdentifier: NSSTRING(adUnitIdentifier) + key: NSSTRING(key) + value: value]; } void _MaxSetBannerCustomData(const char *adUnitIdentifier, const char *customData) { - [_adManager setBannerCustomData: NSSTRING(customData) forAdUnitIdentifier: NSSTRING(adUnitIdentifier)]; + if ( !_initializeSdkCalled ) + { + logUninitializedAccessError("_MaxSetBannerCustomData"); + return; + } + + [getAdManager() setBannerCustomData: NSSTRING(customData) forAdUnitIdentifier: NSSTRING(adUnitIdentifier)]; } void _MaxSetBannerWidth(const char *adUnitIdentifier, const float width) { - [_adManager setBannerWidth: width forAdUnitIdentifier: NSSTRING(adUnitIdentifier)]; + if ( !_initializeSdkCalled ) + { + logUninitializedAccessError("_MaxSetBannerWidth"); + return; + } + + [getAdManager() setBannerWidth: width forAdUnitIdentifier: NSSTRING(adUnitIdentifier)]; } void _MaxUpdateBannerPosition(const char *adUnitIdentifier, const char *bannerPosition) { - [_adManager updateBannerPosition: NSSTRING(bannerPosition) forAdUnitIdentifier: NSSTRING(adUnitIdentifier)]; + if ( !_initializeSdkCalled ) + { + logUninitializedAccessError("_MaxUpdateBannerPosition"); + return; + } + + [getAdManager() updateBannerPosition: NSSTRING(bannerPosition) forAdUnitIdentifier: NSSTRING(adUnitIdentifier)]; } void _MaxUpdateBannerPositionXY(const char *adUnitIdentifier, const float x, const float y) { - [_adManager updateBannerPosition: x y: y forAdUnitIdentifier: NSSTRING(adUnitIdentifier)]; + if ( !_initializeSdkCalled ) + { + logUninitializedAccessError("_MaxUpdateBannerPositionXY"); + return; + } + + [getAdManager() updateBannerPosition: x y: y forAdUnitIdentifier: NSSTRING(adUnitIdentifier)]; } void _MaxShowBanner(const char *adUnitIdentifier) { - if (!isPluginInitialized()) return; + if ( !_initializeSdkCalled ) + { + logUninitializedAccessError("_MaxShowBanner"); + return; + } - [_adManager showBannerWithAdUnitIdentifier: NSSTRING(adUnitIdentifier)]; + [getAdManager() showBannerWithAdUnitIdentifier: NSSTRING(adUnitIdentifier)]; } void _MaxDestroyBanner(const char *adUnitIdentifier) { - if (!isPluginInitialized()) return; + if ( !_initializeSdkCalled ) + { + logUninitializedAccessError("_MaxDestroyBanner"); + return; + } - [_adManager destroyBannerWithAdUnitIdentifier: NSSTRING(adUnitIdentifier)]; + [getAdManager() destroyBannerWithAdUnitIdentifier: NSSTRING(adUnitIdentifier)]; } void _MaxHideBanner(const char *adUnitIdentifier) { - if (!isPluginInitialized()) return; + if ( !_initializeSdkCalled ) + { + logUninitializedAccessError("_MaxHideBanner"); + return; + } - [_adManager hideBannerWithAdUnitIdentifier: NSSTRING(adUnitIdentifier)]; + [getAdManager() hideBannerWithAdUnitIdentifier: NSSTRING(adUnitIdentifier)]; } const char * _MaxGetBannerLayout(const char *adUnitIdentifier) { - if (!isPluginInitialized()) return cStringCopy(@""); - - return cStringCopy([_adManager bannerLayoutForAdUnitIdentifier: NSSTRING(adUnitIdentifier)]); + if ( !_initializeSdkCalled ) + { + logUninitializedAccessError("_MaxGetBannerLayout"); + return cStringCopy(@""); + } + + return cStringCopy([getAdManager() bannerLayoutForAdUnitIdentifier: NSSTRING(adUnitIdentifier)]); } void _MaxCreateMRec(const char *adUnitIdentifier, const char *mrecPosition) { - if (!isPluginInitialized()) return; + if ( !_initializeSdkCalled ) + { + logUninitializedAccessError("_MaxCreateMRec"); + return; + } - [_adManager createMRecWithAdUnitIdentifier: NSSTRING(adUnitIdentifier) atPosition: NSSTRING(mrecPosition)]; + [getAdManager() createMRecWithAdUnitIdentifier: NSSTRING(adUnitIdentifier) atPosition: NSSTRING(mrecPosition)]; } void _MaxCreateMRecXY(const char *adUnitIdentifier, const float x, const float y) { - if (!isPluginInitialized()) return; + if ( !_initializeSdkCalled ) + { + logUninitializedAccessError("_MaxCreateMRecXY"); + return; + } - [_adManager createMRecWithAdUnitIdentifier: NSSTRING(adUnitIdentifier) x: x y: y]; + [getAdManager() createMRecWithAdUnitIdentifier: NSSTRING(adUnitIdentifier) x: x y: y]; } void _MaxLoadMRec(const char *adUnitIdentifier) { - if (!isPluginInitialized()) return; - - [_adManager loadMRecWithAdUnitIdentifier: NSSTRING(adUnitIdentifier)]; + if ( !_initializeSdkCalled ) + { + logUninitializedAccessError("_MaxLoadMRec"); + return; + } + + [getAdManager() loadMRecWithAdUnitIdentifier: NSSTRING(adUnitIdentifier)]; } void _MaxSetMRecPlacement(const char *adUnitIdentifier, const char *placement) { - [_adManager setMRecPlacement: NSSTRING(placement) forAdUnitIdentifier: NSSTRING(adUnitIdentifier)]; + if ( !_initializeSdkCalled ) + { + logUninitializedAccessError("_MaxSetMRecPlacement"); + return; + } + + [getAdManager() setMRecPlacement: NSSTRING(placement) forAdUnitIdentifier: NSSTRING(adUnitIdentifier)]; } void _MaxStartMRecAutoRefresh(const char *adUnitIdentifier) { - if (!isPluginInitialized()) return; + if ( !_initializeSdkCalled ) + { + logUninitializedAccessError("_MaxStartMRecAutoRefresh"); + return; + } - [_adManager startMRecAutoRefreshForAdUnitIdentifier: NSSTRING(adUnitIdentifier)]; + [getAdManager() startMRecAutoRefreshForAdUnitIdentifier: NSSTRING(adUnitIdentifier)]; } void _MaxStopMRecAutoRefresh(const char *adUnitIdentifier) { - if (!isPluginInitialized()) return; + if ( !_initializeSdkCalled ) + { + logUninitializedAccessError("_MaxStopMRecAutoRefresh"); + return; + } - [_adManager stopMRecAutoRefreshForAdUnitIdentifier: NSSTRING(adUnitIdentifier)]; + [getAdManager() stopMRecAutoRefreshForAdUnitIdentifier: NSSTRING(adUnitIdentifier)]; } void _MaxUpdateMRecPosition(const char *adUnitIdentifier, const char *mrecPosition) { - [_adManager updateMRecPosition: NSSTRING(mrecPosition) forAdUnitIdentifier: NSSTRING(adUnitIdentifier)]; + if ( !_initializeSdkCalled ) + { + logUninitializedAccessError("_MaxUpdateMRecPosition"); + return; + } + + [getAdManager() updateMRecPosition: NSSTRING(mrecPosition) forAdUnitIdentifier: NSSTRING(adUnitIdentifier)]; } void _MaxUpdateMRecPositionXY(const char *adUnitIdentifier, const float x, const float y) { - [_adManager updateMRecPosition: x y: y forAdUnitIdentifier: NSSTRING(adUnitIdentifier)]; + if ( !_initializeSdkCalled ) + { + logUninitializedAccessError("_MaxUpdateMRecPositionXY"); + return; + } + + [getAdManager() updateMRecPosition: x y: y forAdUnitIdentifier: NSSTRING(adUnitIdentifier)]; } void _MaxShowMRec(const char *adUnitIdentifier) { - if (!isPluginInitialized()) return; + if ( !_initializeSdkCalled ) + { + logUninitializedAccessError("_MaxShowMRec"); + return; + } - [_adManager showMRecWithAdUnitIdentifier: NSSTRING(adUnitIdentifier)]; + [getAdManager() showMRecWithAdUnitIdentifier: NSSTRING(adUnitIdentifier)]; } void _MaxDestroyMRec(const char *adUnitIdentifier) { - if (!isPluginInitialized()) return; + if ( !_initializeSdkCalled ) + { + logUninitializedAccessError("_MaxDestroyMRec"); + return; + } - [_adManager destroyMRecWithAdUnitIdentifier: NSSTRING(adUnitIdentifier)]; + [getAdManager() destroyMRecWithAdUnitIdentifier: NSSTRING(adUnitIdentifier)]; } void _MaxHideMRec(const char *adUnitIdentifier) { - if (!isPluginInitialized()) return; + if ( !_initializeSdkCalled ) + { + logUninitializedAccessError("_MaxHideMRec"); + return; + } - [_adManager hideMRecWithAdUnitIdentifier: NSSTRING(adUnitIdentifier)]; + [getAdManager() hideMRecWithAdUnitIdentifier: NSSTRING(adUnitIdentifier)]; } void _MaxSetMRecExtraParameter(const char *adUnitIdentifier, const char *key, const char *value) { - [_adManager setMRecExtraParameterForAdUnitIdentifier: NSSTRING(adUnitIdentifier) + if ( !_initializeSdkCalled ) + { + logUninitializedAccessError("_MaxSetMRecExtraParameter"); + return; + } + + [getAdManager() setMRecExtraParameterForAdUnitIdentifier: NSSTRING(adUnitIdentifier) key: NSSTRING(key) value: NSSTRING(value)]; } void _MaxSetMRecLocalExtraParameter(const char *adUnitIdentifier, const char *key, MAUnityRef value) { - if ( !isReadyToInteractWithSdk() ) + if ( !_initializeSdkCalled ) { logUninitializedAccessError("_MaxSetMRecLocalExtraParameter"); + return; } - [_adManager setMRecLocalExtraParameterForAdUnitIdentifier: NSSTRING(adUnitIdentifier) - key: NSSTRING(key) - value: (__bridge id)value]; + [getAdManager() setMRecLocalExtraParameterForAdUnitIdentifier: NSSTRING(adUnitIdentifier) + key: NSSTRING(key) + value: (__bridge id)value]; } void _MaxSetMRecLocalExtraParameterJSON(const char *adUnitIdentifier, const char *key, const char *json) { - if ( !isReadyToInteractWithSdk() ) + if ( !_initializeSdkCalled ) { logUninitializedAccessError("_MaxSetMRecLocalExtraParameter"); + return; } id value = getLocalExtraParameterValue(json); - [_adManager setMRecLocalExtraParameterForAdUnitIdentifier: NSSTRING(adUnitIdentifier) - key: NSSTRING(key) - value: value]; + [getAdManager() setMRecLocalExtraParameterForAdUnitIdentifier: NSSTRING(adUnitIdentifier) + key: NSSTRING(key) + value: value]; } void _MaxSetMRecCustomData(const char *adUnitIdentifier, const char *customData) { - [_adManager setMRecCustomData: NSSTRING(customData) forAdUnitIdentifier: NSSTRING(adUnitIdentifier)]; + if ( !_initializeSdkCalled ) + { + logUninitializedAccessError("_MaxSetMRecCustomData"); + return; + } + + [getAdManager() setMRecCustomData: NSSTRING(customData) forAdUnitIdentifier: NSSTRING(adUnitIdentifier)]; } const char * _MaxGetMRecLayout(const char *adUnitIdentifier) { - if (!isPluginInitialized()) return cStringCopy(@""); - - return cStringCopy([_adManager mrecLayoutForAdUnitIdentifier: NSSTRING(adUnitIdentifier)]); + if ( !_initializeSdkCalled ) + { + logUninitializedAccessError("_MaxGetMRecLayout"); + return cStringCopy(@""); + } + + return cStringCopy([getAdManager() mrecLayoutForAdUnitIdentifier: NSSTRING(adUnitIdentifier)]); } void _MaxLoadInterstitial(const char *adUnitIdentifier) { - if (!isPluginInitialized()) return; + if ( !_initializeSdkCalled ) + { + logUninitializedAccessError("_MaxLoadInterstitial"); + return; + } - [_adManager loadInterstitialWithAdUnitIdentifier: NSSTRING(adUnitIdentifier)]; + [getAdManager() loadInterstitialWithAdUnitIdentifier: NSSTRING(adUnitIdentifier)]; } void _MaxSetInterstitialExtraParameter(const char *adUnitIdentifier, const char *key, const char *value) { - [_adManager setInterstitialExtraParameterForAdUnitIdentifier: NSSTRING(adUnitIdentifier) - key: NSSTRING(key) - value: NSSTRING(value)]; + if ( !_initializeSdkCalled ) + { + logUninitializedAccessError("_MaxSetInterstitialExtraParameter"); + return; + } + + [getAdManager() setInterstitialExtraParameterForAdUnitIdentifier: NSSTRING(adUnitIdentifier) + key: NSSTRING(key) + value: NSSTRING(value)]; } void _MaxSetInterstitialLocalExtraParameter(const char *adUnitIdentifier, const char *key, MAUnityRef value) { - if ( !isReadyToInteractWithSdk() ) + if ( !_initializeSdkCalled ) { logUninitializedAccessError("_MaxSetInterstitialLocalExtraParameter"); + return; } - [_adManager setInterstitialLocalExtraParameterForAdUnitIdentifier: NSSTRING(adUnitIdentifier) - key: NSSTRING(key) - value: (__bridge id)value]; + [getAdManager() setInterstitialLocalExtraParameterForAdUnitIdentifier: NSSTRING(adUnitIdentifier) + key: NSSTRING(key) + value: (__bridge id)value]; } void _MaxSetInterstitialLocalExtraParameterJSON(const char *adUnitIdentifier, const char *key, const char *json) { - if ( !isReadyToInteractWithSdk() ) + if ( !_initializeSdkCalled ) { logUninitializedAccessError("_MaxSetInterstitialLocalExtraParameter"); + return; } id value = getLocalExtraParameterValue(json); - [_adManager setInterstitialLocalExtraParameterForAdUnitIdentifier: NSSTRING(adUnitIdentifier) - key: NSSTRING(key) - value: value]; + [getAdManager() setInterstitialLocalExtraParameterForAdUnitIdentifier: NSSTRING(adUnitIdentifier) + key: NSSTRING(key) + value: value]; } bool _MaxIsInterstitialReady(const char *adUnitIdentifier) { - if (!isPluginInitialized()) return false; + if ( !_initializeSdkCalled ) + { + logUninitializedAccessError("_MaxIsInterstitialReady"); + return false; + } - return [_adManager isInterstitialReadyWithAdUnitIdentifier: NSSTRING(adUnitIdentifier)]; + return [getAdManager() isInterstitialReadyWithAdUnitIdentifier: NSSTRING(adUnitIdentifier)]; } void _MaxShowInterstitial(const char *adUnitIdentifier, const char *placement, const char *customData) { - if (!isPluginInitialized()) return; + if ( !_initializeSdkCalled ) + { + logUninitializedAccessError("_MaxShowInterstitial"); + return; + } - [_adManager showInterstitialWithAdUnitIdentifier: NSSTRING(adUnitIdentifier) placement: NSSTRING(placement) customData: NSSTRING(customData)]; + [getAdManager() showInterstitialWithAdUnitIdentifier: NSSTRING(adUnitIdentifier) placement: NSSTRING(placement) customData: NSSTRING(customData)]; } void _MaxLoadAppOpenAd(const char *adUnitIdentifier) { - if (!isPluginInitialized()) return; + if ( !_initializeSdkCalled ) + { + logUninitializedAccessError("_MaxLoadAppOpenAd"); + return; + } - [_adManager loadAppOpenAdWithAdUnitIdentifier: NSSTRING(adUnitIdentifier)]; + [getAdManager() loadAppOpenAdWithAdUnitIdentifier: NSSTRING(adUnitIdentifier)]; } void _MaxSetAppOpenAdExtraParameter(const char *adUnitIdentifier, const char *key, const char *value) { - [_adManager setAppOpenAdExtraParameterForAdUnitIdentifier: NSSTRING(adUnitIdentifier) - key: NSSTRING(key) - value: NSSTRING(value)]; + if ( !_initializeSdkCalled ) + { + logUninitializedAccessError("_MaxSetAppOpenAdExtraParameter"); + return; + } + + [getAdManager() setAppOpenAdExtraParameterForAdUnitIdentifier: NSSTRING(adUnitIdentifier) + key: NSSTRING(key) + value: NSSTRING(value)]; } void _MaxSetAppOpenAdLocalExtraParameter(const char *adUnitIdentifier, const char *key, MAUnityRef value) { - if ( !isReadyToInteractWithSdk() ) + if ( !_initializeSdkCalled ) { logUninitializedAccessError("_MaxSetAppOpenAdLocalExtraParameter"); + return; } - [_adManager setAppOpenAdLocalExtraParameterForAdUnitIdentifier: NSSTRING(adUnitIdentifier) - key: NSSTRING(key) - value: (__bridge id)value]; + [getAdManager() setAppOpenAdLocalExtraParameterForAdUnitIdentifier: NSSTRING(adUnitIdentifier) + key: NSSTRING(key) + value: (__bridge id)value]; } void _MaxSetAppOpenAdLocalExtraParameterJSON(const char *adUnitIdentifier, const char *key, const char *json) { - if ( !isReadyToInteractWithSdk() ) + if ( !_initializeSdkCalled ) { logUninitializedAccessError("_MaxSetAppOpenAdLocalExtraParameter"); + return; } id value = getLocalExtraParameterValue(json); - [_adManager setAppOpenAdLocalExtraParameterForAdUnitIdentifier: NSSTRING(adUnitIdentifier) - key: NSSTRING(key) - value: value]; + [getAdManager() setAppOpenAdLocalExtraParameterForAdUnitIdentifier: NSSTRING(adUnitIdentifier) + key: NSSTRING(key) + value: value]; } bool _MaxIsAppOpenAdReady(const char *adUnitIdentifier) { - if (!isPluginInitialized()) return false; + if ( !_initializeSdkCalled ) + { + logUninitializedAccessError("_MaxIsAppOpenAdReady"); + return false; + } - return [_adManager isAppOpenAdReadyWithAdUnitIdentifier: NSSTRING(adUnitIdentifier)]; + return [getAdManager() isAppOpenAdReadyWithAdUnitIdentifier: NSSTRING(adUnitIdentifier)]; } void _MaxShowAppOpenAd(const char *adUnitIdentifier, const char *placement, const char *customData) { - if (!isPluginInitialized()) return; + if ( !_initializeSdkCalled ) + { + logUninitializedAccessError("_MaxShowAppOpenAd"); + return; + } - [_adManager showAppOpenAdWithAdUnitIdentifier: NSSTRING(adUnitIdentifier) placement: NSSTRING(placement) customData: NSSTRING(customData)]; + [getAdManager() showAppOpenAdWithAdUnitIdentifier: NSSTRING(adUnitIdentifier) placement: NSSTRING(placement) customData: NSSTRING(customData)]; } void _MaxLoadRewardedAd(const char *adUnitIdentifier) { - if (!isPluginInitialized()) return; + if ( !_initializeSdkCalled ) + { + logUninitializedAccessError("_MaxLoadRewardedAd"); + return; + } - [_adManager loadRewardedAdWithAdUnitIdentifier: NSSTRING(adUnitIdentifier)]; + [getAdManager() loadRewardedAdWithAdUnitIdentifier: NSSTRING(adUnitIdentifier)]; } void _MaxSetRewardedAdExtraParameter(const char *adUnitIdentifier, const char *key, const char *value) { - [_adManager setRewardedAdExtraParameterForAdUnitIdentifier: NSSTRING(adUnitIdentifier) - key: NSSTRING(key) - value: NSSTRING(value)]; + if ( !_initializeSdkCalled ) + { + logUninitializedAccessError("_MaxSetRewardedAdExtraParameter"); + return; + } + + [getAdManager() setRewardedAdExtraParameterForAdUnitIdentifier: NSSTRING(adUnitIdentifier) + key: NSSTRING(key) + value: NSSTRING(value)]; } void _MaxSetRewardedAdLocalExtraParameter(const char *adUnitIdentifier, const char *key, MAUnityRef value) { - if ( !isReadyToInteractWithSdk() ) + if ( !_initializeSdkCalled ) { logUninitializedAccessError("_MaxSetRewardedAdLocalExtraParameter"); + return; } - [_adManager setRewardedAdLocalExtraParameterForAdUnitIdentifier: NSSTRING(adUnitIdentifier) - key: NSSTRING(key) - value: (__bridge id)value]; + [getAdManager() setRewardedAdLocalExtraParameterForAdUnitIdentifier: NSSTRING(adUnitIdentifier) + key: NSSTRING(key) + value: (__bridge id)value]; } void _MaxSetRewardedAdLocalExtraParameterJSON(const char *adUnitIdentifier, const char *key, const char *json) { - if ( !isReadyToInteractWithSdk() ) + if ( !_initializeSdkCalled ) { logUninitializedAccessError("_MaxSetRewardedAdLocalExtraParameter"); + return; } id value = getLocalExtraParameterValue(json); - [_adManager setRewardedAdLocalExtraParameterForAdUnitIdentifier: NSSTRING(adUnitIdentifier) - key: NSSTRING(key) - value: value]; + [getAdManager() setRewardedAdLocalExtraParameterForAdUnitIdentifier: NSSTRING(adUnitIdentifier) + key: NSSTRING(key) + value: value]; } bool _MaxIsRewardedAdReady(const char *adUnitIdentifier) { - if (!isPluginInitialized()) return false; + if ( !_initializeSdkCalled ) + { + logUninitializedAccessError("_MaxIsRewardedAdReady"); + return false; + } - return [_adManager isRewardedAdReadyWithAdUnitIdentifier: NSSTRING(adUnitIdentifier)]; + return [getAdManager() isRewardedAdReadyWithAdUnitIdentifier: NSSTRING(adUnitIdentifier)]; } void _MaxShowRewardedAd(const char *adUnitIdentifier, const char *placement, const char *customData) { - if (!isPluginInitialized()) return; + if ( !_initializeSdkCalled ) + { + logUninitializedAccessError("_MaxShowRewardedAd"); + return; + } - [_adManager showRewardedAdWithAdUnitIdentifier: NSSTRING(adUnitIdentifier) placement: NSSTRING(placement) customData: NSSTRING(customData)]; + [getAdManager() showRewardedAdWithAdUnitIdentifier: NSSTRING(adUnitIdentifier) placement: NSSTRING(placement) customData: NSSTRING(customData)]; } void _MaxLoadRewardedInterstitialAd(const char *adUnitIdentifier) { - if (!isPluginInitialized()) return; + if ( !_initializeSdkCalled ) + { + logUninitializedAccessError("_MaxLoadRewardedInterstitialAd"); + return; + } - [_adManager loadRewardedInterstitialAdWithAdUnitIdentifier: NSSTRING(adUnitIdentifier)]; + [getAdManager() loadRewardedInterstitialAdWithAdUnitIdentifier: NSSTRING(adUnitIdentifier)]; } void _MaxSetRewardedInterstitialAdExtraParameter(const char *adUnitIdentifier, const char *key, const char *value) { - [_adManager setRewardedInterstitialAdExtraParameterForAdUnitIdentifier: NSSTRING(adUnitIdentifier) - key: NSSTRING(key) - value: NSSTRING(value)]; + if ( !_initializeSdkCalled ) + { + logUninitializedAccessError("_MaxSetRewardedInterstitialAdExtraParameter"); + return; + } + + [getAdManager() setRewardedInterstitialAdExtraParameterForAdUnitIdentifier: NSSTRING(adUnitIdentifier) + key: NSSTRING(key) + value: NSSTRING(value)]; } void _MaxSetRewardedInterstitialAdLocalExtraParameter(const char *adUnitIdentifier, const char *key, MAUnityRef value) { - if ( !isReadyToInteractWithSdk() ) + if ( !_initializeSdkCalled ) { logUninitializedAccessError("_MaxSetRewardedInterstitialAdLocalExtraParameter"); + return; } - [_adManager setRewardedInterstitialAdLocalExtraParameterForAdUnitIdentifier: NSSTRING(adUnitIdentifier) - key: NSSTRING(key) - value: (__bridge id)value]; + [getAdManager() setRewardedInterstitialAdLocalExtraParameterForAdUnitIdentifier: NSSTRING(adUnitIdentifier) + key: NSSTRING(key) + value: (__bridge id)value]; } void _MaxSetRewardedInterstitialAdLocalExtraParameterJSON(const char *adUnitIdentifier, const char *key, const char *json) { - if ( !isReadyToInteractWithSdk() ) + if ( !_initializeSdkCalled ) { logUninitializedAccessError("_MaxSetRewardedInterstitialAdLocalExtraParameter"); + return; } id value = getLocalExtraParameterValue(json); - [_adManager setRewardedInterstitialAdLocalExtraParameterForAdUnitIdentifier: NSSTRING(adUnitIdentifier) - key: NSSTRING(key) - value: value]; + [getAdManager() setRewardedInterstitialAdLocalExtraParameterForAdUnitIdentifier: NSSTRING(adUnitIdentifier) + key: NSSTRING(key) + value: value]; } bool _MaxIsRewardedInterstitialAdReady(const char *adUnitIdentifier) { - if (!isPluginInitialized()) return false; + if ( !_initializeSdkCalled ) + { + logUninitializedAccessError("_MaxIsRewardedInterstitialAdReady"); + return false; + } - return [_adManager isRewardedInterstitialAdReadyWithAdUnitIdentifier: NSSTRING(adUnitIdentifier)]; + return [getAdManager() isRewardedInterstitialAdReadyWithAdUnitIdentifier: NSSTRING(adUnitIdentifier)]; } void _MaxShowRewardedInterstitialAd(const char *adUnitIdentifier, const char *placement, const char *customData) { - if (!isPluginInitialized()) return; + if ( !_initializeSdkCalled ) + { + logUninitializedAccessError("_MaxShowRewardedInterstitialAd"); + return; + } - [_adManager showRewardedInterstitialAdWithAdUnitIdentifier: NSSTRING(adUnitIdentifier) placement: NSSTRING(placement) customData: NSSTRING(customData)]; + [getAdManager() showRewardedInterstitialAdWithAdUnitIdentifier: NSSTRING(adUnitIdentifier) placement: NSSTRING(placement) customData: NSSTRING(customData)]; } void _MaxTrackEvent(const char *event, const char *parameters) { - if (!isPluginInitialized()) return; + if ( !_initializeSdkCalled ) + { + logUninitializedAccessError("_MaxTrackEvent"); + return; + } - [_adManager trackEvent: NSSTRING(event) parameters: NSSTRING(parameters)]; + [getAdManager() trackEvent: NSSTRING(event) parameters: NSSTRING(parameters)]; } bool _MaxIsTablet() @@ -1059,29 +1052,12 @@ int _MaxGetSpecialFeatureOptInStatus(int specialFeatureIdentifier) void _MaxSetMuted(bool muted) { - if ( _sdk ) - { - _sdk.settings.muted = muted; - _mutedToSet = nil; - } - else - { - _mutedToSet = @(muted); - } + getSdk().settings.muted = muted; } bool _MaxIsMuted() { - if ( _sdk ) - { - return _sdk.settings.muted; - } - else if ( _mutedToSet != nil ) - { - return _mutedToSet.boolValue; - } - - return false; + return getSdk().settings.muted; } float _MaxScreenDensity() @@ -1091,86 +1067,52 @@ float _MaxScreenDensity() const char * _MaxGetAdInfo(const char *adUnitIdentifier) { - return cStringCopy([_adManager adInfoForAdUnitIdentifier: NSSTRING(adUnitIdentifier)]); + return cStringCopy([getAdManager() adInfoForAdUnitIdentifier: NSSTRING(adUnitIdentifier)]); } const char * _MaxGetAdValue(const char *adUnitIdentifier, const char *key) { - return cStringCopy([_adManager adValueForAdUnitIdentifier: NSSTRING(adUnitIdentifier) withKey: NSSTRING(key)]); + return cStringCopy([getAdManager() adValueForAdUnitIdentifier: NSSTRING(adUnitIdentifier) withKey: NSSTRING(key)]); } void _MaxSetVerboseLogging(bool enabled) { - if ( _sdk ) - { - _sdk.settings.verboseLoggingEnabled = enabled; - _verboseLoggingToSet = nil; - } - else - { - _verboseLoggingToSet = @(enabled); - } + getSdk().settings.verboseLoggingEnabled = enabled; } bool _MaxIsVerboseLoggingEnabled() { - if ( _sdk ) - { - return [_sdk.settings isVerboseLoggingEnabled]; - } - else if ( _verboseLoggingToSet != nil ) - { - return _verboseLoggingToSet.boolValue; - } - - return false; + return [getSdk().settings isVerboseLoggingEnabled]; } void _MaxSetTestDeviceAdvertisingIdentifiers(char **advertisingIdentifiers, int size) { + if ( _initializeSdkCalled ) + { + NSLog(@"[%@] Test device advertising IDs must be set before MAX SDK is initialized", TAG); + return; + } + NSArray *advertisingIdentifiersArray = toStringArray(advertisingIdentifiers, size); - _testDeviceIdentifiersToSet = advertisingIdentifiersArray; + getInitConfigurationBuilder().testDeviceAdvertisingIdentifiers = advertisingIdentifiersArray; } void _MaxSetCreativeDebuggerEnabled(bool enabled) { - if ( _sdk ) - { - _sdk.settings.creativeDebuggerEnabled = enabled; - _creativeDebuggerEnabledToSet = nil; - } - else - { - _creativeDebuggerEnabledToSet = @(enabled); - } + getSdk().settings.creativeDebuggerEnabled = enabled; } void _MaxSetExceptionHandlerEnabled(bool enabled) { - if ( _sdk ) - { - _sdk.settings.exceptionHandlerEnabled = enabled; - _exceptionHandlerEnabledToSet = nil; - } - else - { - _exceptionHandlerEnabledToSet = @(enabled); - } - } - - void _MaxSetLocationCollectionEnabled(bool enabled) - { - if ( _sdk ) - { - _sdk.settings.locationCollectionEnabled = enabled; - _locationCollectionEnabledToSet = nil; - } - else + if ( _initializeSdkCalled ) { - _locationCollectionEnabledToSet = @(enabled); + NSLog(@"[%@] Exception handler must be enabled/disabled before MAX SDK is initialized", TAG); + return; } + + getInitConfigurationBuilder().exceptionHandlerEnabled = enabled; } - + void _MaxSetExtraParameter(const char *key, const char *value) { NSString *stringKey = NSSTRING(key); @@ -1180,19 +1122,8 @@ void _MaxSetExtraParameter(const char *key, const char *value) return; } - if ( _sdk ) - { - ALSdkSettings *settings = _sdk.settings; - [settings setExtraParameterForKey: stringKey value: NSSTRING(value)]; - setPendingExtraParametersIfNeeded( settings ); - } - else - { - @synchronized ( _extraParametersToSetLock ) - { - _extraParametersToSet[stringKey] = NSSTRING(value); - } - } + ALSdkSettings *settings = getSdk().settings; + [settings setExtraParameterForKey: stringKey value: NSSTRING(value)]; } int * _MaxGetSafeAreaInsets() @@ -1204,24 +1135,24 @@ void _MaxSetExtraParameter(const char *key, const char *value) void _MaxShowCmpForExistingUser() { - if (!isPluginInitialized()) + if ( !_initializeSdkCalled ) { logUninitializedAccessError("_MaxShowCmpForExistingUser"); return; } - [_adManager showCMPForExistingUser]; + [getAdManager() showCMPForExistingUser]; } bool _MaxHasSupportedCmp() { - if (!isPluginInitialized()) + if ( !_initializeSdkCalled ) { logUninitializedAccessError("_MaxHasSupportedCmp"); return false; } - return [_sdk.cmpService hasSupportedCMP]; + return [getSdk().cmpService hasSupportedCMP]; } float _MaxGetAdaptiveBannerHeight(const float width) diff --git a/DemoApp/Assets/MaxSdk/Prefabs.meta b/DemoApp/Assets/MaxSdk/Prefabs.meta index 42f29a1..45829b7 100644 --- a/DemoApp/Assets/MaxSdk/Prefabs.meta +++ b/DemoApp/Assets/MaxSdk/Prefabs.meta @@ -1,8 +1,5 @@ fileFormatVersion: 2 -guid: c6b1dd2e4604b4f9187912bf3aff2afd -labels: -- al_max -- al_max_export_path-MaxSdk/Prefabs +guid: b1ef42d076f894359b53ec57a427a224 folderAsset: yes DefaultImporter: externalObjects: {} diff --git a/DemoApp/Assets/MaxSdk/Resources.meta b/DemoApp/Assets/MaxSdk/Resources.meta index 58550d4..03c0c4c 100644 --- a/DemoApp/Assets/MaxSdk/Resources.meta +++ b/DemoApp/Assets/MaxSdk/Resources.meta @@ -1,8 +1,5 @@ fileFormatVersion: 2 -guid: 8315dff900cc742cda75c9da2b3b33ac -labels: -- al_max -- al_max_export_path-MaxSdk/Resources +guid: ebb4a8564e8074807876237c023d7ef7 folderAsset: yes DefaultImporter: externalObjects: {} diff --git a/DemoApp/Assets/MaxSdk/Resources/Images.meta b/DemoApp/Assets/MaxSdk/Resources/Images.meta index cd398ab..16aa852 100644 --- a/DemoApp/Assets/MaxSdk/Resources/Images.meta +++ b/DemoApp/Assets/MaxSdk/Resources/Images.meta @@ -1,8 +1,5 @@ fileFormatVersion: 2 -guid: 5dcd85260f10f43e1ad13c4e66340b35 -labels: -- al_max -- al_max_export_path-MaxSdk/Resources/Images +guid: 62530839001924aff89b18c462d7c991 folderAsset: yes DefaultImporter: externalObjects: {} diff --git a/DemoApp/Assets/MaxSdk/Scripts.meta b/DemoApp/Assets/MaxSdk/Scripts.meta index 4543898..db94d67 100644 --- a/DemoApp/Assets/MaxSdk/Scripts.meta +++ b/DemoApp/Assets/MaxSdk/Scripts.meta @@ -1,8 +1,5 @@ fileFormatVersion: 2 -guid: 765218dc6ff504b589488c745f32faee -labels: -- al_max -- al_max_export_path-MaxSdk/Scripts +guid: b54f71ab59d7b492da373a6ae2e68337 folderAsset: yes DefaultImporter: externalObjects: {} diff --git a/DemoApp/Assets/MaxSdk/Scripts/IntegrationManager/Editor/AppLovinInitialize.cs b/DemoApp/Assets/MaxSdk/Scripts/IntegrationManager/Editor/AppLovinInitialize.cs index 4f61d97..8280424 100644 --- a/DemoApp/Assets/MaxSdk/Scripts/IntegrationManager/Editor/AppLovinInitialize.cs +++ b/DemoApp/Assets/MaxSdk/Scripts/IntegrationManager/Editor/AppLovinInitialize.cs @@ -68,7 +68,13 @@ public class AppLovinInitialize "MaxSdk/Scripts/MaxVariableServiceiOS.cs", "MaxSdk/Scripts/MaxVariableServiceiOS.cs.meta", "MaxSdk/Scripts/MaxVariableServiceUnityEditor.cs", - "MaxSdk/Scripts/MaxVariableServiceUnityEditor.cs.meta" + "MaxSdk/Scripts/MaxVariableServiceUnityEditor.cs.meta", + + // Targeting data and user segments have been removed. + "MaxSdk/Scripts/MaxTargetingData.cs", + "MaxSdk/Scripts/MaxTargetingData.cs.meta", + "MaxSdk/Scripts/MaxUserSegment.cs", + "MaxSdk/Scripts/MaxUserSegment.cs.meta", }; static AppLovinInitialize() @@ -96,8 +102,6 @@ static AppLovinInitialize() } } - AppLovinIntegrationManager.AddLabelsToAssetsIfNeeded(pluginParentDir, isPluginOutsideAssetsDir); - foreach (var obsoleteFileExportPathToDelete in ObsoleteFileExportPathsToDelete) { var pathToDelete = MaxSdkUtils.GetAssetPathForExportPath(obsoleteFileExportPathToDelete); diff --git a/DemoApp/Assets/MaxSdk/Scripts/IntegrationManager/Editor/AppLovinIntegrationManager.cs b/DemoApp/Assets/MaxSdk/Scripts/IntegrationManager/Editor/AppLovinIntegrationManager.cs index 1536e66..a37a70f 100644 --- a/DemoApp/Assets/MaxSdk/Scripts/IntegrationManager/Editor/AppLovinIntegrationManager.cs +++ b/DemoApp/Assets/MaxSdk/Scripts/IntegrationManager/Editor/AppLovinIntegrationManager.cs @@ -25,6 +25,7 @@ public class PluginData public Network AppLovinMax; public Network[] MediatedNetworks; public Network[] PartnerMicroSdks; + public DynamicLibraryToEmbed[] ThirdPartyDynamicLibrariesToEmbed; } [Serializable] @@ -56,6 +57,26 @@ public class Network [NonSerialized] public Versions CurrentVersions; [NonSerialized] public VersionComparisonResult CurrentToLatestVersionComparisonResult = VersionComparisonResult.Lesser; [NonSerialized] public bool RequiresUpdate; + public DynamicLibraryToEmbed[] DynamicLibrariesToEmbed; + } + + [Serializable] + public class DynamicLibraryToEmbed + { + public string PodName; + public string[] FrameworkNames; + + // Min and max versions are inclusive, so if the adapter is the min or max version, the xcframework will get embedded. + public string MinVersion; + public string MaxVersion; + + public DynamicLibraryToEmbed(string podName, string[] frameworkNames, string minVersion, string maxVersion) + { + PodName = podName; + FrameworkNames = frameworkNames; + MinVersion = minVersion; + MaxVersion = maxVersion; + } } /// @@ -124,6 +145,8 @@ public class AppLovinIntegrationManager public static readonly string DefaultPluginExportPath = Path.Combine("Assets", "MaxSdk"); private const string MaxSdkAssetExportPath = "MaxSdk/Scripts/MaxSdk.cs"; + internal static readonly string PluginDataEndpoint = "https://unity.applovin.com/max/1.0/integration_manager_info?plugin_version={0}"; + /// /// Some publishers might re-export our plugin via Unity Package Manager and the plugin will not be under the Assets folder. This means that the mediation adapters, settings files should not be moved to the packages folder, /// since they get overridden when the package is updated. These are the files that should not be moved, if the plugin is not under the Assets/ folder. @@ -248,7 +271,6 @@ private AppLovinIntegrationManager() var pluginParentDir = PluginParentDirectory; var isPluginOutsideAssetsDir = IsPluginOutsideAssetsDirectory; MovePluginFilesIfNeeded(pluginParentDir, isPluginOutsideAssetsDir); - AddLabelsToAssetsIfNeeded(pluginParentDir, isPluginOutsideAssetsDir); AssetDatabase.Refresh(); CallImportPackageCompletedCallback(importingNetwork); @@ -274,62 +296,81 @@ private AppLovinIntegrationManager() static AppLovinIntegrationManager() { } + public static PluginData LoadPluginDataSync() + { + var url = string.Format(PluginDataEndpoint, MaxSdk.Version); + using (var unityWebRequest = UnityWebRequest.Get(url)) + { + var operation = unityWebRequest.SendWebRequest(); + + // Just wait till www is done + while (!operation.isDone) { } + + return CreatePluginDataFromWebResponse(unityWebRequest); + } + } + /// /// Loads the plugin data to be display by integration manager window. /// /// Callback to be called once the plugin data download completes. public IEnumerator LoadPluginData(Action callback) { - var url = string.Format("https://unity.applovin.com/max/1.0/integration_manager_info?plugin_version={0}", MaxSdk.Version); - using (var www = UnityWebRequest.Get(url)) + var url = string.Format(PluginDataEndpoint, MaxSdk.Version); + using (var unityWebRequest = UnityWebRequest.Get(url)) { - var operation = www.SendWebRequest(); + var operation = unityWebRequest.SendWebRequest(); while (!operation.isDone) yield return new WaitForSeconds(0.1f); // Just wait till www is done. Our coroutine is pretty rudimentary. + var pluginData = CreatePluginDataFromWebResponse(unityWebRequest); + + callback(pluginData); + } + } + + private static PluginData CreatePluginDataFromWebResponse(UnityWebRequest unityWebRequest) + { #if UNITY_2020_1_OR_NEWER - if (www.result != UnityWebRequest.Result.Success) + if (unityWebRequest.result != UnityWebRequest.Result.Success) #else - if (www.isNetworkError || www.isHttpError) + if (unityWebRequest.isNetworkError || unityWebRequest.isHttpError) #endif - { - callback(null); - } - else - { - PluginData pluginData; - try - { - pluginData = JsonUtility.FromJson(www.downloadHandler.text); - } - catch (Exception exception) - { - Console.WriteLine(exception); - pluginData = null; - } + { + MaxSdkLogger.E("Failed to load plugin data. Please check your internet connection."); + return null; + } - if (pluginData != null) - { - // Get current version of the plugin - var appLovinMax = pluginData.AppLovinMax; - UpdateCurrentVersions(appLovinMax, PluginParentDirectory); + PluginData pluginData; + try + { + pluginData = JsonUtility.FromJson(unityWebRequest.downloadHandler.text); + } + catch (Exception exception) + { + Console.WriteLine(exception); + pluginData = null; + } - // Get current versions for all the mediation networks. - var mediationPluginParentDirectory = MediationSpecificPluginParentDirectory; - foreach (var network in pluginData.MediatedNetworks) - { - UpdateCurrentVersions(network, mediationPluginParentDirectory); - } + if (pluginData == null) return null; - foreach (var partnerMicroSdk in pluginData.PartnerMicroSdks) - { - UpdateCurrentVersions(partnerMicroSdk, mediationPluginParentDirectory); - } - } + // Get current version of the plugin + var appLovinMax = pluginData.AppLovinMax; + UpdateCurrentVersions(appLovinMax, PluginParentDirectory); - callback(pluginData); - } + // Get current versions for all the mediation networks. + var mediationPluginParentDirectory = MediationSpecificPluginParentDirectory; + foreach (var network in pluginData.MediatedNetworks) + { + UpdateCurrentVersions(network, mediationPluginParentDirectory); + } + + foreach (var partnerMicroSdk in pluginData.PartnerMicroSdks) + { + UpdateCurrentVersions(partnerMicroSdk, mediationPluginParentDirectory); } + + return pluginData; } /// @@ -339,8 +380,7 @@ public IEnumerator LoadPluginData(Action callback) /// The parent directory of where the mediation adapter plugins are imported to. public static void UpdateCurrentVersions(Network network, string mediationPluginParentDirectory) { - var dependencyFilePath = Path.Combine(mediationPluginParentDirectory, network.DependenciesFilePath); - var currentVersions = GetCurrentVersions(dependencyFilePath); + var currentVersions = GetCurrentVersions(MaxSdkUtils.GetAssetPathForExportPath(network.DependenciesFilePath)); network.CurrentVersions = currentVersions; @@ -482,24 +522,6 @@ public static bool IsAdapterInstalled(string adapterName, string iosVersion = nu return iosVersionComparison != VersionComparisonResult.Lesser; } - /// - /// Checks whether or not an adapter older than the given version exists. - /// - /// TODO: Consolidate this method with and return a state enum. - /// - /// The name of the network (the root adapter folder name in "MaxSdk/Mediation/" folder. - /// The adapter version to check for. - /// true if an adapter older than the provided version is installed. - public static bool IsAdapterOlderThanMinVersionInstalled(string adapterName, string iosVersion) // TODO: Add Android version check. - { - var dependencyFilePath = MaxSdkUtils.GetAssetPathForExportPath("MaxSdk/Mediation/" + adapterName + "/Editor/Dependencies.xml"); - if (!File.Exists(dependencyFilePath)) return false; - - var currentVersion = GetCurrentVersions(dependencyFilePath); - var iosVersionComparison = MaxSdkUtils.CompareVersions(currentVersion.Ios, iosVersion); - return iosVersionComparison == VersionComparisonResult.Lesser; - } - #region Utility Methods /// @@ -597,73 +619,6 @@ private bool IsImportingNetwork(string packageName) return importingNetwork != null && GetPluginFileName(importingNetwork).Contains(packageName); } - /// - /// Adds labels to assets so that they can be easily found. - /// - /// The MAX Unity plugin's parent directory. - /// Whether or not the plugin is outside the Assets directory. - public static void AddLabelsToAssetsIfNeeded(string pluginParentDir, bool isPluginOutsideAssetsDirectory) - { - if (isPluginOutsideAssetsDirectory) - { - var defaultPluginLocation = Path.Combine("Assets", "MaxSdk"); - if (Directory.Exists(defaultPluginLocation)) - { - AddLabelsToAssets(defaultPluginLocation, "Assets"); - } - } - - var pluginDir = Path.Combine(pluginParentDir, "MaxSdk"); - AddLabelsToAssets(pluginDir, pluginParentDir); - } - - private static void AddLabelsToAssets(string directoryPath, string pluginParentDir) - { - var files = Directory.GetFiles(directoryPath); - foreach (var file in files) - { - if (file.EndsWith(".meta")) continue; - - UpdateAssetLabelsIfNeeded(file, pluginParentDir); - } - - var directories = Directory.GetDirectories(directoryPath); - foreach (var directory in directories) - { - // Add labels to this directory asset. - UpdateAssetLabelsIfNeeded(directory, pluginParentDir); - - // Recursively add labels to all files under this directory. - AddLabelsToAssets(directory, pluginParentDir); - } - } - - private static void UpdateAssetLabelsIfNeeded(string assetPath, string pluginParentDir) - { - var asset = AssetDatabase.LoadAssetAtPath(assetPath); - var labels = AssetDatabase.GetLabels(asset); - - var labelsToAdd = labels.ToList(); - var didAddLabels = false; - if (!labels.Contains("al_max")) - { - labelsToAdd.Add("al_max"); - didAddLabels = true; - } - - var exportPathLabel = "al_max_export_path-" + assetPath.Replace(pluginParentDir, "").Replace(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar); - if (!labels.Contains(exportPathLabel)) - { - labelsToAdd.Add(exportPathLabel); - didAddLabels = true; - } - - // We only need to set the labels if they changed. - if (!didAddLabels) return; - - AssetDatabase.SetLabels(asset, labelsToAdd.ToArray()); - } - /// /// Moves the imported plugin files to the MaxSdk directory if the publisher has moved the plugin to a different directory. This is a failsafe for when some plugin files are not imported to the new location. /// diff --git a/DemoApp/Assets/MaxSdk/Scripts/IntegrationManager/Editor/AppLovinIntegrationManagerWindow.cs b/DemoApp/Assets/MaxSdk/Scripts/IntegrationManager/Editor/AppLovinIntegrationManagerWindow.cs index 3071a8c..904f8f9 100644 --- a/DemoApp/Assets/MaxSdk/Scripts/IntegrationManager/Editor/AppLovinIntegrationManagerWindow.cs +++ b/DemoApp/Assets/MaxSdk/Scripts/IntegrationManager/Editor/AppLovinIntegrationManagerWindow.cs @@ -36,6 +36,15 @@ public class AppLovinIntegrationManagerWindow : EditorWindow private const string customGradleVersionTooltip = "To set the version to 6.9.3, set the field to: https://services.gradle.org/distributions/gradle-6.9.3-bin.zip"; private const string customGradleToolsVersionTooltip = "To set the version to 4.2.0, set the field to: 4.2.0"; + private const string keyShowMicroSdkPartners = "com.applovin.show_micro_sdk_partners"; + private const string keyShowMediatedNetworks = "com.applovin.show_mediated_networks"; + private const string keyShowSdkSettings = "com.applovin.show_sdk_settings"; + private const string keyShowPrivacySettings = "com.applovin.show_privacy_settings"; + private const string keyShowOtherSettings = "com.applovin.show_other_settings"; + + private const string expandButtonText = "+"; + private const string collapseButtonText = "-"; + private readonly string[] termsFlowPlatforms = new string[3] {"Both", "Android", "iOS"}; private readonly string[] debugUserGeographies = new string[2] {"Not Set", "GDPR"}; @@ -55,6 +64,7 @@ public class AppLovinIntegrationManagerWindow : EditorWindow private static GUILayoutOption privacySettingFieldWidthOption = GUILayout.Width(400); private static readonly GUILayoutOption fieldWidth = GUILayout.Width(actionFieldWidth); private static readonly GUILayoutOption upgradeAllButtonFieldWidth = GUILayout.Width(upgradeAllButtonWidth); + private static readonly GUILayoutOption collapseButtonWidthOption = GUILayout.Width(20f); private static readonly Color darkModeTextColor = new Color(0.29f, 0.6f, 0.8f); @@ -216,28 +226,27 @@ private void OnGUI() if (pluginData != null && pluginData.PartnerMicroSdks != null) { - EditorGUILayout.LabelField("AppLovin Micro SDK Partners", titleLabelStyle); - DrawPartnerMicroSdks(); + DrawCollapsableSection(keyShowMicroSdkPartners, "AppLovin Micro SDK Partners", DrawPartnerMicroSdks); } - // Draw mediated networks - using (new EditorGUILayout.HorizontalScope(GUILayout.ExpandHeight(false))) + // Draw mediated networks); + EditorGUILayout.BeginHorizontal(); + var showDetails = DrawExpandCollapseButton(keyShowMediatedNetworks); + EditorGUILayout.LabelField("Mediated Networks", titleLabelStyle); + GUILayout.FlexibleSpace(); + DrawUpgradeAllButton(); + EditorGUILayout.EndHorizontal(); + if (showDetails) { - EditorGUILayout.LabelField("Mediated Networks", titleLabelStyle); - DrawUpgradeAllButton(); + DrawMediatedNetworks(); } - DrawMediatedNetworks(); - // Draw AppLovin Quality Service settings - EditorGUILayout.LabelField("SDK Settings", titleLabelStyle); - DrawQualityServiceSettings(); + DrawCollapsableSection(keyShowSdkSettings, "SDK Settings", DrawQualityServiceSettings); - EditorGUILayout.LabelField("Privacy Settings", titleLabelStyle); - DrawPrivacySettings(); + DrawCollapsableSection(keyShowPrivacySettings, "Privacy Settings", DrawPrivacySettings); - EditorGUILayout.LabelField("Other Settings", titleLabelStyle); - DrawOtherSettings(); + DrawCollapsableSection(keyShowOtherSettings, "Other Settings", DrawOtherSettings); // Draw Unity environment details EditorGUILayout.LabelField("Unity Environment Details", titleLabelStyle); @@ -956,6 +965,32 @@ private void DrawUnityEnvironmentDetailRow(string key, string value) } } + private void DrawCollapsableSection(string keyShowDetails, string label, Action drawContent) + { + EditorGUILayout.BeginHorizontal(); + var showDetails = DrawExpandCollapseButton(keyShowDetails); + + EditorGUILayout.LabelField(label, titleLabelStyle); + GUILayout.FlexibleSpace(); + EditorGUILayout.EndHorizontal(); + if (showDetails) + { + drawContent(); + } + } + + private bool DrawExpandCollapseButton(string keyShowDetails) + { + var showDetails = EditorPrefs.GetBool(keyShowDetails, true); + var buttonText = showDetails ? collapseButtonText : expandButtonText; + if (GUILayout.Button(buttonText, collapseButtonWidthOption)) + { + EditorPrefs.SetBool(keyShowDetails, !showDetails); + } + + return showDetails; + } + /// /// Calculates the fields width based on the width of the window. /// @@ -969,7 +1004,7 @@ private void CalculateFieldWidth() var versionLabelWidth = Math.Max(versionFieldMinWidth, availableWidth * versionFieldWidthPercentage); versionWidthOption = GUILayout.Width(versionLabelWidth); - const int textFieldOtherUiElementsWidth = 45; // NOTE: Magic number alert. This is the sum of all the spacing the fields and other UI elements. + const int textFieldOtherUiElementsWidth = 55; // NOTE: Magic number alert. This is the sum of all the spacing the fields and other UI elements. var availableUserDescriptionTextFieldWidth = currentWidth - privacySettingLabelWidth - textFieldOtherUiElementsWidth; privacySettingFieldWidthOption = GUILayout.Width(availableUserDescriptionTextFieldWidth); } diff --git a/DemoApp/Assets/MaxSdk/Scripts/IntegrationManager/Editor/AppLovinPostProcessAndroid.cs b/DemoApp/Assets/MaxSdk/Scripts/IntegrationManager/Editor/AppLovinPostProcessAndroid.cs index 1c34801..d32a735 100644 --- a/DemoApp/Assets/MaxSdk/Scripts/IntegrationManager/Editor/AppLovinPostProcessAndroid.cs +++ b/DemoApp/Assets/MaxSdk/Scripts/IntegrationManager/Editor/AppLovinPostProcessAndroid.cs @@ -7,18 +7,17 @@ // #if UNITY_ANDROID -using AppLovinMax.Scripts.IntegrationManager.Editor; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text.RegularExpressions; using System.Xml.Linq; +using AppLovinMax.ThirdParty.MiniJson; using UnityEditor; using UnityEditor.Android; -using UnityEngine; -namespace AppLovinMax.Scripts.Editor +namespace AppLovinMax.Scripts.IntegrationManager.Editor { /// /// A post processor used to update the Android project once it is generated. @@ -33,7 +32,6 @@ public class AppLovinPostProcessAndroid : IPostGenerateGradleAndroidProject private const string PropertyDexingArtifactTransform = "android.enableDexingArtifactTransform"; private const string DisableProperty = "=false"; - private const string KeyMetaDataAppLovinSdkKey = "applovin.sdk.key"; private const string KeyMetaDataAppLovinVerboseLoggingOn = "applovin.sdk.verbose_logging"; private const string KeyMetaDataGoogleApplicationId = "com.google.android.gms.ads.APPLICATION_ID"; private const string KeyMetaDataGoogleOptimizeInitialization = "com.google.android.gms.ads.flag.OPTIMIZE_INITIALIZATION"; @@ -42,6 +40,22 @@ public class AppLovinPostProcessAndroid : IPostGenerateGradleAndroidProject private const string KeyMetaDataMobileFuseAutoInit = "com.mobilefuse.sdk.disable_auto_init"; private const string KeyMetaDataMyTargetAutoInit = "com.my.target.autoInitMode"; + private const string KeyMetaDataAppLovinSdkKey = "applovin.sdk.key"; + + private const string AppLovinSettingsFileName = "applovin_settings.json"; + + private const string KeyTermsFlowSettings = "terms_flow_settings"; + private const string KeyTermsFlowEnabled = "terms_flow_enabled"; + private const string KeyTermsFlowTermsOfService = "terms_flow_terms_of_service"; + private const string KeyTermsFlowPrivacyPolicy = "terms_flow_privacy_policy"; + + private const string KeySdkKey = "sdk_key"; + private const string KeyConsentFlowSettings = "consent_flow_settings"; + private const string KeyConsentFlowEnabled = "consent_flow_enabled"; + private const string KeyConsentFlowTermsOfService = "consent_flow_terms_of_service"; + private const string KeyConsentFlowPrivacyPolicy = "consent_flow_privacy_policy"; + private const string KeyConsentFlowDebugUserGeography = "consent_flow_debug_user_geography"; + #if UNITY_2022_3_OR_NEWER // To match "'com.android.library' version '7.3.1'" line in build.gradle private static readonly Regex TokenGradleVersionLibrary = new Regex(".*id ['\"]com\\.android\\.library['\"] version"); @@ -100,8 +114,12 @@ public void OnPostGenerateGradleAndroidProject(string path) gradlePropertiesUpdated.Add(PropertyAndroidX + EnableProperty); gradlePropertiesUpdated.Add(PropertyJetifier + EnableProperty); #endif + + // `DexingArtifactTransform` has been removed in Gradle 8+ which is the default Gradle version for Unity 6. +#if !UNITY_6000_0_OR_NEWER // Disable dexing using artifact transform (it causes issues for ExoPlayer with Gradle plugin 3.5.0+) gradlePropertiesUpdated.Add(PropertyDexingArtifactTransform + DisableProperty); +#endif try { @@ -114,16 +132,7 @@ public void OnPostGenerateGradleAndroidProject(string path) } ProcessAndroidManifest(path); - - var rawResourceDirectory = Path.Combine(path, "src/main/res/raw"); - if (AppLovinInternalSettings.Instance.ConsentFlowEnabled) - { - AppLovinPreProcessAndroid.EnableConsentFlowIfNeeded(rawResourceDirectory); - } - else - { - AppLovinPreProcessAndroid.EnableTermsFlowIfNeeded(rawResourceDirectory); - } + AddSdkSettings(path); } public int callbackOrder @@ -164,41 +173,16 @@ private static void ProcessAndroidManifest(string path) var metaDataElements = elementApplication.Descendants().Where(element => element.Name.LocalName.Equals("meta-data")); - AddSdkKeyIfNeeded(elementApplication); EnableVerboseLoggingIfNeeded(elementApplication); AddGoogleApplicationIdIfNeeded(elementApplication, metaDataElements); AddGoogleOptimizationFlagsIfNeeded(elementApplication, metaDataElements); DisableAutoInitIfNeeded(elementApplication, metaDataElements); + RemoveSdkKeyIfNeeded(metaDataElements); // Save the updated manifest file. manifest.Save(manifestPath); } - private static void AddSdkKeyIfNeeded(XElement elementApplication) - { - var sdkKey = AppLovinSettings.Instance.SdkKey; - if (string.IsNullOrEmpty(sdkKey)) return; - - var descendants = elementApplication.Descendants(); - var sdkKeyMetaData = descendants.FirstOrDefault(descendant => descendant.FirstAttribute != null && - descendant.FirstAttribute.Name.LocalName.Equals("name") && - descendant.FirstAttribute.Value.Equals(KeyMetaDataAppLovinSdkKey) && - descendant.LastAttribute != null && - descendant.LastAttribute.Name.LocalName.Equals("value")); - - // check if applovin.sdk.key meta data exists. - if (sdkKeyMetaData != null) - { - sdkKeyMetaData.LastAttribute.Value = sdkKey; - } - else - { - // add applovin.sdk.key meta data if it does not exist. - var metaData = CreateMetaDataElement(KeyMetaDataAppLovinSdkKey, sdkKey); - elementApplication.Add(metaData); - } - } - private static void EnableVerboseLoggingIfNeeded(XElement elementApplication) { var enabled = EditorPrefs.GetBool(MaxSdkLogger.KeyVerboseLoggingEnabled, false); @@ -302,6 +286,14 @@ private static void DisableAutoInitIfNeeded(XElement elementApplication, IEnumer } } + private static void RemoveSdkKeyIfNeeded(IEnumerable metaDataElements) + { + var sdkKeyMetaData = GetMetaDataElement(metaDataElements, KeyMetaDataAppLovinSdkKey); + if (sdkKeyMetaData == null) return; + + sdkKeyMetaData.Remove(); + } + private static void UpdateGradleVersionsIfNeeded(string gradleWrapperPropertiesPath, string rootGradleBuildFilePath) { var customGradleVersionUrl = AppLovinSettings.Instance.CustomGradleVersionUrl; @@ -355,6 +347,145 @@ private static void UpdateGradleVersionsIfNeeded(string gradleWrapperPropertiesP } } + private static void AddSdkSettings(string path) + { + var appLovinSdkSettings = new Dictionary(); + var rawResourceDirectory = Path.Combine(path, "src/main/res/raw"); + + // Add the SDK key to the SDK settings. + appLovinSdkSettings[KeySdkKey] = AppLovinSettings.Instance.SdkKey; + + // Add the Consent/Terms flow settings if needed. + if (AppLovinInternalSettings.Instance.ConsentFlowEnabled) + { + EnableConsentFlowIfNeeded(rawResourceDirectory, appLovinSdkSettings); + } + else + { + EnableTermsFlowIfNeeded(rawResourceDirectory, appLovinSdkSettings); + } + + WriteAppLovinSettings(rawResourceDirectory, appLovinSdkSettings); + } + + private static void EnableConsentFlowIfNeeded(string rawResourceDirectory, Dictionary applovinSdkSettings) + { + // Check if consent flow is enabled. No need to create the applovin_consent_flow_settings.json if consent flow is disabled. + var consentFlowEnabled = AppLovinInternalSettings.Instance.ConsentFlowEnabled; + if (!consentFlowEnabled) + { + RemoveAppLovinSettingsRawResourceFileIfNeeded(rawResourceDirectory); + return; + } + + var privacyPolicyUrl = AppLovinInternalSettings.Instance.ConsentFlowPrivacyPolicyUrl; + if (string.IsNullOrEmpty(privacyPolicyUrl)) + { + AppLovinIntegrationManager.ShowBuildFailureDialog("You cannot use the AppLovin SDK's consent flow without defining a Privacy Policy URL in the AppLovin Integration Manager."); + + // No need to update the applovin_consent_flow_settings.json here. Default consent flow state will be determined on the SDK side. + return; + } + + var consentFlowSettings = new Dictionary(); + consentFlowSettings[KeyConsentFlowEnabled] = consentFlowEnabled; + consentFlowSettings[KeyConsentFlowPrivacyPolicy] = privacyPolicyUrl; + + var termsOfServiceUrl = AppLovinInternalSettings.Instance.ConsentFlowTermsOfServiceUrl; + if (MaxSdkUtils.IsValidString(termsOfServiceUrl)) + { + consentFlowSettings[KeyConsentFlowTermsOfService] = termsOfServiceUrl; + } + + var debugUserGeography = AppLovinInternalSettings.Instance.DebugUserGeography; + if (debugUserGeography == MaxSdkBase.ConsentFlowUserGeography.Gdpr) + { + consentFlowSettings[KeyConsentFlowDebugUserGeography] = "gdpr"; + } + + applovinSdkSettings[KeyConsentFlowSettings] = consentFlowSettings; + } + + private static void EnableTermsFlowIfNeeded(string rawResourceDirectory, Dictionary applovinSdkSettings) + { + if (AppLovinInternalSettings.Instance.ConsentFlowEnabled) return; + + // Check if terms flow is enabled for this format. No need to create the applovin_consent_flow_settings.json if consent flow is disabled. + var consentFlowEnabled = AppLovinSettings.Instance.ConsentFlowEnabled; + var consentFlowPlatform = AppLovinSettings.Instance.ConsentFlowPlatform; + if (!consentFlowEnabled || (consentFlowPlatform != Platform.All && consentFlowPlatform != Platform.Android)) + { + RemoveAppLovinSettingsRawResourceFileIfNeeded(rawResourceDirectory); + return; + } + + var privacyPolicyUrl = AppLovinSettings.Instance.ConsentFlowPrivacyPolicyUrl; + if (string.IsNullOrEmpty(privacyPolicyUrl)) + { + AppLovinIntegrationManager.ShowBuildFailureDialog("You cannot use the AppLovin SDK's consent flow without defining a Privacy Policy URL in the AppLovin Integration Manager."); + + // No need to update the applovin_consent_flow_settings.json here. Default consent flow state will be determined on the SDK side. + return; + } + + var consentFlowSettings = new Dictionary(); + consentFlowSettings[KeyTermsFlowEnabled] = consentFlowEnabled; + consentFlowSettings[KeyTermsFlowPrivacyPolicy] = privacyPolicyUrl; + + var termsOfServiceUrl = AppLovinSettings.Instance.ConsentFlowTermsOfServiceUrl; + if (MaxSdkUtils.IsValidString(termsOfServiceUrl)) + { + consentFlowSettings[KeyTermsFlowTermsOfService] = termsOfServiceUrl; + } + + applovinSdkSettings[KeyTermsFlowSettings] = consentFlowSettings; + } + + private static void WriteAppLovinSettingsRawResourceFile(string applovinSdkSettingsJson, string rawResourceDirectory) + { + if (!Directory.Exists(rawResourceDirectory)) + { + Directory.CreateDirectory(rawResourceDirectory); + } + + var consentFlowSettingsFilePath = Path.Combine(rawResourceDirectory, AppLovinSettingsFileName); + try + { + File.WriteAllText(consentFlowSettingsFilePath, applovinSdkSettingsJson + "\n"); + } + catch (Exception exception) + { + MaxSdkLogger.UserError("applovin_settings.json file write failed due to: " + exception.Message); + Console.WriteLine(exception); + } + } + + /// + /// Removes the applovin_settings json file from the build if it exists. + /// + /// The raw resource directory that holds the json file + private static void RemoveAppLovinSettingsRawResourceFileIfNeeded(string rawResourceDirectory) + { + var consentFlowSettingsFilePath = Path.Combine(rawResourceDirectory, AppLovinSettingsFileName); + if (!File.Exists(consentFlowSettingsFilePath)) return; + + try + { + File.Delete(consentFlowSettingsFilePath); + } + catch (Exception exception) + { + MaxSdkLogger.UserError("Deleting applovin_settings.json failed due to: " + exception.Message); + Console.WriteLine(exception); + } + } + + private static void WriteAppLovinSettings(string rawResourceDirectory, Dictionary applovinSdkSettings) + { + var applovinSdkSettingsJson = Json.Serialize(applovinSdkSettings); + WriteAppLovinSettingsRawResourceFile(applovinSdkSettingsJson, rawResourceDirectory); + } + /// /// Creates and returns a meta-data element with the given name and value. /// diff --git a/DemoApp/Assets/MaxSdk/Scripts/IntegrationManager/Editor/AppLovinPostProcessiOS.cs b/DemoApp/Assets/MaxSdk/Scripts/IntegrationManager/Editor/AppLovinPostProcessiOS.cs index d8ee3c7..179a696 100644 --- a/DemoApp/Assets/MaxSdk/Scripts/IntegrationManager/Editor/AppLovinPostProcessiOS.cs +++ b/DemoApp/Assets/MaxSdk/Scripts/IntegrationManager/Editor/AppLovinPostProcessiOS.cs @@ -7,12 +7,12 @@ // #if UNITY_IOS || UNITY_IPHONE - using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; +using System.Text.RegularExpressions; using UnityEditor; using UnityEditor.Callbacks; #if UNITY_2019_3_OR_NEWER @@ -22,6 +22,7 @@ using UnityEngine; using Debug = UnityEngine.Debug; using UnityEngine.Networking; +using VersionComparisonResult = MaxSdkUtils.VersionComparisonResult; namespace AppLovinMax.Scripts.IntegrationManager.Editor { @@ -35,91 +36,34 @@ public class AppLovinPostProcessiOS { private const string OutputFileName = "AppLovinQualityServiceSetup.rb"; -#if UNITY_2019_3_OR_NEWER +#if !UNITY_2019_3_OR_NEWER + private const string UnityMainTargetName = "Unity-iPhone"; +#endif + private const string TargetUnityIphonePodfileLine = "target 'Unity-iPhone' do"; private const string UseFrameworksPodfileLine = "use_frameworks!"; private const string UseFrameworksDynamicPodfileLine = "use_frameworks! :linkage => :dynamic"; private const string UseFrameworksStaticPodfileLine = "use_frameworks! :linkage => :static"; -#else - private const string UnityMainTargetName = "Unity-iPhone"; -#endif + private const string LegacyResourcesDirectoryName = "Resources"; private const string AppLovinMaxResourcesDirectoryName = "AppLovinMAXResources"; private const string AppLovinAdvertisingAttributionEndpoint = "https://postbacks-app.com"; private const string AppLovinSettingsPlistFileName = "AppLovin-Settings.plist"; + + private const string KeySdkKey = "SdkKey"; + + private const string AppLovinVerboseLoggingOnKey = "AppLovinVerboseLoggingOn"; + private const string KeyConsentFlowInfo = "ConsentFlowInfo"; private const string KeyConsentFlowEnabled = "ConsentFlowEnabled"; private const string KeyConsentFlowTermsOfService = "ConsentFlowTermsOfService"; private const string KeyConsentFlowPrivacyPolicy = "ConsentFlowPrivacyPolicy"; private const string KeyConsentFlowDebugUserGeography = "ConsentFlowDebugUserGeography"; - private static List DynamicLibrariesToEmbed - { - get - { - var dynamicLibrariesToEmbed = new List - { - "AppLovinSDK.xcframework", - "DTBiOSSDK.xcframework", - "FBAEMKit.xcframework", - "FBSDKCoreKit_Basics.xcframework", - "FBSDKCoreKit.xcframework", - "FBSDKGamingServicesKit.xcframework", - "FBSDKLoginKit.xcframework", - "FBSDKShareKit.xcframework", - "HyprMX.xcframework", - "Maio.xcframework", - "MobileFuseSDK.xcframework", - "MolocoSDK.xcframework", - "OMSDK_Appodeal.xcframework", - "OMSDK_Ogury.xcframework", - "OMSDK_Pubnativenet.xcframework", - "OMSDK_Smaato.xcframework" - }; - - // LinkedIn Audience Network SDK is distributed as a static library starting version 1.2.0 - if (AppLovinIntegrationManager.IsAdapterOlderThanMinVersionInstalled("LinkedIn", "1.2.0.0")) - { - dynamicLibrariesToEmbed.Add("LinkedinAudienceNetwork.xcframework"); - } - - // Fyber/IA SDK is distributed as a static library starting version 8.2.7 - if (AppLovinIntegrationManager.IsAdapterOlderThanMinVersionInstalled("Fyber", "8.2.7.0")) - { - dynamicLibrariesToEmbed.Add("IASDKCore.xcframework"); - } - - if (AppLovinIntegrationManager.IsAdapterInstalled("InMobi", "10.7.2.0")) - { - dynamicLibrariesToEmbed.Add("InMobiSDK.xcframework"); - } - - if (AppLovinIntegrationManager.IsAdapterInstalled("Smaato", "22.8.3.0")) - { - dynamicLibrariesToEmbed.AddRange(new List() - { - "SmaatoSDKBanner.xcframework", - "SmaatoSDKCore.xcframework", - "SmaatoSDKInAppBidding.xcframework", - "SmaatoSDKInterstitial.xcframework", - "SmaatoSDKNative.xcframework", - "SmaatoSDKOpenMeasurement.xcframework", - "SmaatoSDKOutstream.xcframework", - "SmaatoSDKRewardedAds.xcframework", - "SmaatoSDKRichMedia.xcframework", - "SmaatoSDKVideo.xcframework" - }); - } + private const string KeyAppLovinSdkKeyToRemove = "AppLovinSdkKey"; - if (AppLovinIntegrationManager.IsAdapterInstalled("Verve", "3.0.0.0")) - { - dynamicLibrariesToEmbed.Add("ATOM.xcframework"); - } - - return dynamicLibrariesToEmbed; - } - } + private static readonly Regex PodfilePodLineRegex = new Regex("pod \'([^\']*)\'"); private static string PluginMediationDirectory { @@ -202,7 +146,7 @@ public static void OnPostProcessBuild(BuildTarget buildTarget, string buildPath) } } - [PostProcessBuildAttribute(int.MaxValue)] + [PostProcessBuild(int.MaxValue)] public static void MaxPostProcessPbxProject(BuildTarget buildTarget, string buildPath) { var projectPath = PBXProject.GetPBXProjectPath(buildPath); @@ -246,31 +190,16 @@ private static void EmbedDynamicLibrariesIfNeeded(string buildPath, PBXProject p { // Check that the Pods directory exists (it might not if a publisher is building with Generate Podfile setting disabled in EDM). var podsDirectory = Path.Combine(buildPath, "Pods"); - if (!Directory.Exists(podsDirectory)) return; + if (!Directory.Exists(podsDirectory) || !ShouldEmbedDynamicLibraries(buildPath)) return; - var dynamicLibraryPathsPresentInProject = new List(); - foreach (var dynamicLibraryToSearch in DynamicLibrariesToEmbed) - { - // both .framework and .xcframework are directories, not files - var directories = Directory.GetDirectories(podsDirectory, dynamicLibraryToSearch, SearchOption.AllDirectories); - if (directories.Length <= 0) continue; - - var dynamicLibraryAbsolutePath = directories[0]; - var index = dynamicLibraryAbsolutePath.LastIndexOf("Pods"); - var relativePath = dynamicLibraryAbsolutePath.Substring(index); - dynamicLibraryPathsPresentInProject.Add(relativePath); - } - - if (dynamicLibraryPathsPresentInProject.Count <= 0) return; + var dynamicLibraryPathsToEmbed = GetDynamicLibraryPathsToEmbed(podsDirectory, buildPath); + if (dynamicLibraryPathsToEmbed == null || dynamicLibraryPathsToEmbed.Count == 0) return; #if UNITY_2019_3_OR_NEWER - if (ShouldEmbedDynamicLibraries(buildPath)) + foreach (var dynamicLibraryPath in dynamicLibraryPathsToEmbed) { - foreach (var dynamicLibraryPath in dynamicLibraryPathsPresentInProject) - { - var fileGuid = project.AddFile(dynamicLibraryPath, dynamicLibraryPath); - project.AddFileToEmbedFrameworks(targetGuid, fileGuid); - } + var fileGuid = project.AddFile(dynamicLibraryPath, dynamicLibraryPath); + project.AddFileToEmbedFrameworks(targetGuid, fileGuid); } #else string runpathSearchPaths; @@ -285,6 +214,155 @@ private static void EmbedDynamicLibrariesIfNeeded(string buildPath, PBXProject p #endif } + /// + /// |-----------------------------------------------------------------------------------------------------------------------------------------------------| + /// | embed | use_frameworks! (:linkage => :dynamic) | use_frameworks! :linkage => :static | `use_frameworks!` line not present | + /// |---------------------------|------------------------------------------|---------------------------------------|--------------------------------------| + /// | Unity-iPhone present | Do not embed dynamic libraries | Embed dynamic libraries | Do not embed dynamic libraries | + /// | Unity-iPhone not present | Embed dynamic libraries | Embed dynamic libraries | Embed dynamic libraries | + /// |-----------------------------------------------------------------------------------------------------------------------------------------------------| + /// + /// An iOS build path + /// Whether or not the dynamic libraries should be embedded. + private static bool ShouldEmbedDynamicLibraries(string buildPath) + { + var podfilePath = Path.Combine(buildPath, "Podfile"); + if (!File.Exists(podfilePath)) return false; + + // If the Podfile doesn't have a `Unity-iPhone` target, we should embed the dynamic libraries. + var lines = File.ReadAllLines(podfilePath); + var containsUnityIphoneTarget = lines.Any(line => line.Contains(TargetUnityIphonePodfileLine)); + if (!containsUnityIphoneTarget) return true; + + // If the Podfile does not have a `use_frameworks! :linkage => static` line, we should not embed the dynamic libraries. + var useFrameworksStaticLineIndex = Array.FindIndex(lines, line => line.Contains(UseFrameworksStaticPodfileLine)); + if (useFrameworksStaticLineIndex == -1) return false; + + // If more than one of the `use_frameworks!` lines are present, CocoaPods will use the last one. + var useFrameworksLineIndex = Array.FindIndex(lines, line => line.Trim() == UseFrameworksPodfileLine); // Check for exact line to avoid matching `use_frameworks! :linkage => static/dynamic` + var useFrameworksDynamicLineIndex = Array.FindIndex(lines, line => line.Contains(UseFrameworksDynamicPodfileLine)); + + // Check if `use_frameworks! :linkage => :static` is the last line of the three. If it is, we should embed the dynamic libraries. + return useFrameworksLineIndex < useFrameworksStaticLineIndex && useFrameworksDynamicLineIndex < useFrameworksStaticLineIndex; + } + + private static List GetDynamicLibraryPathsToEmbed(string podsDirectory, string buildPath) + { + var podfilePath = Path.Combine(buildPath, "Podfile"); + var dynamicLibraryFrameworksToEmbed = GetDynamicLibraryFrameworksToEmbed(podfilePath); + + return GetDynamicLibraryPathsInProjectToEmbed(podsDirectory, dynamicLibraryFrameworksToEmbed); + } + + private static List GetDynamicLibraryFrameworksToEmbed(string podfilePath) + { + var dynamicLibrariesToEmbed = GetDynamicLibrariesToEmbed(); + + var podsInUnityIphoneTarget = GetPodNamesInUnityIphoneTarget(podfilePath); + var dynamicLibrariesToIgnore = dynamicLibrariesToEmbed.Where(dynamicLibraryToEmbed => podsInUnityIphoneTarget.Contains(dynamicLibraryToEmbed.PodName)).ToList(); + + // Determine frameworks to embed based on the dynamic libraries to embed and ignore + var dynamicLibraryFrameworksToIgnore = dynamicLibrariesToIgnore.SelectMany(library => library.FrameworkNames).Distinct().ToList(); + return dynamicLibrariesToEmbed.SelectMany(library => library.FrameworkNames).Except(dynamicLibraryFrameworksToIgnore).Distinct().ToList(); + } + + private static List GetDynamicLibrariesToEmbed() + { + var pluginData = AppLovinIntegrationManager.LoadPluginDataSync(); + if (pluginData == null) + { + MaxSdkLogger.E("Failed to load plugin data. Dynamic libraries will not be embedded."); + return null; + } + + // Get the dynamic libraries to embed for each network + var librariesToAdd = pluginData.MediatedNetworks + .Where(network => network.DynamicLibrariesToEmbed != null) + .SelectMany(network => network.DynamicLibrariesToEmbed + .Where(libraryToEmbed => IsRequiredNetworkVersionInstalled(libraryToEmbed, network))) + .ToList(); + + // Get the dynamic libraries to embed for AppLovin MAX + if (pluginData.AppLovinMax.DynamicLibrariesToEmbed != null) + { + librariesToAdd.AddRange(pluginData.AppLovinMax.DynamicLibrariesToEmbed); + } + + // Get the dynamic libraries to embed for third parties + if (pluginData.ThirdPartyDynamicLibrariesToEmbed != null) + { + // TODO: Add version check for third party dynamic libraries. + librariesToAdd.AddRange(pluginData.ThirdPartyDynamicLibrariesToEmbed); + } + + return librariesToAdd; + } + + private static List GetPodNamesInUnityIphoneTarget(string podfilePath) + { + var lines = File.ReadAllLines(podfilePath); + var podNamesInUnityIphone = new List(); + + var insideUnityIphoneTarget = false; + foreach (var line in lines) + { + // Loop until we find the `target 'Unity-iPhone'` line + if (insideUnityIphoneTarget) + { + if (line.Trim() == "end") break; + + if (PodfilePodLineRegex.IsMatch(line)) + { + var podName = PodfilePodLineRegex.Match(line).Groups[1].Value; + podNamesInUnityIphone.Add(podName); + } + } + else if (line.Contains(TargetUnityIphonePodfileLine)) + { + insideUnityIphoneTarget = true; + } + } + + return podNamesInUnityIphone; + } + + private static bool IsRequiredNetworkVersionInstalled(DynamicLibraryToEmbed libraryToEmbed, Network network) + { + var currentIosVersion = network.CurrentVersions.Ios; + if (string.IsNullOrEmpty(currentIosVersion)) return false; + + var minIosVersion = libraryToEmbed.MinVersion; + var maxIosVersion = libraryToEmbed.MaxVersion; + + var greaterThanOrEqualToMinVersion = string.IsNullOrEmpty(minIosVersion) || MaxSdkUtils.CompareVersions(currentIosVersion, minIosVersion) != VersionComparisonResult.Lesser; + var lessThanOrEqualToMaxVersion = string.IsNullOrEmpty(maxIosVersion) || MaxSdkUtils.CompareVersions(currentIosVersion, maxIosVersion) != VersionComparisonResult.Greater; + + return greaterThanOrEqualToMinVersion && lessThanOrEqualToMaxVersion; + } + + private static List GetDynamicLibraryPathsInProjectToEmbed(string podsDirectory, List dynamicLibrariesToEmbed) + { + var dynamicLibraryPathsPresentInProject = new List(); + foreach (var dynamicLibraryToSearch in dynamicLibrariesToEmbed) + { + // both .framework and .xcframework are directories, not files + var directories = Directory.GetDirectories(podsDirectory, dynamicLibraryToSearch, SearchOption.AllDirectories); + if (directories.Length <= 0) continue; + + var dynamicLibraryAbsolutePath = directories[0]; + var relativePath = GetDynamicLibraryRelativePath(dynamicLibraryAbsolutePath); + dynamicLibraryPathsPresentInProject.Add(relativePath); + } + + return dynamicLibraryPathsPresentInProject; + } + + private static string GetDynamicLibraryRelativePath(string dynamicLibraryAbsolutePath) + { + var index = dynamicLibraryAbsolutePath.LastIndexOf("Pods", StringComparison.Ordinal); + return dynamicLibraryAbsolutePath.Substring(index); + } + private static void LocalizeUserTrackingDescriptionIfNeeded(string localizedUserTrackingDescription, string localeCode, string buildPath, PBXProject project, string targetGuid) { // Use the legacy resources directory name if the build is being appended (the "Resources" directory already exists if it is an incremental build). @@ -370,7 +448,7 @@ private static void AddSwiftSupport(string buildPath, PBXProject project, string // Add Swift file CreateSwiftFile(swiftFilePath); - var swiftFileGuid = project.AddFile(swiftFileRelativePath, swiftFileRelativePath, PBXSourceTree.Source); + var swiftFileGuid = project.AddFile(swiftFileRelativePath, swiftFileRelativePath); project.AddFileToBuild(unityFrameworkTargetGuid, swiftFileGuid); // Add Swift version property if needed @@ -400,35 +478,26 @@ private static void CreateSwiftFile(string swiftFilePath) } } - [PostProcessBuildAttribute(int.MaxValue)] + [PostProcessBuild(int.MaxValue)] public static void MaxPostProcessPlist(BuildTarget buildTarget, string path) { var plistPath = Path.Combine(path, "Info.plist"); var plist = new PlistDocument(); plist.ReadFromFile(plistPath); - SetSdkKeyIfNeeded(plist); SetAttributionReportEndpointIfNeeded(plist); EnableVerboseLoggingIfNeeded(plist); AddGoogleApplicationIdIfNeeded(plist); - AddSdkSettingsIfNeeded(plist, path); + AddSdkSettings(plist, path); EnableTermsFlowIfNeeded(plist); AddSkAdNetworksInfoIfNeeded(plist); + RemoveSdkKeyIfNeeded(plist); plist.WriteToFile(plistPath); } - private static void SetSdkKeyIfNeeded(PlistDocument plist) - { - var sdkKey = AppLovinSettings.Instance.SdkKey; - if (string.IsNullOrEmpty(sdkKey)) return; - - const string AppLovinVerboseLoggingOnKey = "AppLovinSdkKey"; - plist.root.SetString(AppLovinVerboseLoggingOnKey, sdkKey); - } - private static void SetAttributionReportEndpointIfNeeded(PlistDocument plist) { if (AppLovinSettings.Instance.SetAttributionReportEndpoint) @@ -453,10 +522,9 @@ private static void EnableVerboseLoggingIfNeeded(PlistDocument plist) if (!EditorPrefs.HasKey(MaxSdkLogger.KeyVerboseLoggingEnabled)) return; var enabled = EditorPrefs.GetBool(MaxSdkLogger.KeyVerboseLoggingEnabled); - const string AppLovinVerboseLoggingOnKey = "AppLovinVerboseLoggingOn"; if (enabled) { - plist.root.SetBoolean(AppLovinVerboseLoggingOnKey, enabled); + plist.root.SetBoolean(AppLovinVerboseLoggingOnKey, true); } else { @@ -473,7 +541,7 @@ private static void AddGoogleApplicationIdIfNeeded(PlistDocument plist) // Log error if the App ID is not set. if (string.IsNullOrEmpty(appId) || !appId.StartsWith("ca-app-pub-")) { - Debug.LogError("[AppLovin MAX] Google App ID is not set. Please enter a valid app ID within the AppLovin Integration Manager window."); + MaxSdkLogger.UserError("[AppLovin MAX] Google App ID is not set. Please enter a valid app ID within the AppLovin Integration Manager window."); return; } @@ -486,18 +554,15 @@ private static void AddYandexSettingsIfNeeded(PBXProject project, string unityMa if (MaxSdkUtils.CompareVersions(PlayerSettings.iOS.targetOSVersionString, "12.0") == MaxSdkUtils.VersionComparisonResult.Lesser) { - Debug.LogWarning("Your iOS target version is under the minimum required version by Yandex. Please update it to 12.0 or newer in your ProjectSettings and rebuild your project."); + MaxSdkLogger.UserWarning("Your iOS target version is under the minimum required version by Yandex. Please update it to 12.0 or newer in your ProjectSettings and rebuild your project."); return; } project.SetBuildProperty(unityMainTargetGuid, "GENERATE_INFOPLIST_FILE", "NO"); } - private static void AddSdkSettingsIfNeeded(PlistDocument infoPlist, string buildPath) + private static void AddSdkSettings(PlistDocument infoPlist, string buildPath) { - // Right now internal settings is only needed for Consent Flow. Remove this setting once we add more settings. - if (!AppLovinInternalSettings.Instance.ConsentFlowEnabled) return; - var sdkSettingsPlistPath = Path.Combine(buildPath, AppLovinSettingsPlistFileName); var sdkSettingsPlist = new PlistDocument(); if (File.Exists(sdkSettingsPlistPath)) @@ -505,6 +570,10 @@ private static void AddSdkSettingsIfNeeded(PlistDocument infoPlist, string build sdkSettingsPlist.ReadFromFile(sdkSettingsPlistPath); } + // Add the SDK key to the SDK settings plist. + sdkSettingsPlist.root.SetString(KeySdkKey, AppLovinSettings.Instance.SdkKey); + + // Add consent flow settings if needed. EnableConsentFlowIfNeeded(sdkSettingsPlist, infoPlist); sdkSettingsPlist.WriteToFile(sdkSettingsPlistPath); @@ -527,6 +596,8 @@ private static void AddSdkSettingsIfNeeded(PlistDocument infoPlist, string build private static void EnableConsentFlowIfNeeded(PlistDocument applovinSettingsPlist, PlistDocument infoPlist) { var consentFlowEnabled = AppLovinInternalSettings.Instance.ConsentFlowEnabled; + if (!consentFlowEnabled) return; + var userTrackingUsageDescription = AppLovinInternalSettings.Instance.UserTrackingUsageDescriptionEn; var privacyPolicyUrl = AppLovinInternalSettings.Instance.ConsentFlowPrivacyPolicyUrl; if (string.IsNullOrEmpty(userTrackingUsageDescription) || string.IsNullOrEmpty(privacyPolicyUrl)) @@ -579,7 +650,7 @@ private static void EnableTermsFlowIfNeeded(PlistDocument plist) } var consentFlowInfoRoot = plist.root.CreateDict("AppLovinConsentFlowInfo"); - consentFlowInfoRoot.SetBoolean("AppLovinConsentFlowEnabled", consentFlowEnabled); + consentFlowInfoRoot.SetBoolean("AppLovinConsentFlowEnabled", true); consentFlowInfoRoot.SetString("AppLovinConsentFlowPrivacyPolicy", privacyPolicyUrl); var termsOfServiceUrl = AppLovinSettings.Instance.ConsentFlowTermsOfServiceUrl; @@ -661,7 +732,7 @@ private static SkAdNetworkData GetSkAdNetworkData() var installedNetworks = mediationNetworkDirectories.Select(Path.GetFileName).ToList(); if (AppLovinSettings.Instance.AddApsSkAdNetworkIds) { - installedNetworks.Add("AmazonPublisherServices"); + installedNetworks.Add("AmazonAdMarketplace"); } var adNetworks = string.Join(",", installedNetworks.ToArray()); @@ -699,39 +770,12 @@ private static SkAdNetworkData GetSkAdNetworkData() } } -#if UNITY_2019_3_OR_NEWER - /// - /// |-----------------------------------------------------------------------------------------------------------------------------------------------------| - /// | embed | use_frameworks! (:linkage => :dynamic) | use_frameworks! :linkage => :static | `use_frameworks!` line not present | - /// |---------------------------|------------------------------------------|---------------------------------------|--------------------------------------| - /// | Unity-iPhone present | Do not embed dynamic libraries | Embed dynamic libraries | Do not embed dynamic libraries | - /// | Unity-iPhone not present | Embed dynamic libraries | Embed dynamic libraries | Embed dynamic libraries | - /// |-----------------------------------------------------------------------------------------------------------------------------------------------------| - /// - /// An iOS build path - /// Whether or not the dynamic libraries should be embedded. - private static bool ShouldEmbedDynamicLibraries(string buildPath) + private static void RemoveSdkKeyIfNeeded(PlistDocument plist) { - var podfilePath = Path.Combine(buildPath, "Podfile"); - if (!File.Exists(podfilePath)) return false; - - // If the Podfile doesn't have a `Unity-iPhone` target, we should embed the dynamic libraries. - var lines = File.ReadAllLines(podfilePath); - var containsUnityIphoneTarget = lines.Any(line => line.Contains(TargetUnityIphonePodfileLine)); - if (!containsUnityIphoneTarget) return true; + if (!plist.root.values.ContainsKey(KeyAppLovinSdkKeyToRemove)) return; - // If the Podfile does not have a `use_frameworks! :linkage => static` line, we should not embed the dynamic libraries. - var useFrameworksStaticLineIndex = Array.FindIndex(lines, line => line.Contains(UseFrameworksStaticPodfileLine)); - if (useFrameworksStaticLineIndex == -1) return false; - - // If more than one of the `use_frameworks!` lines are present, CocoaPods will use the last one. - var useFrameworksLineIndex = Array.FindIndex(lines, line => line.Trim() == UseFrameworksPodfileLine); // Check for exact line to avoid matching `use_frameworks! :linkage => static/dynamic` - var useFrameworksDynamicLineIndex = Array.FindIndex(lines, line => line.Contains(UseFrameworksDynamicPodfileLine)); - - // Check if `use_frameworks! :linkage => :static` is the last line of the three. If it is, we should embed the dynamic libraries. - return useFrameworksLineIndex < useFrameworksStaticLineIndex && useFrameworksDynamicLineIndex < useFrameworksStaticLineIndex; + plist.root.values.Remove(KeyAppLovinSdkKeyToRemove); } -#endif } } diff --git a/DemoApp/Assets/MaxSdk/Scripts/IntegrationManager/Editor/AppLovinPreProcess.cs b/DemoApp/Assets/MaxSdk/Scripts/IntegrationManager/Editor/AppLovinPreProcess.cs index 2b8500d..3f6e2b8 100644 --- a/DemoApp/Assets/MaxSdk/Scripts/IntegrationManager/Editor/AppLovinPreProcess.cs +++ b/DemoApp/Assets/MaxSdk/Scripts/IntegrationManager/Editor/AppLovinPreProcess.cs @@ -42,7 +42,7 @@ protected static void TryAddStringToDependencyFile(string lineToAdd, string cont if (containerElement == null) { - Debug.LogError(containerElementString + " not found in Dependencies.xml file"); + MaxSdkLogger.E(containerElementString + " not found in Dependencies.xml file"); return; } @@ -61,7 +61,7 @@ protected static void TryAddStringToDependencyFile(string lineToAdd, string cont } catch (Exception exception) { - Debug.LogError("Google CMP will not function. Unable to add string to dependency file due to exception: " + exception.Message); + MaxSdkLogger.UserWarning("Google CMP will not function. Unable to add string to dependency file due to exception: " + exception.Message); } } @@ -80,7 +80,7 @@ protected static void TryRemoveStringFromDependencyFile(string lineToRemove, str if (containerElement == null) { - Debug.LogError(containerElementString + " not found in Dependencies.xml file"); + MaxSdkLogger.E(containerElementString + " not found in Dependencies.xml file"); return; } @@ -98,7 +98,7 @@ protected static void TryRemoveStringFromDependencyFile(string lineToRemove, str } catch (Exception exception) { - Debug.LogError("Unable to remove string from dependency file due to exception: " + exception.Message); + MaxSdkLogger.UserWarning("Unable to remove string from dependency file due to exception: " + exception.Message); } } } diff --git a/DemoApp/Assets/MaxSdk/Scripts/IntegrationManager/Editor/AppLovinPreProcessAndroid.cs b/DemoApp/Assets/MaxSdk/Scripts/IntegrationManager/Editor/AppLovinPreProcessAndroid.cs index 61bea2b..204a7ba 100644 --- a/DemoApp/Assets/MaxSdk/Scripts/IntegrationManager/Editor/AppLovinPreProcessAndroid.cs +++ b/DemoApp/Assets/MaxSdk/Scripts/IntegrationManager/Editor/AppLovinPreProcessAndroid.cs @@ -8,16 +8,8 @@ #if UNITY_ANDROID -using System.Linq; -using System; -using System.Collections.Generic; -using System.IO; -using AppLovinMax.ThirdParty.MiniJson; -using UnityEditor; using UnityEditor.Build; using UnityEditor.Build.Reporting; -using UnityEngine; - namespace AppLovinMax.Scripts.IntegrationManager.Editor { @@ -26,19 +18,6 @@ namespace AppLovinMax.Scripts.IntegrationManager.Editor /// public class AppLovinPreProcessAndroid : AppLovinProcessGradleBuildFile, IPreprocessBuildWithReport { - private const string AppLovinSettingsFileName = "applovin_settings.json"; - - private const string KeyTermsFlowSettings = "terms_flow_settings"; - private const string KeyTermsFlowEnabled = "terms_flow_enabled"; - private const string KeyTermsFlowTermsOfService = "terms_flow_terms_of_service"; - private const string KeyTermsFlowPrivacyPolicy = "terms_flow_privacy_policy"; - - private const string KeyConsentFlowSettings = "consent_flow_settings"; - private const string KeyConsentFlowEnabled = "consent_flow_enabled"; - private const string KeyConsentFlowTermsOfService = "consent_flow_terms_of_service"; - private const string KeyConsentFlowPrivacyPolicy = "consent_flow_privacy_policy"; - private const string KeyConsentFlowDebugUserGeography = "consent_flow_debug_user_geography"; - private const string UmpLegacyDependencyLine = ""; private const string UmpDependencyLine = ""; private const string AndroidPackagesContainerElementString = "androidPackages"; @@ -63,126 +42,6 @@ private static void PreprocessAppLovinQualityServicePlugin() #endif } - public static void EnableConsentFlowIfNeeded(string rawResourceDirectory) - { - // Check if consent flow is enabled. No need to create the applovin_consent_flow_settings.json if consent flow is disabled. - var consentFlowEnabled = AppLovinInternalSettings.Instance.ConsentFlowEnabled; - if (!consentFlowEnabled) - { - RemoveAppLovinSettingsRawResourceFileIfNeeded(rawResourceDirectory); - return; - } - - var privacyPolicyUrl = AppLovinInternalSettings.Instance.ConsentFlowPrivacyPolicyUrl; - if (string.IsNullOrEmpty(privacyPolicyUrl)) - { - AppLovinIntegrationManager.ShowBuildFailureDialog("You cannot use the AppLovin SDK's consent flow without defining a Privacy Policy URL in the AppLovin Integration Manager."); - - // No need to update the applovin_consent_flow_settings.json here. Default consent flow state will be determined on the SDK side. - return; - } - - var consentFlowSettings = new Dictionary(); - consentFlowSettings[KeyConsentFlowEnabled] = consentFlowEnabled; - consentFlowSettings[KeyConsentFlowPrivacyPolicy] = privacyPolicyUrl; - - var termsOfServiceUrl = AppLovinInternalSettings.Instance.ConsentFlowTermsOfServiceUrl; - if (MaxSdkUtils.IsValidString(termsOfServiceUrl)) - { - consentFlowSettings[KeyConsentFlowTermsOfService] = termsOfServiceUrl; - } - - var debugUserGeography = AppLovinInternalSettings.Instance.DebugUserGeography; - if (debugUserGeography == MaxSdkBase.ConsentFlowUserGeography.Gdpr) - { - consentFlowSettings[KeyConsentFlowDebugUserGeography] = "gdpr"; - } - - var applovinSdkSettings = new Dictionary(); - applovinSdkSettings[KeyConsentFlowSettings] = consentFlowSettings; - - var applovinSdkSettingsJson = Json.Serialize(applovinSdkSettings); - WriteAppLovinSettingsRawResourceFile(applovinSdkSettingsJson, rawResourceDirectory); - } - - public static void EnableTermsFlowIfNeeded(string rawResourceDirectory) - { - if (AppLovinInternalSettings.Instance.ConsentFlowEnabled) return; - - // Check if terms flow is enabled for this format. No need to create the applovin_consent_flow_settings.json if consent flow is disabled. - var consentFlowEnabled = AppLovinSettings.Instance.ConsentFlowEnabled; - var consentFlowPlatform = AppLovinSettings.Instance.ConsentFlowPlatform; - if (!consentFlowEnabled || (consentFlowPlatform != Platform.All && consentFlowPlatform != Platform.Android)) - { - RemoveAppLovinSettingsRawResourceFileIfNeeded(rawResourceDirectory); - return; - } - - var privacyPolicyUrl = AppLovinSettings.Instance.ConsentFlowPrivacyPolicyUrl; - if (string.IsNullOrEmpty(privacyPolicyUrl)) - { - AppLovinIntegrationManager.ShowBuildFailureDialog("You cannot use the AppLovin SDK's consent flow without defining a Privacy Policy URL in the AppLovin Integration Manager."); - - // No need to update the applovin_consent_flow_settings.json here. Default consent flow state will be determined on the SDK side. - return; - } - - var consentFlowSettings = new Dictionary(); - consentFlowSettings[KeyTermsFlowEnabled] = consentFlowEnabled; - consentFlowSettings[KeyTermsFlowPrivacyPolicy] = privacyPolicyUrl; - - var termsOfServiceUrl = AppLovinSettings.Instance.ConsentFlowTermsOfServiceUrl; - if (MaxSdkUtils.IsValidString(termsOfServiceUrl)) - { - consentFlowSettings[KeyTermsFlowTermsOfService] = termsOfServiceUrl; - } - - var applovinSdkSettings = new Dictionary(); - applovinSdkSettings[KeyTermsFlowSettings] = consentFlowSettings; - - var applovinSdkSettingsJson = Json.Serialize(applovinSdkSettings); - WriteAppLovinSettingsRawResourceFile(applovinSdkSettingsJson, rawResourceDirectory); - } - - private static void WriteAppLovinSettingsRawResourceFile(string applovinSdkSettingsJson, string rawResourceDirectory) - { - if (!Directory.Exists(rawResourceDirectory)) - { - Directory.CreateDirectory(rawResourceDirectory); - } - - var consentFlowSettingsFilePath = Path.Combine(rawResourceDirectory, AppLovinSettingsFileName); - try - { - File.WriteAllText(consentFlowSettingsFilePath, applovinSdkSettingsJson + "\n"); - } - catch (Exception exception) - { - MaxSdkLogger.UserError("applovin_settings.json file write failed due to: " + exception.Message); - Console.WriteLine(exception); - } - } - - /// - /// Removes the applovin_settings json file from the build if it exists. - /// - /// The raw resource directory that holds the json file - private static void RemoveAppLovinSettingsRawResourceFileIfNeeded(string rawResourceDirectory) - { - var consentFlowSettingsFilePath = Path.Combine(rawResourceDirectory, AppLovinSettingsFileName); - if (!File.Exists(consentFlowSettingsFilePath)) return; - - try - { - File.Delete(consentFlowSettingsFilePath); - } - catch (Exception exception) - { - MaxSdkLogger.UserError("Deleting applovin_settings.json failed due to: " + exception.Message); - Console.WriteLine(exception); - } - } - private static void AddGoogleCmpDependencyIfNeeded() { // Remove the legacy fixed UMP version if it exists, we'll add the dependency with a dynamic version below. diff --git a/DemoApp/Assets/MaxSdk/Scripts/MaxSdk.cs b/DemoApp/Assets/MaxSdk/Scripts/MaxSdk.cs index 05e7a99..24ecf39 100644 --- a/DemoApp/Assets/MaxSdk/Scripts/MaxSdk.cs +++ b/DemoApp/Assets/MaxSdk/Scripts/MaxSdk.cs @@ -18,7 +18,7 @@ public class MaxSdk : MaxSdkUnityEditor #endif { - private const string _version = "6.5.2"; + private const string _version = "6.6.0"; /// /// Returns the current plugin version. diff --git a/DemoApp/Assets/MaxSdk/Scripts/MaxSdkAndroid.cs b/DemoApp/Assets/MaxSdk/Scripts/MaxSdkAndroid.cs index fd38238..b2dc98d 100644 --- a/DemoApp/Assets/MaxSdk/Scripts/MaxSdkAndroid.cs +++ b/DemoApp/Assets/MaxSdk/Scripts/MaxSdkAndroid.cs @@ -21,21 +21,12 @@ public static MaxUserServiceAndroid UserService static MaxSdkAndroid() { InitializeEventExecutor(); + + MaxUnityPluginClass.CallStatic("setBackgroundCallback", BackgroundCallback); } #region Initialization - /// - /// Set AppLovin SDK Key. - /// - /// This method must be called before any other SDK operation - /// - /// AppLovin SDK Key. Must not be null. - public static void SetSdkKey(string sdkKey) - { - MaxUnityPluginClass.CallStatic("setSdkKey", sdkKey); - } - /// /// Initialize the default instance of AppLovin SDK. /// @@ -47,7 +38,7 @@ public static void SetSdkKey(string sdkKey) public static void InitializeSdk(string[] adUnitIds = null) { var serializedAdUnitIds = (adUnitIds != null) ? string.Join(",", adUnitIds) : ""; - MaxUnityPluginClass.CallStatic("initializeSdk", serializedAdUnitIds, GenerateMetaData(), BackgroundCallback); + MaxUnityPluginClass.CallStatic("initializeSdk", serializedAdUnitIds, GenerateMetaData()); } /// @@ -77,19 +68,12 @@ public static void SetUserId(string userId) } /// - /// User segments allow us to serve ads using custom-defined rules based on which segment the user is in. For now, we only support a custom string 32 alphanumeric characters or less as the user segment. - /// - public static MaxUserSegment UserSegment - { - get { return SharedUserSegment; } - } - - /// - /// This class allows you to provide user or app data that will improve how we target ads. + /// Set the . /// - public static MaxTargetingData TargetingData + /// The segment collection to be set. Must not be {@code null} + public static void SetSegmentCollection(MaxSegmentCollection segmentCollection) { - get { return SharedTargetingData; } + MaxUnityPluginClass.CallStatic("setSegmentCollection", JsonUtility.ToJson(segmentCollection)); } #endregion @@ -1035,15 +1019,6 @@ public static void SetExceptionHandlerEnabled(bool enabled) MaxUnityPluginClass.CallStatic("setExceptionHandlerEnabled", enabled); } - /// - /// Whether or not AppLovin SDK will collect the device location if available. Defaults to true. - /// - /// true if AppLovin SDK should collect the device location if available. - public static void SetLocationCollectionEnabled(bool enabled) - { - MaxUnityPluginClass.CallStatic("setLocationCollectionEnabled", enabled); - } - /// /// Set an extra parameter to pass to the AppLovin server. /// @@ -1075,61 +1050,15 @@ public static SafeAreaInsets GetSafeAreaInsets() #endregion - #region Private - - internal static void SetUserSegmentField(string name, string value) - { - MaxUnityPluginClass.CallStatic("setUserSegmentField", name, value); - } - - internal static void SetTargetingDataYearOfBirth(int yearOfBirth) - { - MaxUnityPluginClass.CallStatic("setTargetingDataYearOfBirth", yearOfBirth); - } - - internal static void SetTargetingDataGender(String gender) - { - MaxUnityPluginClass.CallStatic("setTargetingDataGender", gender); - } - - internal static void SetTargetingDataMaximumAdContentRating(int maximumAdContentRating) - { - MaxUnityPluginClass.CallStatic("setTargetingDataMaximumAdContentRating", maximumAdContentRating); - } - - internal static void SetTargetingDataEmail(string email) - { - MaxUnityPluginClass.CallStatic("setTargetingDataEmail", email); - } - - internal static void SetTargetingDataPhoneNumber(string phoneNumber) - { - MaxUnityPluginClass.CallStatic("setTargetingDataPhoneNumber", phoneNumber); - } - - internal static void SetTargetingDataKeywords(string[] keywords) - { - // Wrap the string array in an object array, so the compiler does not split into multiple strings. - object[] arguments = {keywords}; - MaxUnityPluginClass.CallStatic("setTargetingDataKeywords", arguments); - } - - internal static void SetTargetingDataInterests(string[] interests) - { - // Wrap the string array in an object array, so the compiler does not split into multiple strings. - object[] arguments = {interests}; - MaxUnityPluginClass.CallStatic("setTargetingDataInterests", arguments); - } + #region Obsolete - internal static void ClearAllTargetingData() + [Obsolete("This API has been deprecated and will be removed in a future release. Please set your SDK key in the AppLovin Integration Manager.")] + public static void SetSdkKey(string sdkKey) { - MaxUnityPluginClass.CallStatic("clearAllTargetingData"); + MaxUnityPluginClass.CallStatic("setSdkKey", sdkKey); + Debug.LogWarning("MaxSdk.SetSdkKey() has been deprecated and will be removed in a future release. Please set your SDK key in the AppLovin Integration Manager."); } - #endregion - - #region Obsolete - [Obsolete("This method has been deprecated. Please use `GetSdkConfiguration().ConsentDialogState`")] public static ConsentDialogState GetConsentDialogState() { diff --git a/DemoApp/Assets/MaxSdk/Scripts/MaxSdkBase.cs b/DemoApp/Assets/MaxSdk/Scripts/MaxSdkBase.cs index dacb7af..8d6c62d 100644 --- a/DemoApp/Assets/MaxSdk/Scripts/MaxSdkBase.cs +++ b/DemoApp/Assets/MaxSdk/Scripts/MaxSdkBase.cs @@ -14,10 +14,6 @@ public abstract class MaxSdkBase { - // Shared Properties - protected static readonly MaxUserSegment SharedUserSegment = new MaxUserSegment(); - protected static readonly MaxTargetingData SharedTargetingData = new MaxTargetingData(); - /// /// This enum represents the user's geography used to determine the type of consent flow shown to the user. /// @@ -568,9 +564,6 @@ protected static string GenerateMetaData() var metaData = new Dictionary(2); metaData.Add("UnityVersion", Application.unityVersion); - var graphicsMemorySize = SystemInfo.graphicsMemorySize; - metaData.Add("GraphicsMemorySizeMegabytes", graphicsMemorySize.ToString()); - return Json.Serialize(metaData); } diff --git a/DemoApp/Assets/MaxSdk/Scripts/MaxSdkUnityEditor.cs b/DemoApp/Assets/MaxSdk/Scripts/MaxSdkUnityEditor.cs index 11ff89b..6c98edd 100644 --- a/DemoApp/Assets/MaxSdk/Scripts/MaxSdkUnityEditor.cs +++ b/DemoApp/Assets/MaxSdk/Scripts/MaxSdkUnityEditor.cs @@ -21,7 +21,6 @@ public class MaxSdkUnityEditor : MaxSdkBase { private static bool _isInitialized; - private static bool _hasSdkKey; private static bool _hasUserConsent = false; private static bool _isUserConsentSet = false; private static bool _isAgeRestrictedUser = false; @@ -34,6 +33,10 @@ public class MaxSdkUnityEditor : MaxSdkBase private static readonly HashSet ReadyAdUnits = new HashSet(); private static readonly Dictionary StubBanners = new Dictionary(); + // Ad Placement + private static readonly Dictionary BannerPlacements = new Dictionary(); + private static readonly Dictionary MRecPlacements = new Dictionary(); + public static MaxUserServiceUnityEditor UserService { get { return MaxUserServiceUnityEditor.Instance; } @@ -46,17 +49,6 @@ public static void InitializeMaxSdkUnityEditorOnLoad() StubBanners.Clear(); } - /// - /// Set AppLovin SDK Key. - /// - /// This method must be called before any other SDK operation - /// - /// AppLovin SDK key. Must not be null. - public static void SetSdkKey(string sdkKey) - { - _hasSdkKey = true; - } - #region Initialization /// @@ -70,10 +62,7 @@ public static void SetSdkKey(string sdkKey) /// public static void InitializeSdk(string[] adUnitIds = null) { - _ensureHaveSdkKey(); - _isInitialized = true; - _hasSdkKey = true; // Slight delay to emulate the SDK initializing ExecuteWithDelay(0.1f, () => @@ -118,19 +107,15 @@ public static void DisableStubAds() public static void SetUserId(string userId) { } /// - /// User segments allow us to serve ads using custom-defined rules based on which segment the user is in. For now, we only support a custom string 32 alphanumeric characters or less as the user segment. + /// Set the . /// - public static MaxUserSegment UserSegment + /// The segment collection to be set. Must not be {@code null} + public static void SetSegmentCollection(MaxSegmentCollection segmentCollection) { - get { return SharedUserSegment; } - } - - /// - /// This class allows you to provide user or app data that will improve how we target ads. - /// - public static MaxTargetingData TargetingData - { - get { return SharedTargetingData; } + if (_isInitialized) + { + Debug.LogError("Segment collection must be set before MAX SDK is initialized "); + } } #endregion @@ -314,7 +299,8 @@ public static void CreateBanner(string adUnitIdentifier, BannerPosition bannerPo ExecuteWithDelay(1f, () => { - var eventProps = Json.Serialize(CreateBaseEventPropsDictionary("OnBannerAdLoadedEvent", adUnitIdentifier)); + var placement = MaxSdkUtils.GetStringFromDictionary(BannerPlacements, adUnitIdentifier); + var eventProps = Json.Serialize(CreateBaseEventPropsDictionary("OnBannerAdLoadedEvent", adUnitIdentifier, placement)); MaxSdkCallbacks.ForwardEvent(eventProps); }); } @@ -366,7 +352,8 @@ public static void LoadBanner(string adUnitIdentifier) ExecuteWithDelay(1f, () => { - var eventProps = Json.Serialize(CreateBaseEventPropsDictionary("OnBannerAdLoadedEvent", adUnitIdentifier)); + var placement = MaxSdkUtils.GetStringFromDictionary(BannerPlacements, adUnitIdentifier); + var eventProps = Json.Serialize(CreateBaseEventPropsDictionary("OnBannerAdLoadedEvent", adUnitIdentifier, placement)); MaxSdkCallbacks.ForwardEvent(eventProps); }); } @@ -378,6 +365,7 @@ public static void LoadBanner(string adUnitIdentifier) /// Placement to set public static void SetBannerPlacement(string adUnitIdentifier, string placement) { + BannerPlacements[adUnitIdentifier] = placement; MaxSdkLogger.UserDebug("Setting banner placement to '" + placement + "' for ad unit id '" + adUnitIdentifier + "'"); } @@ -406,7 +394,7 @@ public static void StopBannerAutoRefresh(string adUnitIdentifier) /// A new position for the banner. Must not be null. public static void UpdateBannerPosition(string adUnitIdentifier, BannerPosition bannerPosition) { - Debug.Log("[AppLovin MAX] Updating banner position to '" + bannerPosition + "' for ad unit id '" + adUnitIdentifier + "'"); + MaxSdkLogger.D("[AppLovin MAX] Updating banner position to '" + bannerPosition + "' for ad unit id '" + adUnitIdentifier + "'"); } /// @@ -431,7 +419,7 @@ public static void UpdateBannerPosition(string adUnitIdentifier, float x, float public static void SetBannerWidth(string adUnitIdentifier, float width) { // NOTE: Will implement in a future release - Debug.Log("[AppLovin MAX] Set banner width to '" + width + "' for ad unit id '" + adUnitIdentifier + "'"); + MaxSdkLogger.D("[AppLovin MAX] Set banner width to '" + width + "' for ad unit id '" + adUnitIdentifier + "'"); } /// @@ -563,7 +551,8 @@ public static void CreateMRec(string adUnitIdentifier, AdViewPosition mrecPositi ExecuteWithDelay(1f, () => { - var eventProps = Json.Serialize(CreateBaseEventPropsDictionary("OnMRecAdLoadedEvent", adUnitIdentifier)); + var placement = MaxSdkUtils.GetStringFromDictionary(MRecPlacements, adUnitIdentifier); + var eventProps = Json.Serialize(CreateBaseEventPropsDictionary("OnMRecAdLoadedEvent", adUnitIdentifier, placement)); MaxSdkCallbacks.ForwardEvent(eventProps); }); } @@ -595,7 +584,8 @@ public static void LoadMRec(string adUnitIdentifier) ExecuteWithDelay(1f, () => { - var eventProps = Json.Serialize(CreateBaseEventPropsDictionary("OnMRecAdLoadedEvent", adUnitIdentifier)); + var placement = MaxSdkUtils.GetStringFromDictionary(MRecPlacements, adUnitIdentifier); + var eventProps = Json.Serialize(CreateBaseEventPropsDictionary("OnMRecAdLoadedEvent", adUnitIdentifier, placement)); MaxSdkCallbacks.ForwardEvent(eventProps); }); } @@ -607,6 +597,7 @@ public static void LoadMRec(string adUnitIdentifier) /// Placement to set public static void SetMRecPlacement(string adUnitIdentifier, string placement) { + MRecPlacements[adUnitIdentifier] = placement; MaxSdkLogger.UserDebug("Setting MREC placement to '" + placement + "' for ad unit id '" + adUnitIdentifier + "'"); } @@ -796,11 +787,11 @@ public static void ShowInterstitial(string adUnitIdentifier, string placement = if (_showStubAds) { - ShowStubInterstitial(adUnitIdentifier); + ShowStubInterstitial(adUnitIdentifier, placement); } } - private static void ShowStubInterstitial(string adUnitIdentifier) + private static void ShowStubInterstitial(string adUnitIdentifier, string placement) { #if UNITY_EDITOR var prefabPath = MaxSdkUtils.GetAssetPathForExportPath("MaxSdk/Prefabs/Interstitial.prefab"); @@ -813,12 +804,12 @@ private static void ShowStubInterstitial(string adUnitIdentifier) interstitialText.text += ":\n" + adUnitIdentifier; closeButton.onClick.AddListener(() => { - var adHiddenEventProps = Json.Serialize(CreateBaseEventPropsDictionary("OnInterstitialHiddenEvent", adUnitIdentifier)); + var adHiddenEventProps = Json.Serialize(CreateBaseEventPropsDictionary("OnInterstitialHiddenEvent", adUnitIdentifier, placement)); MaxSdkCallbacks.ForwardEvent(adHiddenEventProps); Object.Destroy(stubInterstitial); }); - var adDisplayedEventProps = Json.Serialize(CreateBaseEventPropsDictionary("OnInterstitialDisplayedEvent", adUnitIdentifier)); + var adDisplayedEventProps = Json.Serialize(CreateBaseEventPropsDictionary("OnInterstitialDisplayedEvent", adUnitIdentifier, placement)); MaxSdkCallbacks.ForwardEvent(adDisplayedEventProps); #endif } @@ -913,11 +904,11 @@ public static void ShowAppOpenAd(string adUnitIdentifier, string placement = nul if (_showStubAds) { - ShowStubAppOpenAd(adUnitIdentifier); + ShowStubAppOpenAd(adUnitIdentifier, placement); } } - private static void ShowStubAppOpenAd(string adUnitIdentifier) + private static void ShowStubAppOpenAd(string adUnitIdentifier, string placement) { #if UNITY_EDITOR var prefabPath = MaxSdkUtils.GetAssetPathForExportPath("MaxSdk/Prefabs/Interstitial.prefab"); @@ -930,12 +921,12 @@ private static void ShowStubAppOpenAd(string adUnitIdentifier) appOpenAdText.text = "MAX App Open Ad:\n" + adUnitIdentifier; closeButton.onClick.AddListener(() => { - var adHiddenEventProps = Json.Serialize(CreateBaseEventPropsDictionary("OnAppOpenAdHiddenEvent", adUnitIdentifier)); + var adHiddenEventProps = Json.Serialize(CreateBaseEventPropsDictionary("OnAppOpenAdHiddenEvent", adUnitIdentifier, placement)); MaxSdkCallbacks.ForwardEvent(adHiddenEventProps); Object.Destroy(stubAppOpenAd); }); - var adDisplayedEventProps = Json.Serialize(CreateBaseEventPropsDictionary("OnAppOpenAdDisplayedEvent", adUnitIdentifier)); + var adDisplayedEventProps = Json.Serialize(CreateBaseEventPropsDictionary("OnAppOpenAdDisplayedEvent", adUnitIdentifier, placement)); MaxSdkCallbacks.ForwardEvent(adDisplayedEventProps); #endif } @@ -1029,11 +1020,11 @@ public static void ShowRewardedAd(string adUnitIdentifier, string placement = nu if (_showStubAds) { - ShowStubRewardedAd(adUnitIdentifier); + ShowStubRewardedAd(adUnitIdentifier, placement); } } - private static void ShowStubRewardedAd(string adUnitIdentifier) + private static void ShowStubRewardedAd(string adUnitIdentifier, string placement) { #if UNITY_EDITOR var prefabPath = MaxSdkUtils.GetAssetPathForExportPath("MaxSdk/Prefabs/Rewarded.prefab"); @@ -1051,14 +1042,14 @@ private static void ShowStubRewardedAd(string adUnitIdentifier) { if (grantedReward) { - var rewardEventPropsDict = CreateBaseEventPropsDictionary("OnRewardedAdReceivedRewardEvent", adUnitIdentifier); + var rewardEventPropsDict = CreateBaseEventPropsDictionary("OnRewardedAdReceivedRewardEvent", adUnitIdentifier, placement); rewardEventPropsDict["rewardLabel"] = "coins"; rewardEventPropsDict["rewardAmount"] = "5"; var rewardEventProps = Json.Serialize(rewardEventPropsDict); MaxSdkCallbacks.ForwardEvent(rewardEventProps); } - var adHiddenEventProps = Json.Serialize(CreateBaseEventPropsDictionary("OnRewardedAdHiddenEvent", adUnitIdentifier)); + var adHiddenEventProps = Json.Serialize(CreateBaseEventPropsDictionary("OnRewardedAdHiddenEvent", adUnitIdentifier, placement)); MaxSdkCallbacks.ForwardEvent(adHiddenEventProps); Object.Destroy(stubRewardedAd); }); @@ -1068,7 +1059,7 @@ private static void ShowStubRewardedAd(string adUnitIdentifier) rewardStatus.text = "Reward granted. Will send reward callback on ad close."; }); - var adDisplayedEventProps = Json.Serialize(CreateBaseEventPropsDictionary("OnRewardedAdDisplayedEvent", adUnitIdentifier)); + var adDisplayedEventProps = Json.Serialize(CreateBaseEventPropsDictionary("OnRewardedAdDisplayedEvent", adUnitIdentifier, placement)); MaxSdkCallbacks.ForwardEvent(adDisplayedEventProps); #endif } @@ -1162,11 +1153,11 @@ public static void ShowRewardedInterstitialAd(string adUnitIdentifier, string pl if (_showStubAds) { - ShowStubRewardedInterstitialAd(adUnitIdentifier); + ShowStubRewardedInterstitialAd(adUnitIdentifier, placement); } } - private static void ShowStubRewardedInterstitialAd(string adUnitIdentifier) + private static void ShowStubRewardedInterstitialAd(string adUnitIdentifier, string placement) { #if UNITY_EDITOR var prefabPath = MaxSdkUtils.GetAssetPathForExportPath("MaxSdk/Prefabs/Rewarded.prefab"); @@ -1184,14 +1175,14 @@ private static void ShowStubRewardedInterstitialAd(string adUnitIdentifier) { if (grantedReward) { - var rewardEventPropsDict = CreateBaseEventPropsDictionary("OnRewardedInterstitialAdReceivedRewardEvent", adUnitIdentifier); + var rewardEventPropsDict = CreateBaseEventPropsDictionary("OnRewardedInterstitialAdReceivedRewardEvent", adUnitIdentifier, placement); rewardEventPropsDict["rewardLabel"] = "coins"; rewardEventPropsDict["rewardAmount"] = "5"; var rewardEventProps = Json.Serialize(rewardEventPropsDict); MaxSdkCallbacks.ForwardEvent(rewardEventProps); } - var adHiddenEventProps = Json.Serialize(CreateBaseEventPropsDictionary("OnRewardedInterstitialAdHiddenEvent", adUnitIdentifier)); + var adHiddenEventProps = Json.Serialize(CreateBaseEventPropsDictionary("OnRewardedInterstitialAdHiddenEvent", adUnitIdentifier, placement)); MaxSdkCallbacks.ForwardEvent(adHiddenEventProps); Object.Destroy(stubRewardedAd); }); @@ -1201,7 +1192,7 @@ private static void ShowStubRewardedInterstitialAd(string adUnitIdentifier) rewardStatus.text = "Reward granted. Will send reward callback on ad close."; }); - var adDisplayedEventProps = Json.Serialize(CreateBaseEventPropsDictionary("OnRewardedAdDisplayedEvent", adUnitIdentifier)); + var adDisplayedEventProps = Json.Serialize(CreateBaseEventPropsDictionary("OnRewardedAdDisplayedEvent", adUnitIdentifier, placement)); MaxSdkCallbacks.ForwardEvent(adDisplayedEventProps); #endif } @@ -1316,12 +1307,6 @@ public static void SetTestDeviceAdvertisingIdentifiers(string[] advertisingIdent /// true if the native AppLovin SDKs should not listen to exceptions. public static void SetExceptionHandlerEnabled(bool enabled) { } - /// - /// Whether or not AppLovin SDK will collect the device location if available. Defaults to true. - /// - /// true if AppLovin SDK should collect the device location if available. - public static void SetLocationCollectionEnabled(bool enabled) { } - /// /// Set an extra parameter to pass to the AppLovin server. /// @@ -1344,25 +1329,25 @@ public static SafeAreaInsets GetSafeAreaInsets() private static void RequestAdUnit(string adUnitId) { - _ensureInitialized(); + EnsureInitialized(); RequestedAdUnits.Add(adUnitId); } private static bool IsAdUnitRequested(string adUnitId) { - _ensureInitialized(); + EnsureInitialized(); return RequestedAdUnits.Contains(adUnitId); } private static void AddReadyAdUnit(string adUnitId) { - _ensureInitialized(); + EnsureInitialized(); ReadyAdUnits.Add(adUnitId); } private static bool IsAdUnitReady(string adUnitId) { - _ensureInitialized(); + EnsureInitialized(); return ReadyAdUnits.Contains(adUnitId); } @@ -1371,28 +1356,20 @@ private static void RemoveReadyAdUnit(string adUnitId) ReadyAdUnits.Remove(adUnitId); } - private static void _ensureHaveSdkKey() + private static void EnsureInitialized() { - if (_hasSdkKey) return; - MaxSdkLogger.UserWarning( - "MAX Ads SDK did not receive SDK key. Please call Max.SetSdkKey() to assign it"); - } - - private static void _ensureInitialized() - { - _ensureHaveSdkKey(); - if (_isInitialized) return; - MaxSdkLogger.UserWarning( - "MAX Ads SDK is not initialized by the time ad is requested. Please call Max.InitializeSdk() in your first scene"); + + MaxSdkLogger.UserWarning("MAX Ads SDK is not initialized by the time ad is requested. Please call Max.InitializeSdk() in your first scene"); } - private static Dictionary CreateBaseEventPropsDictionary(string eventName, string adUnitId) + private static Dictionary CreateBaseEventPropsDictionary(string eventName, string adUnitId, string placement = null) { return new Dictionary() { {"name", eventName}, - {"adUnitId", adUnitId} + {"adUnitId", adUnitId}, + {"placement", placement ?? ""} }; } @@ -1408,28 +1385,16 @@ private static IEnumerator ExecuteAction(float seconds, Action action) action(); } - internal static void SetUserSegmentField(string key, string value) { } - - internal static void SetTargetingDataYearOfBirth(int yearOfBirth) { } - - internal static void SetTargetingDataGender(string gender) { } - - internal static void SetTargetingDataMaximumAdContentRating(int maximumAdContentRating) { } - - internal static void SetTargetingDataEmail(string email) { } - - internal static void SetTargetingDataPhoneNumber(string phoneNumber) { } - - internal static void SetTargetingDataKeywords(string[] keywords) { } - - internal static void SetTargetingDataInterests(string[] interests) { } - - internal static void ClearAllTargetingData() { } - #endregion #region Obsolete + [Obsolete("This API has been deprecated and will be removed in a future release. Please set your SDK key in the AppLovin Integration Manager.")] + public static void SetSdkKey(string sdkKey) + { + Debug.LogWarning("MaxSdk.SetSdkKey() has been deprecated and will be removed in a future release. Please set your SDK key in the AppLovin Integration Manager."); + } + [Obsolete("This method has been deprecated. Please use `GetSdkConfiguration().ConsentDialogState`")] public static ConsentDialogState GetConsentDialogState() { diff --git a/DemoApp/Assets/MaxSdk/Scripts/MaxSdkiOS.cs b/DemoApp/Assets/MaxSdk/Scripts/MaxSdkiOS.cs index d128f1a..467793d 100644 --- a/DemoApp/Assets/MaxSdk/Scripts/MaxSdkiOS.cs +++ b/DemoApp/Assets/MaxSdk/Scripts/MaxSdkiOS.cs @@ -16,6 +16,10 @@ public class MaxSdkiOS : MaxSdkBase static MaxSdkiOS() { InitializeEventExecutor(); + +#if UNITY_IOS + _MaxSetBackgroundCallback(BackgroundCallback); +#endif } #if UNITY_IOS @@ -27,21 +31,10 @@ public static MaxUserServiceiOS UserService #region Initialization [DllImport("__Internal")] - private static extern void _MaxSetSdkKey(string sdkKey); - - /// - /// Set AppLovin SDK Key. - /// - /// This method must be called before any other SDK operation - /// - /// AppLovin SDK key. Must not be null. - public static void SetSdkKey(string sdkKey) - { - _MaxSetSdkKey(sdkKey); - } + private static extern void _MaxSetBackgroundCallback(ALUnityBackgroundCallback backgroundCallback); [DllImport("__Internal")] - private static extern void _MaxInitializeSdk(string serializedAdUnitIds, string serializedMetaData, ALUnityBackgroundCallback backgroundCallback); + private static extern void _MaxInitializeSdk(string serializedAdUnitIds, string serializedMetaData); /// /// Initialize the default instance of AppLovin SDK. @@ -54,7 +47,7 @@ public static void SetSdkKey(string sdkKey) public static void InitializeSdk(string[] adUnitIds = null) { var serializedAdUnitIds = (adUnitIds != null) ? string.Join(",", adUnitIds) : ""; - _MaxInitializeSdk(serializedAdUnitIds, GenerateMetaData(), BackgroundCallback); + _MaxInitializeSdk(serializedAdUnitIds, GenerateMetaData()); } [DllImport("__Internal")] @@ -89,22 +82,19 @@ public static void SetUserId(string userId) _MaxSetUserId(userId); } - /// - /// User segments allow us to serve ads using custom-defined rules based on which segment the user is in. For now, we only support a custom string 32 alphanumeric characters or less as the user segment. - /// - public static MaxUserSegment UserSegment - { - get { return SharedUserSegment; } - } + [DllImport("__Internal")] + private static extern bool _MaxSetSegmentCollection(string segmentCollectionsJson); /// - /// This class allows you to provide user or app data that will improve how we target ads. + /// Set the . /// - public static MaxTargetingData TargetingData + /// The segment collection to be set. Must not be {@code null} + public static void SetSegmentCollection(MaxSegmentCollection segmentCollection) { - get { return SharedTargetingData; } + _MaxSetSegmentCollection(JsonUtility.ToJson(segmentCollection)); } + #endregion #region MAX @@ -1292,18 +1282,6 @@ public static void SetExceptionHandlerEnabled(bool enabled) _MaxSetExceptionHandlerEnabled(enabled); } - [DllImport("__Internal")] - private static extern bool _MaxSetLocationCollectionEnabled(bool enabled); - - /// - /// Whether or not AppLovin SDK will collect the device location if available. Defaults to true. - /// - /// true if AppLovin SDK should collect the device location if available. - public static void SetLocationCollectionEnabled(bool enabled) - { - _MaxSetLocationCollectionEnabled(enabled); - } - [DllImport("__Internal")] private static extern void _MaxSetExtraParameter(string key, string value); @@ -1345,78 +1323,6 @@ public static SafeAreaInsets GetSafeAreaInsets() #region Private - [DllImport("__Internal")] - private static extern bool _MaxSetUserSegmentField(string name, string value); - - internal static void SetUserSegmentField(string name, string value) - { - _MaxSetUserSegmentField(name, value); - } - - [DllImport("__Internal")] - private static extern void _MaxSetTargetingDataYearOfBirth(int yearOfBirth); - - internal static void SetTargetingDataYearOfBirth(int yearOfBirth) - { - _MaxSetTargetingDataYearOfBirth(yearOfBirth); - } - - [DllImport("__Internal")] - private static extern void _MaxSetTargetingDataGender(String gender); - - internal static void SetTargetingDataGender(String gender) - { - _MaxSetTargetingDataGender(gender); - } - - [DllImport("__Internal")] - private static extern void _MaxSetTargetingDataMaximumAdContentRating(int maximumAdContentRating); - - internal static void SetTargetingDataMaximumAdContentRating(int maximumAdContentRating) - { - _MaxSetTargetingDataMaximumAdContentRating(maximumAdContentRating); - } - - [DllImport("__Internal")] - private static extern void _MaxSetTargetingDataEmail(string email); - - internal static void SetTargetingDataEmail(string email) - { - _MaxSetTargetingDataEmail(email); - } - - [DllImport("__Internal")] - private static extern void _MaxSetTargetingDataPhoneNumber(string phoneNumber); - - internal static void SetTargetingDataPhoneNumber(string phoneNumber) - { - _MaxSetTargetingDataPhoneNumber(phoneNumber); - } - - [DllImport("__Internal")] - private static extern void _MaxSetTargetingDataKeywords(string[] keywords, int size); - - internal static void SetTargetingDataKeywords(string[] keywords) - { - _MaxSetTargetingDataKeywords(keywords, keywords == null ? 0 : keywords.Length); - } - - [DllImport("__Internal")] - private static extern void _MaxSetTargetingDataInterests(string[] interests, int size); - - internal static void SetTargetingDataInterests(string[] interests) - { - _MaxSetTargetingDataInterests(interests, interests == null ? 0 : interests.Length); - } - - [DllImport("__Internal")] - private static extern void _MaxClearAllTargetingData(); - - internal static void ClearAllTargetingData() - { - _MaxClearAllTargetingData(); - } - [MonoPInvokeCallback(typeof(ALUnityBackgroundCallback))] internal static void BackgroundCallback(string propsStr) { @@ -1427,6 +1333,16 @@ internal static void BackgroundCallback(string propsStr) #region Obsolete + [DllImport("__Internal")] + private static extern void _MaxSetSdkKey(string sdkKey); + + [Obsolete("This API has been deprecated and will be removed in a future release. Please set your SDK key in the AppLovin Integration Manager.")] + public static void SetSdkKey(string sdkKey) + { + _MaxSetSdkKey(sdkKey); + Debug.LogWarning("MaxSdk.SetSdkKey() has been deprecated and will be removed in a future release. Please set your SDK key in the AppLovin Integration Manager."); + } + [DllImport("__Internal")] private static extern int _MaxConsentDialogState(); diff --git a/DemoApp/Assets/MaxSdk/Scripts/MaxSegmentCollection.cs b/DemoApp/Assets/MaxSdk/Scripts/MaxSegmentCollection.cs new file mode 100644 index 0000000..43e6ea1 --- /dev/null +++ b/DemoApp/Assets/MaxSdk/Scripts/MaxSegmentCollection.cs @@ -0,0 +1,91 @@ +using System; +using System.Collections.Generic; +using UnityEngine; + +/// +/// This class contains a collection of objects. +/// +[Serializable] +public class MaxSegmentCollection +{ + [SerializeField] private List segments; + + private MaxSegmentCollection(MaxSegmentCollectionBuilder maxSegmentCollectionBuilder) + { + segments = maxSegmentCollectionBuilder.segments; + } + + /// The list of in the + public List GetSegments() + { + return segments; + } + + public static MaxSegmentCollectionBuilder Builder() + { + return new MaxSegmentCollectionBuilder(); + } + + /// + /// Builder class for MaxSegmentCollection. + /// + public class MaxSegmentCollectionBuilder + { + internal readonly List segments = new List(); + + internal MaxSegmentCollectionBuilder() { } + + /// + /// Adds a MaxSegment to the collection. + /// + /// The MaxSegment to add. + /// The MaxSegmentCollectionBuilder instance for chaining. + public MaxSegmentCollectionBuilder AddSegment(MaxSegment segment) + { + segments.Add(segment); + return this; + } + + /// + /// Builds and returns the MaxSegmentCollection. + /// + /// The constructed MaxSegmentCollection. + public MaxSegmentCollection Build() + { + return new MaxSegmentCollection(this); + } + } +} + +/// +/// This class encapsulates a key-value pair, where the key is an int and the value is a List<int>. +/// +[Serializable] +public class MaxSegment +{ + [SerializeField] private int key; + [SerializeField] private List values; + + /// + /// Initializes a new with the specified key and value(s). + /// + /// The key of the segment. Must be a non-negative number in the range of [0, 32000]. + /// The values(s) associated with the key. Each value must be a non-negative number in the range of [0, 32000]. + public MaxSegment(int key, List values) + { + this.key = key; + this.values = values; + } + + /// The key of the segment. Must be a non-negative number in the range of [0, 32000]. + public int GetKey() + { + return key; + } + + /// The value(s) associated with the key. Each value must be a non-negative number in the range of [0, 32000]. + public List GetValues() + { + return values; + } +} diff --git a/DemoApp/Assets/MaxSdk/Scripts/MaxTargetingData.cs.meta b/DemoApp/Assets/MaxSdk/Scripts/MaxSegmentCollection.cs.meta similarity index 69% rename from DemoApp/Assets/MaxSdk/Scripts/MaxTargetingData.cs.meta rename to DemoApp/Assets/MaxSdk/Scripts/MaxSegmentCollection.cs.meta index 35e7771..f37749e 100644 --- a/DemoApp/Assets/MaxSdk/Scripts/MaxTargetingData.cs.meta +++ b/DemoApp/Assets/MaxSdk/Scripts/MaxSegmentCollection.cs.meta @@ -1,8 +1,8 @@ fileFormatVersion: 2 -guid: 409fe14211f31433da09f5b4bd5467b9 +guid: c1a4950b4ed22489684fa40311f9d5b8 labels: - al_max -- al_max_export_path-MaxSdk/Scripts/MaxTargetingData.cs +- al_max_export_path-MaxSdk/Scripts/MaxSegmentCollection.cs MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/DemoApp/Assets/MaxSdk/Scripts/MaxTargetingData.cs b/DemoApp/Assets/MaxSdk/Scripts/MaxTargetingData.cs deleted file mode 100644 index d41990c..0000000 --- a/DemoApp/Assets/MaxSdk/Scripts/MaxTargetingData.cs +++ /dev/null @@ -1,142 +0,0 @@ -// -// MaxTargetingData.cs -// AppLovin MAX Unity Plugin -// -// Created by Harry Arakkal on 11/19/21. -// Copyright © 2020 AppLovin. All rights reserved. -// - -/// -/// This class allows you to provide user or app data that will improve how we target ads. -/// -public class MaxTargetingData -{ - /// - /// This enumeration represents content ratings for the ads shown to users. - /// They correspond to IQG Media Ratings. - /// - public enum AdContentRating - { - None, - AllAudiences, - EveryoneOverTwelve, - MatureAudiences - } - - /// - /// This enumeration represents gender. - /// - public enum UserGender - { - Unknown, - Female, - Male, - Other - } - - /// - /// The year of birth of the user. - /// Set this property to 0 to clear this value. - /// - public int YearOfBirth - { - set - { - MaxSdk.SetTargetingDataYearOfBirth(value); - } - } - - /// - /// The gender of the user. - /// Set this property to UserGender.Unknown to clear this value. - /// - public UserGender Gender - { - set - { - string genderString = ""; - if ( value == UserGender.Female ) - { - genderString = "F"; - } - else if ( value == UserGender.Male ) - { - genderString = "M"; - } - else if ( value == UserGender.Other ) - { - genderString = "O"; - } - - MaxSdk.SetTargetingDataGender(genderString); - } - } - - /// - /// The maximum ad content rating to show the user. - /// Set this property to AdContentRating.None to clear this value. - /// - public AdContentRating MaximumAdContentRating - { - set - { - MaxSdk.SetTargetingDataMaximumAdContentRating((int) value); - } - } - - /// - /// The email of the user. - /// Set this property to null to clear this value. - /// - public string Email - { - set - { - MaxSdk.SetTargetingDataEmail(value); - } - } - - /// - /// The phone number of the user. Do not include the country calling code. - /// Set this property to null to clear this value. - /// - public string PhoneNumber - { - set - { - MaxSdk.SetTargetingDataPhoneNumber(value); - } - } - - /// - /// The keywords describing the application. - /// Set this property to null to clear this value. - /// - public string[] Keywords - { - set - { - MaxSdk.SetTargetingDataKeywords(value); - } - } - - /// - /// The interests of the user. - /// Set this property to null to clear this value. - /// - public string[] Interests - { - set - { - MaxSdk.SetTargetingDataInterests(value); - } - } - - /// - /// Clear all saved data from this class. - /// - public void ClearAll() - { - MaxSdk.ClearAllTargetingData(); - } -} diff --git a/DemoApp/Assets/MaxSdk/Scripts/MaxUserSegment.cs b/DemoApp/Assets/MaxSdk/Scripts/MaxUserSegment.cs deleted file mode 100644 index 5f954a2..0000000 --- a/DemoApp/Assets/MaxSdk/Scripts/MaxUserSegment.cs +++ /dev/null @@ -1,31 +0,0 @@ -// -// MaxUserSegment.cs -// AppLovin MAX Unity Plugin -// -// Created by Thomas So on 10/31/20. -// Copyright © 2020 AppLovin. All rights reserved. -// - -/// -/// User segments allow us to serve ads using custom-defined rules based on which segment the user is in. For now, we only support a custom string 32 alphanumeric characters or less as the user segment. -/// -public class MaxUserSegment -{ - private string _name; - - public string Name - { - set - { - _name = value; - - MaxSdk.SetUserSegmentField("name", _name); - } - get { return _name; } - } - - public override string ToString() - { - return "[MaxUserSegment Name: " + Name + "]"; - } -} diff --git a/DemoApp/Assets/MaxSdk/Scripts/MaxUserSegment.cs.meta b/DemoApp/Assets/MaxSdk/Scripts/MaxUserSegment.cs.meta deleted file mode 100644 index 9c1916a..0000000 --- a/DemoApp/Assets/MaxSdk/Scripts/MaxUserSegment.cs.meta +++ /dev/null @@ -1,14 +0,0 @@ -fileFormatVersion: 2 -guid: 8fb1f6f31b19c407b9d3fa62557d373a -labels: -- al_max -- al_max_export_path-MaxSdk/Scripts/MaxUserSegment.cs -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: