From 9d7ccbc81a181936a50721d12c235ace0303f9d5 Mon Sep 17 00:00:00 2001 From: runner Date: Tue, 2 May 2023 17:01:58 +0000 Subject: [PATCH] Release 4.7.0 --- LICENSE | 2 +- SourceCode/Private/Core/Api/USRVApiSdk.h | 3 +- SourceCode/Private/Core/Api/USRVApiSdk.m | 13 +- .../UADSConfigurationLoaderWithPrivacy.m | 5 +- .../UADSInitializationResponse.h | 1 + .../UADSInitializationResponse.m | 1 + .../PrivacyLoader/UADSPrivacyLoader.h | 7 + .../PrivacyLoader/UADSPrivacyLoader.m | 4 + .../PrivacyLoader/UADSPrivacyStorage.h | 1 + .../PrivacyLoader/UADSPrivacyStorage.m | 4 + .../UADSConfigurationLoaderBuilder.h | 1 + .../UADSConfigurationLoaderBuilder.m | 1 + .../UADSConfigurationExperiments.h | 1 + .../UADSConfigurationExperiments.m | 4 + .../Core/Configuration/UADSErrorState.h | 2 + .../Core/Configuration/UADSErrorState.m | 2 + .../USRVCoreModuleConfiguration.m | 3 +- .../Decorators/UADSDeviceInfoReaderGate.h | 13 ++ .../Decorators/UADSDeviceInfoReaderGate.m | 32 +++ .../Decorators/UADSDeviceInfoReaderKeys.h | 4 + .../Decorators/UADSDeviceInfoReaderKeys.m | 2 + .../UADSDeviceInfoReaderWithPrivacy.m | 3 - .../UADSPIITrackingStatusReader.h | 2 +- .../UADSPIITrackingStatusReader.m | 4 +- .../UADSDeviceInfoReaderWithSessionId.h | 12 ++ .../UADSDeviceInfoReaderWithSessionId.m | 28 +++ .../DeviceInfoReader/UADSDeviceIDFIReader.h | 1 + .../DeviceInfoReader/UADSDeviceIDFIReader.m | 6 +- .../DeviceInfoReader/UADSDeviceInfoReader.m | 6 + .../UADSDeviceInfoReaderBuilder.h | 3 + .../UADSDeviceInfoReaderBuilder.m | 17 ++ .../UADSJsonStorageKeyNames.h | 1 + .../UADSJsonStorageKeyNames.m | 2 +- .../UADSMinDeviceInfoReader.m | 2 +- .../Metric/UADSSCARHeaderBiddingMetric.m | 2 +- .../UADSSCARRawSignalsReader.m | 6 +- .../UADSSCARWebRequestSignalSender.m | 10 +- .../UADSHeaderBiddingToken.h | 1 + .../UADSHeaderBiddingToken.m | 12 ++ .../UADSHeaderBiddingTokenReaderBuilder.h | 2 + .../UADSHeaderBiddingTokenReaderBuilder.m | 8 +- .../UADSHeaderBiddingTokenReaderSwiftBridge.h | 11 + .../UADSHeaderBiddingTokenReaderSwiftBridge.m | 13 ++ .../SessionIdReader/UADSGameSessionIdReader.m | 24 +-- .../UADSSharedSessionIdReader.m | 5 +- .../Private/Core/Device/USRVMuteSwitch.m | 8 +- .../Private/Core/Device/USRVStorageManager.h | 2 +- .../Private/Core/Device/USRVStorageManager.m | 11 - .../USRVInitializeStateConfig.m | 56 +++-- .../Core/Properties/USRVSdkProperties.m | 4 +- .../Core/Request/Metrics/Events/UADSMetric.m | 2 +- .../Core/SKAdNetwork/USRVApiSKAdNetwork.h | 2 - .../Core/SKAdNetwork/USRVApiSKAdNetwork.m | 24 --- .../Core/SKAdNetwork/USRVSKAdNetworkProxy.h | 11 - .../Core/SKAdNetwork/USRVSKAdNetworkProxy.m | 105 ---------- SourceCode/Private/Core/UADSServiceProvider.m | 47 +++-- .../Initialize/UADSSDKInitializerProxy.m | 4 +- .../UADSServiceProviderProxy.h | 4 + .../UADSServiceProviderProxy.m | 17 +- .../UnityServicesIdentifiers/UADSIdStore.h | 13 -- .../UADSInstallationId.m | 93 --------- .../UnityServicesIdentifiers/UADSPlist.h | 22 -- .../UnityServicesIdentifiers/UADSPlist.m | 48 ----- .../UnityServicesIdentifiers/UADSSessionId.m | 36 ---- .../UADSUnityPlayerPrefsStore.h | 12 -- .../UADSUnityPlayerPrefsStore.m | 65 ------ .../UADSUserDefaultsStore.h | 12 -- .../UADSUserDefaultsStore.m | 29 --- SourceCode/Public/UnityAds.h | 2 - SourceCode/Public/UnityServices.m | 31 ++- .../UADSInstallationId.h | 26 --- .../UnityServicesIdentifiers/UADSSessionId.h | 27 --- .../DeviceInfoBodyReaderBuilder.swift | 83 ++++++++ .../SDKStateStorage.swift | 61 +++--- .../InitializationTaskFactoryBase.swift | 30 ++- .../InitializationTaskFactoryStrategy.swift | 14 +- .../Initialization/SDKInitializerBase.swift | 27 ++- .../SharedSessionIdReader.swift | 11 - .../Tasks/InitModulesTask.swift | 25 +++ .../Tasks/PreviousSessionCleanupTask.swift | 9 +- .../Tasks/PrivacyFetchTask.swift | 25 ++- .../Initialization/Tasks/StartInitTask.swift | 44 +++- ...UnityAdsEventsNetworkServicesFactory.swift | 77 +++++++ .../UnityAdsNetworkServicesFactory.swift | 126 ++--------- .../DeviceInfo/DeviceInfoObjBridge.swift | 42 ++++ .../SDKInitializerOBJBridge.swift | 2 +- .../JSONStorage/JSONStorageBridge.swift | 28 +++ .../JSONStorageContentNormalizer.swift | 103 +++++++++ .../ServiceProviderObjCBridge.swift | 48 ++++- .../Swift/Settings/SDKSettingsStorage.swift | 31 +-- .../Swift/Token/HeaderBiddingToken.swift | 32 +++ .../Token/HeaderBiddingTokenReader.swift | 37 ++++ .../Swift/UnityAdsServiceProvider.swift | 117 ++++++++--- Tests/.swiftlint.yml | 6 +- Tests/Categories/UnityAds+Testability.m | 12 +- .../InitializeTests.m | 1 + .../InitializationPerformanceTest.swift | 17 +- Tests/UnityAdsTests-Bridging-Header.h | 8 +- .../Mocks/UADSPIITrackingStatusReaderMock.m | 4 +- ...DSConfigurationLoaderWithPrivacyTestCase.m | 9 + .../Mocks/UADSPrivacyStorageMock.h | 1 + .../Mocks/UADSPrivacyStorageMock.m | 1 + ...rationLoaderIntegrationMetricsBatchTests.m | 14 +- ...tionLoaderIntegrationPrivacyRequestTests.m | 17 +- ...SConfigurationLoaderIntegrationTestsBase.m | 1 + ...VConfigurationRequestFactoryBaseTestCase.m | 1 + .../Core/Data/USRVJsonUtilitiesTests.m | 1 + .../DeviceTestsHelper/UADSDeviceTestsHelper.h | 10 +- .../DeviceTestsHelper/UADSDeviceTestsHelper.m | 134 ++++++------ ...ADSAsyncTokenWithPrivacyIntegrationTests.m | 8 +- ...derBiddingTokenReaderSwiftBridgeTestCase.m | 38 ++++ ...ceInfoReaderExtendedIntegrationTestsCase.m | 50 ++++- ...DeviceInfoReaderIntegrationTestsCaseBase.h | 13 +- ...DeviceInfoReaderIntegrationTestsCaseBase.m | 35 ++-- ...DSDeviceInfoReaderIntegrationTestsLegacy.m | 19 +- ...SDeviceInfoReaderMinIntegrationTestsCase.m | 21 +- .../UADSGameSessionIdReaderBaseTestsCase.m | 10 +- Tests/UnityAdsTests/InvocationTests.m | 5 + .../Metrics/UADSMetricSenderTestCase.m | 2 + ...foBodyReaderIntegrationTestsCaseBase.swift | 158 ++++++++++++++ ...foBodyReaderIntegrationTestsCaseBase.swift | 67 ++++++ ...ceInfoBodyReaderIntegrationTestsCase.swift | 28 +++ ...SDKInitializerLegacyIntegrationTests.swift | 22 +- .../JSONStorageContentNormalizerTests.swift | 118 +++++++++++ .../ObjCBridges/SDKObjCBridgesTests.swift | 51 +++++ ...tializerParallelFlowIntegrationTests.swift | 67 ++++-- ...alizerSequentialFlowIntegrationTests.swift | 90 ++++++-- ...nitializationTaskSequenceLegacyTests.swift | 10 - .../Tasks/InitModulesTaskTests.swift | 76 +++++++ .../Tasks/Mocks/LegacyTaskMock.swift | 13 ++ .../PreviousSessionCleanupTaskTests.swift | 31 ++- .../Tasks/StartInitTaskTests.swift | 71 +++++++ ...nitializerLegacyIntegrationTestsBase.swift | 44 +++- .../SDKNetworkTestsHelper.swift | 10 +- .../MetricTypes/SDKMetricType.swift | 2 + .../MetricTypes/SDKMetricTypeLegacy.swift | 4 +- .../Mocks/ExperimentsReaderMock.swift | 12 ++ .../Mocks/Factories/InitTaskFactoryMock.swift | 12 ++ .../Mocks/Metrcis/ExpectedMetrics.swift | 10 +- .../URLProtocolMetricsNetworkStub.swift | 4 +- .../Mocks/Storage/KeyValueStorageMock.swift | 29 +++ .../TestTools/Mocks/Tasks/TaskMock.swift | 15 ++ .../TestTools/Mocks/TimeReaderMock.swift | 26 +++ .../Network/NetworkTestCaseBase.swift | 3 +- .../HeaderBiddingTokenReaderTestsCase.swift | 47 +++++ .../Mocks/MockIdStore.swift | 23 --- .../UADSInstallationIdExtension.h | 14 -- .../UADSInstallationIdTests.swift | 195 ------------------ .../UADSPlistTests.swift | 176 ---------------- .../UADSSessionIdTests.swift | 54 ----- .../UADSUnityPlayerPrefsStoreTests.swift | 85 -------- .../UADSUserDefaultsStoreTests.swift | 39 ---- .../Tools/Timer/UADSTimerTests.m | 2 +- .../DynamicLibLoader/DynamicLibLoaderTests.m | 4 - .../GMATestsHelper/GMATestsHelper.m | 5 +- .../UADTestsTools/Mocks/USRVWebViewAppMock.m | 1 - .../Mocks/UnityAdsLoadDelegateMock.m | 4 +- .../UADSLoadModuleIntegrationTests.m | 1 - .../WebViewMethodInvokeHandlerTests.m | 4 +- UnityAds.podspec | 4 +- 160 files changed, 2374 insertions(+), 1667 deletions(-) create mode 100644 SourceCode/Private/Core/Device/DeviceInfoReader/Decorators/UADSDeviceInfoReaderGate.h create mode 100644 SourceCode/Private/Core/Device/DeviceInfoReader/Decorators/UADSDeviceInfoReaderGate.m create mode 100644 SourceCode/Private/Core/Device/DeviceInfoReader/Decorators/UADSDeviceInfoReaderWithSessionId.h create mode 100644 SourceCode/Private/Core/Device/DeviceInfoReader/Decorators/UADSDeviceInfoReaderWithSessionId.m create mode 100644 SourceCode/Private/Core/Device/HeaderBiddingTokenReader/UADSHeaderBiddingTokenReaderSwiftBridge.h create mode 100644 SourceCode/Private/Core/Device/HeaderBiddingTokenReader/UADSHeaderBiddingTokenReaderSwiftBridge.m delete mode 100644 SourceCode/Private/Core/SKAdNetwork/USRVApiSKAdNetwork.h delete mode 100644 SourceCode/Private/Core/SKAdNetwork/USRVApiSKAdNetwork.m delete mode 100644 SourceCode/Private/Core/SKAdNetwork/USRVSKAdNetworkProxy.h delete mode 100644 SourceCode/Private/Core/SKAdNetwork/USRVSKAdNetworkProxy.m delete mode 100644 SourceCode/Private/UnityServicesIdentifiers/UADSIdStore.h delete mode 100644 SourceCode/Private/UnityServicesIdentifiers/UADSInstallationId.m delete mode 100644 SourceCode/Private/UnityServicesIdentifiers/UADSPlist.h delete mode 100644 SourceCode/Private/UnityServicesIdentifiers/UADSPlist.m delete mode 100644 SourceCode/Private/UnityServicesIdentifiers/UADSSessionId.m delete mode 100644 SourceCode/Private/UnityServicesIdentifiers/UADSUnityPlayerPrefsStore.h delete mode 100644 SourceCode/Private/UnityServicesIdentifiers/UADSUnityPlayerPrefsStore.m delete mode 100644 SourceCode/Private/UnityServicesIdentifiers/UADSUserDefaultsStore.h delete mode 100644 SourceCode/Private/UnityServicesIdentifiers/UADSUserDefaultsStore.m delete mode 100644 SourceCode/Public/UnityServicesIdentifiers/UADSInstallationId.h delete mode 100644 SourceCode/Public/UnityServicesIdentifiers/UADSSessionId.h create mode 100644 SourceCode/Swift/DeviceInfo/DeviceInfoBodyReaderBuilder.swift delete mode 100644 SourceCode/Swift/Initialization/SharedSessionId/SharedSessionIdReader.swift create mode 100644 SourceCode/Swift/Initialization/Tasks/InitModulesTask.swift create mode 100644 SourceCode/Swift/Network/UnityAdsEventsNetworkServicesFactory.swift create mode 100644 SourceCode/Swift/ObjBridges/DeviceInfo/DeviceInfoObjBridge.swift create mode 100644 SourceCode/Swift/ObjBridges/JSONStorage/JSONStorageBridge.swift create mode 100644 SourceCode/Swift/ObjBridges/JSONStorage/JSONStorageContentNormalizer.swift create mode 100644 SourceCode/Swift/Token/HeaderBiddingToken.swift create mode 100644 SourceCode/Swift/Token/HeaderBiddingTokenReader.swift create mode 100644 Tests/UnityAdsTests/Core/Device/HeaderBiddingTokenReader/UADSHeaderBiddingTokenReaderSwiftBridgeTestCase.m create mode 100644 Tests/UnityAdsTests/Swift/DeviceInfoBodyReader/DeviceInfoBodyReaderIntegrationTestsCaseBase.swift create mode 100644 Tests/UnityAdsTests/Swift/DeviceInfoBodyReader/ExtendedDeviceInfoBodyReaderIntegrationTestsCaseBase.swift create mode 100644 Tests/UnityAdsTests/Swift/DeviceInfoBodyReader/MinDeviceInfoBodyReaderIntegrationTestsCase.swift create mode 100644 Tests/UnityAdsTests/Swift/Initialization/IntegrationTests/ObjCBridges/JSONStorageContentNormalizerTests.swift create mode 100644 Tests/UnityAdsTests/Swift/Initialization/IntegrationTests/ObjCBridges/SDKObjCBridgesTests.swift create mode 100644 Tests/UnityAdsTests/Swift/Initialization/Tasks/InitModulesTaskTests.swift create mode 100644 Tests/UnityAdsTests/Swift/Initialization/Tasks/Mocks/LegacyTaskMock.swift create mode 100644 Tests/UnityAdsTests/Swift/Initialization/Tasks/StartInitTaskTests.swift create mode 100644 Tests/UnityAdsTests/Swift/TestTools/Mocks/ExperimentsReaderMock.swift create mode 100644 Tests/UnityAdsTests/Swift/TestTools/Mocks/Factories/InitTaskFactoryMock.swift create mode 100644 Tests/UnityAdsTests/Swift/TestTools/Mocks/Storage/KeyValueStorageMock.swift create mode 100644 Tests/UnityAdsTests/Swift/TestTools/Mocks/Tasks/TaskMock.swift create mode 100644 Tests/UnityAdsTests/Swift/TestTools/Mocks/TimeReaderMock.swift create mode 100644 Tests/UnityAdsTests/Swift/Token/HeaderBiddingTokenReaderTestsCase.swift delete mode 100644 Tests/UnityAdsTests/Swift/UnityServicesIdentifiersTests/Mocks/MockIdStore.swift delete mode 100644 Tests/UnityAdsTests/Swift/UnityServicesIdentifiersTests/UADSInstallationIdExtension.h delete mode 100644 Tests/UnityAdsTests/Swift/UnityServicesIdentifiersTests/UADSInstallationIdTests.swift delete mode 100644 Tests/UnityAdsTests/Swift/UnityServicesIdentifiersTests/UADSPlistTests.swift delete mode 100644 Tests/UnityAdsTests/Swift/UnityServicesIdentifiersTests/UADSSessionIdTests.swift delete mode 100644 Tests/UnityAdsTests/Swift/UnityServicesIdentifiersTests/UADSUnityPlayerPrefsStoreTests.swift delete mode 100644 Tests/UnityAdsTests/Swift/UnityServicesIdentifiersTests/UADSUserDefaultsStoreTests.swift diff --git a/LICENSE b/LICENSE index e046de09..c38d960d 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Unity Advertisements copyright © 2022 Unity Technologies. +Unity Advertisements copyright © 2023 Unity Technologies. This software is subject to, and made available under, the terms of service for Operate Solutions (see https://unity3d.com/legal/one-operate-services-terms-of-service), and is an "Operate Service" as defined therein. Your use of the Services constitutes your acceptance of such terms. Unless expressly provided otherwise, the software under this license is made available strictly on an "AS IS" BASIS WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED. Please review the terms of service for details on these and other terms and conditions. \ No newline at end of file diff --git a/SourceCode/Private/Core/Api/USRVApiSdk.h b/SourceCode/Private/Core/Api/USRVApiSdk.h index 4af51953..3bfbdd1e 100644 --- a/SourceCode/Private/Core/Api/USRVApiSdk.h +++ b/SourceCode/Private/Core/Api/USRVApiSdk.h @@ -7,6 +7,5 @@ typedef NS_ENUM (NSInteger, USRVDownloadLatestWebViewStatus) { kDownloadLatestWebViewStatusMissingLatestConfig, kDownloadLatestWebViewStatusBackgroundDownloadStarted }; -+ (void)setServiceProviderForTesting: (id)sProvider; -+ (void)WebViewExposed_getTrrData: (USRVWebViewCallback *)callback; ++ (void)WebViewExposed_getTrrData: (nonnull USRVWebViewCallback *)callback; @end diff --git a/SourceCode/Private/Core/Api/USRVApiSdk.m b/SourceCode/Private/Core/Api/USRVApiSdk.m index 7b163045..1128089e 100644 --- a/SourceCode/Private/Core/Api/USRVApiSdk.m +++ b/SourceCode/Private/Core/Api/USRVApiSdk.m @@ -7,17 +7,8 @@ #import "USRVDevice.h" #import "UADSServiceProviderContainer.h" -static UADSServiceProvider* serviceProvider; @implementation USRVApiSdk -+ (void)load { - serviceProvider = UADSServiceProviderContainer.sharedInstance.serviceProvider; -} - -+ (void)setServiceProviderForTesting: (UADSServiceProvider*)sProvider { - serviceProvider = sProvider; -} - + (void)WebViewExposed_loadComplete: (USRVWebViewCallback *)callback { USRVLogDebug(@"Web application loaded"); [[USRVWebViewApp getCurrentApp] setWebAppLoaded: true]; @@ -114,11 +105,11 @@ + (NSString *)privacyState { } + (void)WebViewExposed_getTrrData: (USRVWebViewCallback *)callback { - [callback invoke: serviceProvider.configurationStorage.getCurrentConfiguration.originalJSON, nil]; + [callback invoke: UADSServiceProviderContainer.sharedInstance.serviceProvider.configurationStorage.getCurrentConfiguration.originalJSON, nil]; } + (void)WebViewExposed_getSharedSessionID:(USRVWebViewCallback *)callback { - [callback invoke: serviceProvider.sharedSessionId]; + [callback invoke: UADSServiceProviderContainer.sharedInstance.serviceProvider.sharedSessionId]; } @end diff --git a/SourceCode/Private/Core/Configuration/SDKConfigurationReader/ConfigurationLoader/Decorators/UADSConfigurationLoaderWithPrivacy.m b/SourceCode/Private/Core/Configuration/SDKConfigurationReader/ConfigurationLoader/Decorators/UADSConfigurationLoaderWithPrivacy.m index 2d412f76..2e05d325 100644 --- a/SourceCode/Private/Core/Configuration/SDKConfigurationReader/ConfigurationLoader/Decorators/UADSConfigurationLoaderWithPrivacy.m +++ b/SourceCode/Private/Core/Configuration/SDKConfigurationReader/ConfigurationLoader/Decorators/UADSConfigurationLoaderWithPrivacy.m @@ -1,9 +1,11 @@ #import "UADSConfigurationLoaderWithPrivacy.h" +#import "UADSErrorState.h" @interface UADSConfigurationLoaderWithPrivacy () @property (nonatomic, strong) idoriginal; @property (nonatomic, strong) idprivacyLoader; @property (nonatomic, strong) idresponseStorage; +@property (nonatomic, strong) NSArray *fastFailCodes; @end @implementation UADSConfigurationLoaderWithPrivacy @@ -17,6 +19,7 @@ + (instancetype)newWithOriginal: (id)original decorator.original = original; decorator.privacyLoader = privacyLoader; decorator.responseStorage = responseStorage; + decorator.fastFailCodes = @[@(kPrivacyGameIdDisabledCode)]; return decorator; } @@ -72,7 +75,7 @@ - (void)processPrivacyError: (id)privacyError } - (BOOL)shouldProceedWithTheCallForError: (id)error { - return error.errorDomain == kPrivacyLoaderErrorDomain; + return error.errorDomain == kPrivacyLoaderErrorDomain && ![_fastFailCodes containsObject: error.errorCode]; } @end diff --git a/SourceCode/Private/Core/Configuration/SDKConfigurationReader/ConfigurationLoader/PrivacyLoader/UADSInitializationResponse.h b/SourceCode/Private/Core/Configuration/SDKConfigurationReader/ConfigurationLoader/PrivacyLoader/UADSInitializationResponse.h index 5ee9ef1e..e33aa7fd 100644 --- a/SourceCode/Private/Core/Configuration/SDKConfigurationReader/ConfigurationLoader/PrivacyLoader/UADSInitializationResponse.h +++ b/SourceCode/Private/Core/Configuration/SDKConfigurationReader/ConfigurationLoader/PrivacyLoader/UADSInitializationResponse.h @@ -34,6 +34,7 @@ NS_ASSUME_NONNULL_BEGIN @property (nonatomic, strong, readonly) NSDictionary *originalJSON; @property (nonatomic, assign) long responseCode; @property (nonatomic, assign) BOOL allowTracking; +@property (nonatomic, assign) BOOL shouldSendNonBehavioural; + (instancetype)newFromDictionary: (NSDictionary *)dictionary; diff --git a/SourceCode/Private/Core/Configuration/SDKConfigurationReader/ConfigurationLoader/PrivacyLoader/UADSInitializationResponse.m b/SourceCode/Private/Core/Configuration/SDKConfigurationReader/ConfigurationLoader/PrivacyLoader/UADSInitializationResponse.m index 0265f007..f144894f 100644 --- a/SourceCode/Private/Core/Configuration/SDKConfigurationReader/ConfigurationLoader/PrivacyLoader/UADSInitializationResponse.m +++ b/SourceCode/Private/Core/Configuration/SDKConfigurationReader/ConfigurationLoader/PrivacyLoader/UADSInitializationResponse.m @@ -40,6 +40,7 @@ + (instancetype)newFromDictionary: (NSDictionary *)dictionary { response.originalJSON = dictionary; response.allowTracking = [dictionary[@"pas"] boolValue] ? : false; + response.shouldSendNonBehavioural = [dictionary[@"snb"] boolValue] ?: false; return response; } diff --git a/SourceCode/Private/Core/Configuration/SDKConfigurationReader/ConfigurationLoader/PrivacyLoader/UADSPrivacyLoader.h b/SourceCode/Private/Core/Configuration/SDKConfigurationReader/ConfigurationLoader/PrivacyLoader/UADSPrivacyLoader.h index 2a8daf5b..54c701e6 100644 --- a/SourceCode/Private/Core/Configuration/SDKConfigurationReader/ConfigurationLoader/PrivacyLoader/UADSPrivacyLoader.h +++ b/SourceCode/Private/Core/Configuration/SDKConfigurationReader/ConfigurationLoader/PrivacyLoader/UADSPrivacyLoader.h @@ -2,6 +2,8 @@ #import "UADSInitializationResponse.h" #import "UADSGenericCompletion.h" #import "USRVInitializationRequestFactory.h" +#import "UADSErrorState.h" + NS_ASSUME_NONNULL_BEGIN typedef void (^UADSPrivacyCompletion)(UADSInitializationResponse *); @@ -32,6 +34,11 @@ extern NSString *const kPrivacyLoaderErrorDomain; code: kUADSPrivacyLoaderInvalidResponseCode \ userInfo: nil] \ +#define uads_privacyGameDisabledError \ + [[NSError alloc] initWithDomain: kPrivacyLoaderErrorDomain \ + code: kPrivacyGameIdDisabledCode \ + userInfo: nil] \ + @protocol UADSPrivacyLoader - (void)loadPrivacyWithSuccess: (UADSPrivacyCompletion)success andErrorCompletion: (UADSErrorCompletion)errorCompletion; diff --git a/SourceCode/Private/Core/Configuration/SDKConfigurationReader/ConfigurationLoader/PrivacyLoader/UADSPrivacyLoader.m b/SourceCode/Private/Core/Configuration/SDKConfigurationReader/ConfigurationLoader/PrivacyLoader/UADSPrivacyLoader.m index d6c03ab0..de68f1ec 100644 --- a/SourceCode/Private/Core/Configuration/SDKConfigurationReader/ConfigurationLoader/PrivacyLoader/UADSPrivacyLoader.m +++ b/SourceCode/Private/Core/Configuration/SDKConfigurationReader/ConfigurationLoader/PrivacyLoader/UADSPrivacyLoader.m @@ -68,6 +68,10 @@ - (void)makePrivacyRequestWithSuccess: (nonnull UADSPrivacyCompletion)success } if (![request is2XXResponse]) { + if (request.responseCode == 423) { + errorCompletion(uads_privacyGameDisabledError); + return; + } errorCompletion(uads_privacyInvalidResponseCodeError); return; } diff --git a/SourceCode/Private/Core/Configuration/SDKConfigurationReader/ConfigurationLoader/PrivacyLoader/UADSPrivacyStorage.h b/SourceCode/Private/Core/Configuration/SDKConfigurationReader/ConfigurationLoader/PrivacyLoader/UADSPrivacyStorage.h index f253f05f..7d90af51 100644 --- a/SourceCode/Private/Core/Configuration/SDKConfigurationReader/ConfigurationLoader/PrivacyLoader/UADSPrivacyStorage.h +++ b/SourceCode/Private/Core/Configuration/SDKConfigurationReader/ConfigurationLoader/PrivacyLoader/UADSPrivacyStorage.h @@ -21,6 +21,7 @@ NSString * uads_privacyResponseStateToString(UADSPrivacyResponseState); @protocol UADSPrivacyResponseReader - (UADSPrivacyResponseState)responseState; +- (BOOL)shouldSendUserNonBehavioral; @end diff --git a/SourceCode/Private/Core/Configuration/SDKConfigurationReader/ConfigurationLoader/PrivacyLoader/UADSPrivacyStorage.m b/SourceCode/Private/Core/Configuration/SDKConfigurationReader/ConfigurationLoader/PrivacyLoader/UADSPrivacyStorage.m index dc3e23b8..558483b7 100644 --- a/SourceCode/Private/Core/Configuration/SDKConfigurationReader/ConfigurationLoader/PrivacyLoader/UADSPrivacyStorage.m +++ b/SourceCode/Private/Core/Configuration/SDKConfigurationReader/ConfigurationLoader/PrivacyLoader/UADSPrivacyStorage.m @@ -34,6 +34,10 @@ - (void)saveResponse: (nonnull UADSInitializationResponse *)response { [self.mediator notifyObserversWithObjectAndRemove: response]; } +- (BOOL)shouldSendUserNonBehavioral { + return self.response.shouldSendNonBehavioural; +} + - (UADSPrivacyResponseState)responseState { if (!self.response) { return kUADSPrivacyResponseUnknown; diff --git a/SourceCode/Private/Core/Configuration/SDKConfigurationReader/ConfigurationLoader/UADSConfigurationLoaderBuilder.h b/SourceCode/Private/Core/Configuration/SDKConfigurationReader/ConfigurationLoader/UADSConfigurationLoaderBuilder.h index 572b130c..34747975 100644 --- a/SourceCode/Private/Core/Configuration/SDKConfigurationReader/ConfigurationLoader/UADSConfigurationLoaderBuilder.h +++ b/SourceCode/Private/Core/Configuration/SDKConfigurationReader/ConfigurationLoader/UADSConfigurationLoaderBuilder.h @@ -28,6 +28,7 @@ NS_ASSUME_NONNULL_BEGIN @property (nonatomic, strong) idlogger; @property (nonatomic, strong) id retryInfoReader; @property (nonatomic, strong) id gameSessionIdReader; +@property (nonatomic, strong) id sharedSessionIdReader; @property (nonatomic) BOOL noCompression; - (id)requestFactoryWithExtendedInfo: (BOOL)hasExtendedInfo; diff --git a/SourceCode/Private/Core/Configuration/SDKConfigurationReader/ConfigurationLoader/UADSConfigurationLoaderBuilder.m b/SourceCode/Private/Core/Configuration/SDKConfigurationReader/ConfigurationLoader/UADSConfigurationLoaderBuilder.m index 77616999..7d48412e 100644 --- a/SourceCode/Private/Core/Configuration/SDKConfigurationReader/ConfigurationLoader/UADSConfigurationLoaderBuilder.m +++ b/SourceCode/Private/Core/Configuration/SDKConfigurationReader/ConfigurationLoader/UADSConfigurationLoaderBuilder.m @@ -94,6 +94,7 @@ + (instancetype)newWithConfig: (id)config builder.logger = self.logger; builder.currentTimeStampReader = self.currentTimeStampReader; builder.gameSessionIdReader = self.gameSessionIdReader; + builder.sharedSessionIdReader = self.sharedSessionIdReader; return builder.defaultReader; } diff --git a/SourceCode/Private/Core/Configuration/SDKConfigurationReader/UADSConfigurationExperiments.h b/SourceCode/Private/Core/Configuration/SDKConfigurationReader/UADSConfigurationExperiments.h index 75c5e3af..61ff598e 100644 --- a/SourceCode/Private/Core/Configuration/SDKConfigurationReader/UADSConfigurationExperiments.h +++ b/SourceCode/Private/Core/Configuration/SDKConfigurationReader/UADSConfigurationExperiments.h @@ -15,6 +15,7 @@ NS_ASSUME_NONNULL_BEGIN - (BOOL) isPrivacyWaitEnabled; - (BOOL) isNativeWebViewCacheEnabled; - (BOOL) isWebAdAssetCacheEnabled; +- (BOOL) isSwiftTokenEnabled; - (NSDictionary *)nextSessionFlags; - (NSDictionary *)currentSessionFlags; diff --git a/SourceCode/Private/Core/Configuration/SDKConfigurationReader/UADSConfigurationExperiments.m b/SourceCode/Private/Core/Configuration/SDKConfigurationReader/UADSConfigurationExperiments.m index 0abbac6c..2dec3bd6 100644 --- a/SourceCode/Private/Core/Configuration/SDKConfigurationReader/UADSConfigurationExperiments.m +++ b/SourceCode/Private/Core/Configuration/SDKConfigurationReader/UADSConfigurationExperiments.m @@ -73,6 +73,10 @@ - (BOOL)isWebAdAssetCacheEnabled { return [self isExperimentEnabledWithKey: @"wac"]; } +- (BOOL)isSwiftTokenEnabled { + return [self isExperimentEnabledWithKey: @"s_tkn"]; +} + - (NSDictionary *)nextSessionFlags { return [self flattenFlagsWith:^BOOL (id key) { return [self isExperimentForNextSession: key]; diff --git a/SourceCode/Private/Core/Configuration/UADSErrorState.h b/SourceCode/Private/Core/Configuration/UADSErrorState.h index 82f3f998..ec9d557b 100644 --- a/SourceCode/Private/Core/Configuration/UADSErrorState.h +++ b/SourceCode/Private/Core/Configuration/UADSErrorState.h @@ -13,3 +13,5 @@ typedef NS_ENUM (NSInteger, UADSErrorState) { NSString * uads_errorStateString(UADSErrorState state); BOOL uads_isWebViewErrorState(UADSErrorState state); + +extern const int kPrivacyGameIdDisabledCode; diff --git a/SourceCode/Private/Core/Configuration/UADSErrorState.m b/SourceCode/Private/Core/Configuration/UADSErrorState.m index 4175603a..3b9d88f3 100644 --- a/SourceCode/Private/Core/Configuration/UADSErrorState.m +++ b/SourceCode/Private/Core/Configuration/UADSErrorState.m @@ -45,3 +45,5 @@ BOOL uads_isWebViewErrorState(UADSErrorState state) { return false; } } + +const int kPrivacyGameIdDisabledCode = 423; diff --git a/SourceCode/Private/Core/Configuration/USRVCoreModuleConfiguration.m b/SourceCode/Private/Core/Configuration/USRVCoreModuleConfiguration.m index 853c9e5c..564c7968 100644 --- a/SourceCode/Private/Core/Configuration/USRVCoreModuleConfiguration.m +++ b/SourceCode/Private/Core/Configuration/USRVCoreModuleConfiguration.m @@ -33,8 +33,7 @@ @implementation USRVCoreModuleConfiguration @"USRVApiPermissions", @"USRVApiMainBundle", @"USRVApiWebAuth", - @"USRVApiTrackingManager", - @"USRVApiSKAdNetwork" + @"USRVApiTrackingManager" ]; } /* getWebAppApiClassList */ diff --git a/SourceCode/Private/Core/Device/DeviceInfoReader/Decorators/UADSDeviceInfoReaderGate.h b/SourceCode/Private/Core/Device/DeviceInfoReader/Decorators/UADSDeviceInfoReaderGate.h new file mode 100644 index 00000000..47898646 --- /dev/null +++ b/SourceCode/Private/Core/Device/DeviceInfoReader/Decorators/UADSDeviceInfoReaderGate.h @@ -0,0 +1,13 @@ +#import "UADSDeviceInfoReader.h" +#import "UADSPIIDataProvider.h" +#import "UADSPrivacyStorage.h" +#import "UADSPIITrackingStatusReader.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface UADSDeviceInfoReaderGate : NSObject ++ (instancetype)decorateOriginal: (id)original + withPrivacyReader: (id)privacyReader; +@end + +NS_ASSUME_NONNULL_END diff --git a/SourceCode/Private/Core/Device/DeviceInfoReader/Decorators/UADSDeviceInfoReaderGate.m b/SourceCode/Private/Core/Device/DeviceInfoReader/Decorators/UADSDeviceInfoReaderGate.m new file mode 100644 index 00000000..ceafe93a --- /dev/null +++ b/SourceCode/Private/Core/Device/DeviceInfoReader/Decorators/UADSDeviceInfoReaderGate.m @@ -0,0 +1,32 @@ +#import "UADSDeviceInfoReaderGate.h" +#import "NSMutableDictionary+SafeRemoval.h" +#import "UADSJsonStorageKeyNames.h" + +@interface UADSDeviceInfoReaderGate () +@property (nonatomic, strong) idoriginal; +@property (nonatomic, strong) idprivacyReader; +@end + + +@implementation UADSDeviceInfoReaderGate ++ (instancetype)decorateOriginal: (id)original + withPrivacyReader: (id)privacyReader { + UADSDeviceInfoReaderGate *decorator = [self new]; + + decorator.original = original; + decorator.privacyReader = privacyReader; + return decorator; +} + + +- (nonnull NSDictionary *)getDeviceInfoForGameMode:(UADSGameMode)mode { + NSMutableDictionary *info = [[NSMutableDictionary alloc] initWithDictionary: [_original getDeviceInfoForGameMode: mode]]; + if (!_privacyReader.shouldSendUserNonBehavioral) { + [info uads_removeObjectForKeyAndReturn: UADSJsonStorageKeyNames.userNonBehavioralFlagKey]; + } + + return info; +} + +@end + diff --git a/SourceCode/Private/Core/Device/DeviceInfoReader/Decorators/UADSDeviceInfoReaderKeys.h b/SourceCode/Private/Core/Device/DeviceInfoReader/Decorators/UADSDeviceInfoReaderKeys.h index 1428cb96..3c2520fd 100644 --- a/SourceCode/Private/Core/Device/DeviceInfoReader/Decorators/UADSDeviceInfoReaderKeys.h +++ b/SourceCode/Private/Core/Device/DeviceInfoReader/Decorators/UADSDeviceInfoReaderKeys.h @@ -55,4 +55,8 @@ extern NSString *const kUADSDeviceInfoSKADNVersionsKey; extern NSString *const kUADSDeviceInfoAnalyticSessionIDKey; extern NSString *const kUADSDeviceInfoAnalyticUserIDKey; +extern NSString *const kUADSDeviceInfoSessionIdKey; + +extern NSString *const kUADSDeviceInfoReaderAUIDKey; + NS_ASSUME_NONNULL_END diff --git a/SourceCode/Private/Core/Device/DeviceInfoReader/Decorators/UADSDeviceInfoReaderKeys.m b/SourceCode/Private/Core/Device/DeviceInfoReader/Decorators/UADSDeviceInfoReaderKeys.m index d2dad000..b6692a77 100644 --- a/SourceCode/Private/Core/Device/DeviceInfoReader/Decorators/UADSDeviceInfoReaderKeys.m +++ b/SourceCode/Private/Core/Device/DeviceInfoReader/Decorators/UADSDeviceInfoReaderKeys.m @@ -50,3 +50,5 @@ NSString *const kUADSDeviceInfoBuiltSDKVersionKey = @"builtSdkVersion"; NSString *const kUADSDeviceInfoAnalyticSessionIDKey = @"analyticsSessionId"; NSString *const kUADSDeviceInfoAnalyticUserIDKey = @"analyticsUserId"; +NSString *const kUADSDeviceInfoSessionIdKey = @"sessionId"; +NSString *const kUADSDeviceInfoReaderAUIDKey = @"auid"; diff --git a/SourceCode/Private/Core/Device/DeviceInfoReader/Decorators/UADSDeviceInfoReaderWithPII/UADSDeviceInfoReaderWithPrivacy.m b/SourceCode/Private/Core/Device/DeviceInfoReader/Decorators/UADSDeviceInfoReaderWithPII/UADSDeviceInfoReaderWithPrivacy.m index e1ef2481..96de17f5 100644 --- a/SourceCode/Private/Core/Device/DeviceInfoReader/Decorators/UADSDeviceInfoReaderWithPII/UADSDeviceInfoReaderWithPrivacy.m +++ b/SourceCode/Private/Core/Device/DeviceInfoReader/Decorators/UADSDeviceInfoReaderWithPII/UADSDeviceInfoReaderWithPrivacy.m @@ -31,9 +31,6 @@ - (nonnull NSDictionary *)getDeviceInfoForGameMode: (UADSGameMode)mode { if (_privacyReader.responseState == kUADSPrivacyResponseAllowed) { mInfo[self.vendorIDKey] = _dataProvider.vendorID; mInfo[self.advertisingTrackingIdKey] = _dataProvider.advertisingTrackingID; - - [mInfo uads_setValueIfNotNil: @(_userContainer.userNonBehavioralFlag) - forKey: self.userNonBehavioralFlagKey]; } return mInfo; diff --git a/SourceCode/Private/Core/Device/DeviceInfoReader/Decorators/UADSDeviceInfoReaderWithPII/UADSPIITrackingStatusReader.h b/SourceCode/Private/Core/Device/DeviceInfoReader/Decorators/UADSDeviceInfoReaderWithPII/UADSPIITrackingStatusReader.h index 04dd0d43..5605638f 100644 --- a/SourceCode/Private/Core/Device/DeviceInfoReader/Decorators/UADSDeviceInfoReaderWithPII/UADSPIITrackingStatusReader.h +++ b/SourceCode/Private/Core/Device/DeviceInfoReader/Decorators/UADSDeviceInfoReaderWithPII/UADSPIITrackingStatusReader.h @@ -14,7 +14,7 @@ extern NSString * uads_privacyModeString(UADSPrivacyMode mode); @protocol UADSPIITrackingStatusReader - (UADSPrivacyMode)privacyMode; -- (BOOL) userNonBehavioralFlag; +- (NSNumber *)userNonBehavioralFlag; @end @interface UADSPIITrackingStatusReaderBase : NSObject diff --git a/SourceCode/Private/Core/Device/DeviceInfoReader/Decorators/UADSDeviceInfoReaderWithPII/UADSPIITrackingStatusReader.m b/SourceCode/Private/Core/Device/DeviceInfoReader/Decorators/UADSDeviceInfoReaderWithPII/UADSPIITrackingStatusReader.m index a1aa0de0..4d4e34ed 100644 --- a/SourceCode/Private/Core/Device/DeviceInfoReader/Decorators/UADSDeviceInfoReaderWithPII/UADSPIITrackingStatusReader.m +++ b/SourceCode/Private/Core/Device/DeviceInfoReader/Decorators/UADSDeviceInfoReaderWithPII/UADSPIITrackingStatusReader.m @@ -93,14 +93,14 @@ - (UADSPrivacyMode)spmPrivacyMode { return uads_privacyModeFromString(privacyMode); } -- (BOOL)userNonBehavioralFlag { +- (NSNumber *)userNonBehavioralFlag { id flag = [self.storageReader getValueForKey: [UADSJsonStorageKeyNames userNonBehavioralValueFlagKey]]; if (flag == nil) { flag = [self.storageReader getValueForKey: [UADSJsonStorageKeyNames userNonbehavioralValueFlagKey]]; } - return [flag boolValue]; + return flag ? @([flag boolValue]) : nil; } @end diff --git a/SourceCode/Private/Core/Device/DeviceInfoReader/Decorators/UADSDeviceInfoReaderWithSessionId.h b/SourceCode/Private/Core/Device/DeviceInfoReader/Decorators/UADSDeviceInfoReaderWithSessionId.h new file mode 100644 index 00000000..03c9911b --- /dev/null +++ b/SourceCode/Private/Core/Device/DeviceInfoReader/Decorators/UADSDeviceInfoReaderWithSessionId.h @@ -0,0 +1,12 @@ +#import +#import "UADSDeviceInfoReader.h" +#import "UADSSharedSessionIdReader.h" +NS_ASSUME_NONNULL_BEGIN + +@interface UADSDeviceInfoReaderWithSessionId : NSObject + ++ (id)newWithOriginal: (id)original + andSessionIdReader: (id)sessionIdReader; +@end + +NS_ASSUME_NONNULL_END diff --git a/SourceCode/Private/Core/Device/DeviceInfoReader/Decorators/UADSDeviceInfoReaderWithSessionId.m b/SourceCode/Private/Core/Device/DeviceInfoReader/Decorators/UADSDeviceInfoReaderWithSessionId.m new file mode 100644 index 00000000..11852d25 --- /dev/null +++ b/SourceCode/Private/Core/Device/DeviceInfoReader/Decorators/UADSDeviceInfoReaderWithSessionId.m @@ -0,0 +1,28 @@ +#import "UADSDeviceInfoReaderWithSessionId.h" +#import "UADSDeviceInfoReaderKeys.h" + +@interface UADSDeviceInfoReaderWithSessionId() +@property (nonatomic, strong) id original; +@property (nonatomic, strong) id sessionIdReader; +@end + +@implementation UADSDeviceInfoReaderWithSessionId + ++ (id)newWithOriginal: (id)original + andSessionIdReader: (id)sessionIdReader { + UADSDeviceInfoReaderWithSessionId *reader = [UADSDeviceInfoReaderWithSessionId new]; + reader.original = original; + reader.sessionIdReader = sessionIdReader; + return reader; +} + +- (NSDictionary *)getDeviceInfoForGameMode: (UADSGameMode)mode { + NSDictionary *info = [_original getDeviceInfoForGameMode: mode]; + + NSMutableDictionary *mInfo = [[NSMutableDictionary alloc] initWithDictionary: info]; + mInfo[kUADSDeviceInfoSessionIdKey] = _sessionIdReader.sessionId; + + return mInfo; +} + +@end diff --git a/SourceCode/Private/Core/Device/DeviceInfoReader/UADSDeviceIDFIReader.h b/SourceCode/Private/Core/Device/DeviceInfoReader/UADSDeviceIDFIReader.h index a12d0b92..b0d0040d 100644 --- a/SourceCode/Private/Core/Device/DeviceInfoReader/UADSDeviceIDFIReader.h +++ b/SourceCode/Private/Core/Device/DeviceInfoReader/UADSDeviceIDFIReader.h @@ -14,6 +14,7 @@ NS_ASSUME_NONNULL_BEGIN - (NSString *)sessionID; - (NSString *)userID; +- (NSString *)auID; @end diff --git a/SourceCode/Private/Core/Device/DeviceInfoReader/UADSDeviceIDFIReader.m b/SourceCode/Private/Core/Device/DeviceInfoReader/UADSDeviceIDFIReader.m index d8958349..c5f12807 100644 --- a/SourceCode/Private/Core/Device/DeviceInfoReader/UADSDeviceIDFIReader.m +++ b/SourceCode/Private/Core/Device/DeviceInfoReader/UADSDeviceIDFIReader.m @@ -10,7 +10,7 @@ @implementation UADSDeviceIDFIReaderBase - (nonnull NSString *)idfi { - NSString *currentValue = [USRVPreferences getString: kUADSStorageIDFIKey]; + NSString *currentValue = [USRVPreferences getString: kUADSStorageIDFIKey] ?: [self auID]; if (currentValue == nil || currentValue.length == 0) { currentValue = [[USRVDevice getUniqueEventId] lowercaseString]; @@ -25,6 +25,10 @@ - (NSString *)sessionID { return [USRVPreferences getString: kUADSStorageAnalyticSessionKey]; } +- (NSString *)auID { + return [USRVPreferences getString: kUADSStorageAUIDKey]; +} + - (NSString *)userID { return [USRVPreferences getString: kUADSStorageAnalyticUserKey]; } diff --git a/SourceCode/Private/Core/Device/DeviceInfoReader/UADSDeviceInfoReader.m b/SourceCode/Private/Core/Device/DeviceInfoReader/UADSDeviceInfoReader.m index b5d477f8..767674b9 100644 --- a/SourceCode/Private/Core/Device/DeviceInfoReader/UADSDeviceInfoReader.m +++ b/SourceCode/Private/Core/Device/DeviceInfoReader/UADSDeviceInfoReader.m @@ -270,6 +270,12 @@ - (NSDictionary *)extendInfo: (NSDictionary *)baseInfo { [info uads_setValueIfNotNil: self.userDefaultsReader.sessionID forKey: kUADSDeviceInfoAnalyticSessionIDKey]; }]; + + [self measurePerformanceAndLog: @"AUID" + using: ^{ + [info uads_setValueIfNotNil: self.userDefaultsReader.auID + forKey: kUADSDeviceInfoReaderAUIDKey]; + }]; [self measurePerformanceAndLog: @"userID" using: ^{ diff --git a/SourceCode/Private/Core/Device/DeviceInfoReader/UADSDeviceInfoReaderBuilder.h b/SourceCode/Private/Core/Device/DeviceInfoReader/UADSDeviceInfoReaderBuilder.h index 1bcb5971..1b660525 100644 --- a/SourceCode/Private/Core/Device/DeviceInfoReader/UADSDeviceInfoReaderBuilder.h +++ b/SourceCode/Private/Core/Device/DeviceInfoReader/UADSDeviceInfoReaderBuilder.h @@ -6,6 +6,8 @@ #import "UADSPrivacyStorage.h" #import "UADSLogger.h" #import "UADSGameSessionIdReader.h" +#import "UADSSharedSessionIdReader.h" + NS_ASSUME_NONNULL_BEGIN @interface UADSDeviceInfoReaderBuilder : NSObject @@ -16,6 +18,7 @@ NS_ASSUME_NONNULL_BEGIN @property (nonatomic, strong) idcurrentTimeStampReader; @property (nonatomic, strong) id clientConfig; @property (nonatomic, strong) idgameSessionIdReader; +@property (nonatomic, strong) id sharedSessionIdReader; @property BOOL extendedReader; - (id)defaultReader; diff --git a/SourceCode/Private/Core/Device/DeviceInfoReader/UADSDeviceInfoReaderBuilder.m b/SourceCode/Private/Core/Device/DeviceInfoReader/UADSDeviceInfoReaderBuilder.m index abc1142d..c8eea640 100644 --- a/SourceCode/Private/Core/Device/DeviceInfoReader/UADSDeviceInfoReaderBuilder.m +++ b/SourceCode/Private/Core/Device/DeviceInfoReader/UADSDeviceInfoReaderBuilder.m @@ -11,6 +11,8 @@ #import "UADSDeviceInfoStorageKeysProviderExtended.h" #import "UADSDeviceInfoStorageKeysProviderMinimal.h" #import "UADSDeviceInfoReaderWithPrivacy.h" +#import "UADSDeviceInfoReaderGate.h" +#import "UADSDeviceInfoReaderWithSessionId.h" @implementation UADSDeviceInfoReaderBuilder - (id)defaultReader { @@ -28,14 +30,19 @@ @implementation UADSDeviceInfoReaderBuilder deviceInfoReader = [self addStorageDumpDecorator: deviceInfoReader]; if (extendedReader) { + deviceInfoReader = [self addGate: deviceInfoReader]; deviceInfoReader = [self addPIIDecorator: deviceInfoReader]; + + deviceInfoReader = [self addSessionIdDecorator: deviceInfoReader]; deviceInfoReader = [self addMetrics: deviceInfoReader usingMetricsSender: self.metricsSender currentTimestamp: self.currentTimeStampReader]; + } deviceInfoReader = [self addFilter: deviceInfoReader]; + return deviceInfoReader; } @@ -69,6 +76,11 @@ @implementation UADSDeviceInfoReaderBuilder andBlockList: self.defaultBlockList]; } +- (id)addGate: (id)original { + return [UADSDeviceInfoReaderGate decorateOriginal: original + withPrivacyReader: self.privacyReader]; +} + - (id)defaultBlockList { if (_storageBlockListProvider) { return _storageBlockListProvider; @@ -84,6 +96,11 @@ @implementation UADSDeviceInfoReaderBuilder andUserContainer: self.userStorageReader]; } +- (id)addSessionIdDecorator: (id)original { + return [UADSDeviceInfoReaderWithSessionId newWithOriginal: original + andSessionIdReader: self.sharedSessionIdReader]; +} + - (id)addMetrics: (id)original usingMetricsSender: (id)metricsSender currentTimestamp: (id)timestampReader { diff --git a/SourceCode/Private/Core/Device/DeviceInfoReader/UADSJsonStorageKeyNames.h b/SourceCode/Private/Core/Device/DeviceInfoReader/UADSJsonStorageKeyNames.h index 245b82e0..3eb28225 100644 --- a/SourceCode/Private/Core/Device/DeviceInfoReader/UADSJsonStorageKeyNames.h +++ b/SourceCode/Private/Core/Device/DeviceInfoReader/UADSJsonStorageKeyNames.h @@ -18,6 +18,7 @@ extern NSString *const kUADSUserContainerName; extern NSString *const kUADSStorageIDFIKey; extern NSString *const kUADSStorageAnalyticSessionKey; extern NSString *const kUADSStorageAnalyticUserKey; +extern NSString *const kUADSStorageAUIDKey; @interface UADSJsonStorageKeyNames : NSObject + (NSString *)webViewContainerKey; diff --git a/SourceCode/Private/Core/Device/DeviceInfoReader/UADSJsonStorageKeyNames.m b/SourceCode/Private/Core/Device/DeviceInfoReader/UADSJsonStorageKeyNames.m index c1fde656..3badc781 100644 --- a/SourceCode/Private/Core/Device/DeviceInfoReader/UADSJsonStorageKeyNames.m +++ b/SourceCode/Private/Core/Device/DeviceInfoReader/UADSJsonStorageKeyNames.m @@ -26,7 +26,7 @@ NSString *const kUADSStorageAnalyticSessionKey = @"unity.player_sessionid"; NSString *const kUADSStorageAnalyticUserKey = @"unity.cloud_userid"; - +NSString *const kUADSStorageAUIDKey = @"auid"; NSString *const kUADSSdkServiceModeKey = @"sdk.mode.value"; diff --git a/SourceCode/Private/Core/Device/DeviceInfoReader/UADSMinDeviceInfoReader.m b/SourceCode/Private/Core/Device/DeviceInfoReader/UADSMinDeviceInfoReader.m index 368ee126..fc19eb40 100644 --- a/SourceCode/Private/Core/Device/DeviceInfoReader/UADSMinDeviceInfoReader.m +++ b/SourceCode/Private/Core/Device/DeviceInfoReader/UADSMinDeviceInfoReader.m @@ -36,7 +36,7 @@ - (nonnull NSDictionary *)getDeviceInfoForGameMode: (UADSGameMode)mode { [info uads_setValueIfNotNil: self.userDefaultsReader.idfi forKey: kUADSDeviceInfoIDFIKey]; - [info uads_setValueIfNotNil: @(_userContainerReader.userNonBehavioralFlag) + [info uads_setValueIfNotNil: _userContainerReader.userNonBehavioralFlag forKey: UADSJsonStorageKeyNames.userNonBehavioralFlagKey]; diff --git a/SourceCode/Private/Core/Device/HeaderBiddingTokenReader/ScarHeaderBidding/Metric/UADSSCARHeaderBiddingMetric.m b/SourceCode/Private/Core/Device/HeaderBiddingTokenReader/ScarHeaderBidding/Metric/UADSSCARHeaderBiddingMetric.m index 1a17e1f1..dea03626 100644 --- a/SourceCode/Private/Core/Device/HeaderBiddingTokenReader/ScarHeaderBidding/Metric/UADSSCARHeaderBiddingMetric.m +++ b/SourceCode/Private/Core/Device/HeaderBiddingTokenReader/ScarHeaderBidding/Metric/UADSSCARHeaderBiddingMetric.m @@ -33,7 +33,7 @@ + (instancetype)newScarSendTimeSuccess: (NSNumber *)value isAsync:(BOOL)isAsync } + (instancetype)newScarSendTimeFailure: (NSNumber *)value tags: (NSDictionary *)tags isAsync:(BOOL)isAsync { - return [self newWithName: isAsync ? @"native_hb_signals_async_upload_failure" : @"native_hb_signals_sync_upload_success" + return [self newWithName: isAsync ? @"native_hb_signals_async_upload_failure" : @"native_hb_signals_sync_upload_failure" value: value tags: tags]; } diff --git a/SourceCode/Private/Core/Device/HeaderBiddingTokenReader/ScarHeaderBidding/UADSSCARRawSignalsReader.m b/SourceCode/Private/Core/Device/HeaderBiddingTokenReader/ScarHeaderBidding/UADSSCARRawSignalsReader.m index 1259d001..d46d5a4d 100644 --- a/SourceCode/Private/Core/Device/HeaderBiddingTokenReader/ScarHeaderBidding/UADSSCARRawSignalsReader.m +++ b/SourceCode/Private/Core/Device/HeaderBiddingTokenReader/ScarHeaderBidding/UADSSCARRawSignalsReader.m @@ -1,6 +1,7 @@ #import "UADSSCARRawSignalsReader.h" #import "UADSSCARSignalIdentifiers.h" #import "UADSSCARHeaderBiddingMetric.h" +#import "NSMutableDictionary+SafeOperations.h" @implementation UADSSCARRawSignalsReader @@ -16,9 +17,8 @@ - (void) requestSCARSignalsWithIsAsync:(BOOL)isAsync completion: (_Nullable UADS }; id error = ^(id _Nonnull error) { - NSMutableDictionary *tags = [NSMutableDictionary dictionaryWithDictionary: @{ - @"reason": error.errorCode - }]; + NSMutableDictionary *tags = [NSMutableDictionary new]; + [tags uads_setValueIfNotNil:error.errorCode forKey:@"reason"]; [self.config.metricsSender sendMetric: [UADSSCARHeaderBiddingMetric newScarFetchTimeFailure:[self durationFromStartTime:startTime] tags:tags isAsync:isAsync]]; completion(nil); }; diff --git a/SourceCode/Private/Core/Device/HeaderBiddingTokenReader/ScarHeaderBidding/UADSSCARWebRequestSignalSender.m b/SourceCode/Private/Core/Device/HeaderBiddingTokenReader/ScarHeaderBidding/UADSSCARWebRequestSignalSender.m index 3e287040..4720f472 100644 --- a/SourceCode/Private/Core/Device/HeaderBiddingTokenReader/ScarHeaderBidding/UADSSCARWebRequestSignalSender.m +++ b/SourceCode/Private/Core/Device/HeaderBiddingTokenReader/ScarHeaderBidding/UADSSCARWebRequestSignalSender.m @@ -63,8 +63,14 @@ - (void)sendSCARSignalsWithUUIDString:(NSString* _Nonnull)uuidString signals:(UA request.body = jsonString; dispatch_async(queue, ^{ - NSData* data = [request makeRequest]; - [self.config.metricsSender sendMetric: [UADSSCARHeaderBiddingMetric newScarSendTimeSuccess:[self durationFromStartTime:startTime] isAsync:isAsync]]; + [request makeRequest]; + if (request.error) { + NSMutableDictionary *tags = [NSMutableDictionary new]; + [tags uads_setValueIfNotNil:[NSString stringWithFormat:@"%li",(long)request.error.code] forKey:@"reason"]; + [self.config.metricsSender sendMetric: [UADSSCARHeaderBiddingMetric newScarSendTimeFailure:[self durationFromStartTime:startTime] tags:tags isAsync:isAsync]]; + } else { + [self.config.metricsSender sendMetric: [UADSSCARHeaderBiddingMetric newScarSendTimeSuccess:[self durationFromStartTime:startTime] isAsync:isAsync]]; + } }); } diff --git a/SourceCode/Private/Core/Device/HeaderBiddingTokenReader/UADSHeaderBiddingToken.h b/SourceCode/Private/Core/Device/HeaderBiddingTokenReader/UADSHeaderBiddingToken.h index 49d63ac8..96c2a691 100644 --- a/SourceCode/Private/Core/Device/HeaderBiddingTokenReader/UADSHeaderBiddingToken.h +++ b/SourceCode/Private/Core/Device/HeaderBiddingTokenReader/UADSHeaderBiddingToken.h @@ -17,6 +17,7 @@ NS_ASSUME_NONNULL_BEGIN + (instancetype)newWebToken: (NSString *)value; + (instancetype)newInvalidToken; + (instancetype)newInvalidNativeToken; ++ (instancetype)newWithDictionary: (NSDictionary *)dictionary; - (BOOL) isValid; diff --git a/SourceCode/Private/Core/Device/HeaderBiddingTokenReader/UADSHeaderBiddingToken.m b/SourceCode/Private/Core/Device/HeaderBiddingTokenReader/UADSHeaderBiddingToken.m index c94cb40e..cedf3f8d 100644 --- a/SourceCode/Private/Core/Device/HeaderBiddingTokenReader/UADSHeaderBiddingToken.m +++ b/SourceCode/Private/Core/Device/HeaderBiddingTokenReader/UADSHeaderBiddingToken.m @@ -46,6 +46,18 @@ + (instancetype)newInvalidNativeToken { return token; } ++ (instancetype)newWithDictionary: (NSDictionary *)dictionary { + UADSHeaderBiddingToken *token = [self new]; + token.value = dictionary[@"value"]; + NSNumber *type = dictionary[@"type"]; + token.type = type.intValue; + token.uuidString = dictionary[@"uuidString"]; + NSMutableDictionary *info = [NSMutableDictionary dictionaryWithDictionary:dictionary[@"info"]]; + token.info = info; + token.customPrefix = dictionary[@"customPrefix"]; + return token; +} + - (BOOL)isValid { return _value != nil && ![_value isEqual: @""]; } diff --git a/SourceCode/Private/Core/Device/HeaderBiddingTokenReader/UADSHeaderBiddingTokenReaderBuilder.h b/SourceCode/Private/Core/Device/HeaderBiddingTokenReader/UADSHeaderBiddingTokenReaderBuilder.h index 608959f4..b1fded41 100644 --- a/SourceCode/Private/Core/Device/HeaderBiddingTokenReader/UADSHeaderBiddingTokenReaderBuilder.h +++ b/SourceCode/Private/Core/Device/HeaderBiddingTokenReader/UADSHeaderBiddingTokenReaderBuilder.h @@ -5,6 +5,7 @@ #import "UADSPrivacyStorage.h" #import "UADSGameSessionIdReader.h" #import "UADSGMAScar.h" +#import "UADSSharedSessionIdReader.h" NS_ASSUME_NONNULL_BEGIN @@ -22,6 +23,7 @@ NS_ASSUME_NONNULL_BEGIN @property (nonatomic, strong) id requestFactory; @property (nonatomic, weak) UADSGMAScar* scar; @property (nonatomic) id uniqueIdGenerator; +@property (nonatomic, strong) id sharedSessionIdReader; - (id)defaultReader; diff --git a/SourceCode/Private/Core/Device/HeaderBiddingTokenReader/UADSHeaderBiddingTokenReaderBuilder.m b/SourceCode/Private/Core/Device/HeaderBiddingTokenReader/UADSHeaderBiddingTokenReaderBuilder.m index 523d5798..420d38c6 100644 --- a/SourceCode/Private/Core/Device/HeaderBiddingTokenReader/UADSHeaderBiddingTokenReaderBuilder.m +++ b/SourceCode/Private/Core/Device/HeaderBiddingTokenReader/UADSHeaderBiddingTokenReaderBuilder.m @@ -11,6 +11,7 @@ #import "UADSHBTokenReaderWithPrivacyWait.h" #import "UADSHeaderBiddingTokenReaderWithSCARSignals.h" #import "UADSUUIDStringGenerator.h" +#import "UADSHeaderBiddingTokenReaderSwiftBridge.h" static NSString *const kDefaultTokenPrefix = @"1:"; @@ -71,6 +72,7 @@ @implementation UADSHeaderBiddingTokenReaderBuilder builder.extendedReader = true; builder.currentTimeStampReader = [UADSCurrentTimestampBase new]; builder.gameSessionIdReader = self.gameSessionIdReader; + builder.sharedSessionIdReader = self.sharedSessionIdReader; _deviceInfoReader = builder.defaultReader; return _deviceInfoReader; } @@ -91,11 +93,15 @@ @implementation UADSHeaderBiddingTokenReaderBuilder - (id)tokenGenerator { if (!_tokenGenerator) { - _tokenGenerator = [UADSHeaderBiddingTokenReaderBase newWithDeviceInfoReader: self.deviceInfoReader + if (self.experiments.isSwiftTokenEnabled) { + _tokenGenerator = [UADSHeaderBiddingTokenReaderSwiftBridge new]; + } else { + _tokenGenerator = [UADSHeaderBiddingTokenReaderBase newWithDeviceInfoReader: self.deviceInfoReader andCompressor: self.bodyCompressor withTokenPrefix: self.nativeTokenPrefix withUniqueIdGenerator: self.uniqueIdGenerator ?: [UADSUUIDStringGenerator new] withConfigurationReader: self.sdkConfigReader]; + } } if (self.experiments.isPrivacyWaitEnabled) { diff --git a/SourceCode/Private/Core/Device/HeaderBiddingTokenReader/UADSHeaderBiddingTokenReaderSwiftBridge.h b/SourceCode/Private/Core/Device/HeaderBiddingTokenReader/UADSHeaderBiddingTokenReaderSwiftBridge.h new file mode 100644 index 00000000..13c40450 --- /dev/null +++ b/SourceCode/Private/Core/Device/HeaderBiddingTokenReader/UADSHeaderBiddingTokenReaderSwiftBridge.h @@ -0,0 +1,11 @@ +#import +#import "UADSHeaderBiddingTokenReaderBase.h" +#import "UADSServiceProviderContainer.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface UADSHeaderBiddingTokenReaderSwiftBridge : NSObject + +@end + +NS_ASSUME_NONNULL_END diff --git a/SourceCode/Private/Core/Device/HeaderBiddingTokenReader/UADSHeaderBiddingTokenReaderSwiftBridge.m b/SourceCode/Private/Core/Device/HeaderBiddingTokenReader/UADSHeaderBiddingTokenReaderSwiftBridge.m new file mode 100644 index 00000000..540e9ab2 --- /dev/null +++ b/SourceCode/Private/Core/Device/HeaderBiddingTokenReader/UADSHeaderBiddingTokenReaderSwiftBridge.m @@ -0,0 +1,13 @@ +#import "UADSHeaderBiddingTokenReaderSwiftBridge.h" + +@implementation UADSHeaderBiddingTokenReaderSwiftBridge + +- (void)getToken:(nonnull UADSHeaderBiddingTokenCompletion)completion { + [[UADSServiceProviderContainer.sharedInstance.serviceProvider objBridge] getToken:^(NSDictionary * _Nonnull tokenDict) { + completion([UADSHeaderBiddingToken newWithDictionary:tokenDict]); + }]; +} + +@end + + diff --git a/SourceCode/Private/Core/Device/SessionIdReader/UADSGameSessionIdReader.m b/SourceCode/Private/Core/Device/SessionIdReader/UADSGameSessionIdReader.m index 18b2ff06..8a16f47c 100644 --- a/SourceCode/Private/Core/Device/SessionIdReader/UADSGameSessionIdReader.m +++ b/SourceCode/Private/Core/Device/SessionIdReader/UADSGameSessionIdReader.m @@ -1,32 +1,14 @@ #import "UADSGameSessionIdReader.h" -#import "USRVStorageManager.h" -#import "USRVDevice.h" -#import "UADSJsonStorageKeyNames.h" +#import "UADSServiceProviderContainer.h" @interface UADSGameSessionIdReaderBase () -@property (nonatomic, strong) NSNumber *gameSessionId; @end @implementation UADSGameSessionIdReaderBase - (nonnull NSNumber *)gameSessionId { - @synchronized (self) { - [self generateSessionIdIfNeeded]; - } - return _gameSessionId; -} - -- (void)generateSessionIdIfNeeded { - if (_gameSessionId != nil) { - return; - } - - NSString *uuidString = [[[USRVDevice getUniqueEventId] stringByReplacingOccurrencesOfString:@"-" withString:@""] substringToIndex:12]; - long long hex = strtoull([uuidString UTF8String], NULL, 16); - _gameSessionId = [NSNumber numberWithLongLong:hex]; - - [[USRVStorageManager getStorage: kUnityServicesStorageTypePrivate] set: UADSJsonStorageKeyNames.webViewDataGameSessionIdKey - value: _gameSessionId]; + UADSServiceProvider *provider = UADSServiceProviderContainer.sharedInstance.serviceProvider; + return [NSNumber numberWithLongLong: [[provider.objBridge gameSessionId] longLongValue]]; } @end diff --git a/SourceCode/Private/Core/Device/SessionIdReader/UADSSharedSessionIdReader.m b/SourceCode/Private/Core/Device/SessionIdReader/UADSSharedSessionIdReader.m index 10251eff..41029409 100644 --- a/SourceCode/Private/Core/Device/SessionIdReader/UADSSharedSessionIdReader.m +++ b/SourceCode/Private/Core/Device/SessionIdReader/UADSSharedSessionIdReader.m @@ -1,10 +1,11 @@ #import "UADSSharedSessionIdReader.h" -#import "UADSSessionId.h" +#import "UADSServiceProviderContainer.h" @implementation UADSSharedSessionIdReaderBase - (nonnull NSString *)sessionId { - return UADSSessionId.shared.sessionId; + UADSServiceProvider *provider = UADSServiceProviderContainer.sharedInstance.serviceProvider; + return [provider.objBridge sessionId]; } @end diff --git a/SourceCode/Private/Core/Device/USRVMuteSwitch.m b/SourceCode/Private/Core/Device/USRVMuteSwitch.m index 47a9e565..0551884e 100644 --- a/SourceCode/Private/Core/Device/USRVMuteSwitch.m +++ b/SourceCode/Private/Core/Device/USRVMuteSwitch.m @@ -44,7 +44,7 @@ - (NSString *)getMuteDetectionFilePath { } - (bool)writeToMuteDetectionPath: (NSString *)filePath { - NSLog(@"MuteSwitch: Attempting to write bytes to file"); + USRVLogDebug(@"MuteSwitch: Attempting to write bytes to file"); @try { NSData *muteFileData = [[NSData alloc] initWithBytesNoCopy: MuteSwitchDetection_aiff @@ -53,12 +53,12 @@ - (bool)writeToMuteDetectionPath: (NSString *)filePath { [muteFileData writeToFile: filePath atomically: YES]; } @catch (NSException *exception) { - NSLog(@"MuteSwitch: File creation failed."); + USRVLogDebug(@"MuteSwitch: File creation failed."); self.fileCreated = NO; return NO; } - NSLog(@"MuteSwitch: File creation successful"); + USRVLogDebug(@"MuteSwitch: File creation successful"); self.fileCreated = YES; return YES; } @@ -76,7 +76,7 @@ - (void)playbackComplete { } - (void)sendMuteState: (bool)muteState { - NSLog(@"MuteSwitch: Device mute state detected to be %@", muteState ? @"true" : @"false"); + USRVLogDebug(@"MuteSwitch: Device mute state detected to be %@", muteState ? @"true" : @"false"); if ([USRVWebViewApp getCurrentApp]) { [[USRVWebViewApp getCurrentApp] sendEvent: @"MUTE_STATE_RECEIVED" diff --git a/SourceCode/Private/Core/Device/USRVStorageManager.h b/SourceCode/Private/Core/Device/USRVStorageManager.h index 0d56b7a3..7ec9e0a4 100644 --- a/SourceCode/Private/Core/Device/USRVStorageManager.h +++ b/SourceCode/Private/Core/Device/USRVStorageManager.h @@ -4,7 +4,7 @@ + (instancetype) sharedInstance; + (USRVStorage *)getStorage: (UnityServicesStorageType)storageType; -+ (void)removeStorage: (UnityServicesStorageType)storageType; + - (void)commit: (NSDictionary *)storageContents; @end diff --git a/SourceCode/Private/Core/Device/USRVStorageManager.m b/SourceCode/Private/Core/Device/USRVStorageManager.m index f8018b5f..ce5a0743 100644 --- a/SourceCode/Private/Core/Device/USRVStorageManager.m +++ b/SourceCode/Private/Core/Device/USRVStorageManager.m @@ -16,10 +16,6 @@ + (USRVStorage *)getStorage: (UnityServicesStorageType)storageType { return [[USRVStorageManager sharedInstance] getStorage: storageType]; } -+ (void)removeStorage: (UnityServicesStorageType)storageType { - [[USRVStorageManager sharedInstance] removeStorage: storageType]; -} - _uads_custom_singleton_imp(USRVStorageManager, ^{ return [self new]; }) @@ -97,13 +93,6 @@ - (void)initStorage: (UnityServicesStorageType)storageType { } } /* initStorage */ -- (void)removeStorage: (UnityServicesStorageType)storageType { - dispatch_sync(_syncQueue, ^{ - [_storageLocations removeObjectForKey: [NSNumber numberWithInteger: storageType]]; - [_storages removeObjectForKey: [NSNumber numberWithInteger: storageType]]; - }); -} - - (USRVStorage *)getStorage: (UnityServicesStorageType)storageType { __block USRVStorage *result = NULL; diff --git a/SourceCode/Private/Core/InitializationFlow/USRVInitializeStateConfig.m b/SourceCode/Private/Core/InitializationFlow/USRVInitializeStateConfig.m index 4e777574..15fda8de 100644 --- a/SourceCode/Private/Core/InitializationFlow/USRVInitializeStateConfig.m +++ b/SourceCode/Private/Core/InitializationFlow/USRVInitializeStateConfig.m @@ -63,6 +63,14 @@ - (instancetype)executeWithLoader { return nextState; } } else if (configError && self.retries < [self.configuration maxRetries]) { + if (configError.code == kPrivacyGameIdDisabledCode) { + id nextState = [[USRVInitializeStateError alloc] initWithConfiguration: self.configuration + erroredState: self + code: kUADSErrorStateNetworkConfigRequest + message: @"GameId disabled"]; + return nextState; + } + self.retryDelay = self.retryDelay * [self.configuration retryScalingFactor]; self.retries++; [[UADSInitializeEventsMetricSender sharedInstance] didRetryConfig]; @@ -114,26 +122,34 @@ - (void)processError: (NSError *)configError andCompletion: (void (^)(void))completion error:(void (^)(NSError * _Nonnull))error { if (configError && self.retries < [self.configuration maxRetries]) { - self.retryDelay = self.retryDelay * [self.configuration retryScalingFactor]; - self.retries++; - [[UADSInitializeEventsMetricSender sharedInstance] didRetryConfig]; - USRVInitializeStateConfig *retryState = [[USRVInitializeStateConfig alloc] initWithConfiguration: self.localConfig]; - retryState.configuration = self.localConfig; - retryState.localConfig = self.localConfig; - [retryState setRetries: self.retries]; - [retryState setRetryDelay: self.retryDelay]; - retryState.configLoader = self.configLoader; - - id nextState = [[USRVInitializeStateRetry alloc] initWithConfiguration: self.localConfig - retryState: retryState - retryDelay: self.retryDelay]; - [nextState startWithCompletion:^{ - self.retries = retryState.retries; - completion(); - } error:^(NSError * _Nonnull er) { - self.retries = retryState.retries; - error(er); - }]; + if (configError.code == kPrivacyGameIdDisabledCode) { + id nextState = [[USRVInitializeStateError alloc] initWithConfiguration: self.configuration + erroredState: self + code: kUADSErrorStateNetworkConfigRequest + message: @"GameId disabled"]; + [nextState startWithCompletion:completion error:error]; + } else { + self.retryDelay = self.retryDelay * [self.configuration retryScalingFactor]; + self.retries++; + [[UADSInitializeEventsMetricSender sharedInstance] didRetryConfig]; + USRVInitializeStateConfig *retryState = [[USRVInitializeStateConfig alloc] initWithConfiguration: self.localConfig]; + retryState.configuration = self.localConfig; + retryState.localConfig = self.localConfig; + [retryState setRetries: self.retries]; + [retryState setRetryDelay: self.retryDelay]; + retryState.configLoader = self.configLoader; + + id nextState = [[USRVInitializeStateRetry alloc] initWithConfiguration: self.localConfig + retryState: retryState + retryDelay: self.retryDelay]; + [nextState startWithCompletion:^{ + self.retries = retryState.retries; + completion(); + } error:^(NSError * _Nonnull er) { + self.retries = retryState.retries; + error(er); + }]; + } } else { USRVInitializeStateConfig *erroredState = [[USRVInitializeStateConfig alloc] initWithConfiguration: self.localConfig retries: self.retries diff --git a/SourceCode/Private/Core/Properties/USRVSdkProperties.m b/SourceCode/Private/Core/Properties/USRVSdkProperties.m index bf8512fb..d82f12a2 100644 --- a/SourceCode/Private/Core/Properties/USRVSdkProperties.m +++ b/SourceCode/Private/Core/Properties/USRVSdkProperties.m @@ -11,12 +11,12 @@ NSString *const kUnityServicesLocalStorageFilePrefix = @"UnityAdsStorage-"; NSString *const kUnityServicesWebviewBranchInfoDictionaryKey = @"UADSWebviewBranch"; NSString *const kUnityServicesWebviewConfigInfoDictionaryKey = @"UADSWebviewConfig"; -NSString *const kUnityServicesVersionName = @"4.6.1"; +NSString *const kUnityServicesVersionName = @"4.7.0"; NSString *const kUnityServicesFlavorDebug = @"debug"; NSString *const kUnityServicesFlavorRelease = @"release"; NSString *const kChinaIsoAlpha2Code = @"CN"; NSString *const kChinaIsoAlpha3Code = @"CHN"; -int const kUnityServicesVersionCode = 4610; +int const kUnityServicesVersionCode = 4700; @implementation USRVSdkProperties diff --git a/SourceCode/Private/Core/Request/Metrics/Events/UADSMetric.m b/SourceCode/Private/Core/Request/Metrics/Events/UADSMetric.m index 8c6afaa6..18de3095 100644 --- a/SourceCode/Private/Core/Request/Metrics/Events/UADSMetric.m +++ b/SourceCode/Private/Core/Request/Metrics/Events/UADSMetric.m @@ -48,7 +48,7 @@ - (BOOL)isEqual: (id)object { UADSMetric *other = (UADSMetric *)object; return [self.name isEqual: other.name] && - ((!self.value && !other.value) || [self.value isEqualToNumber: other.value]) && +// ((!self.value && !other.value) || [self.value isEqualToNumber: other.value]) && ((!self.tags && !other.tags) || [self.tags isEqualToDictionary: other.tags]); } diff --git a/SourceCode/Private/Core/SKAdNetwork/USRVApiSKAdNetwork.h b/SourceCode/Private/Core/SKAdNetwork/USRVApiSKAdNetwork.h deleted file mode 100644 index c3d09fad..00000000 --- a/SourceCode/Private/Core/SKAdNetwork/USRVApiSKAdNetwork.h +++ /dev/null @@ -1,2 +0,0 @@ -@interface USRVApiSKAdNetwork : NSObject -@end diff --git a/SourceCode/Private/Core/SKAdNetwork/USRVApiSKAdNetwork.m b/SourceCode/Private/Core/SKAdNetwork/USRVApiSKAdNetwork.m deleted file mode 100644 index 2cc0cf07..00000000 --- a/SourceCode/Private/Core/SKAdNetwork/USRVApiSKAdNetwork.m +++ /dev/null @@ -1,24 +0,0 @@ -#import "USRVApiSKAdNetwork.h" -#import "USRVWebViewCallback.h" -#import "USRVSKAdNetworkProxy.h" - -@implementation USRVApiSKAdNetwork - - -+ (void)WebViewExposed_available: (USRVWebViewCallback *)callback { - BOOL available = [[USRVSKAdNetworkProxy sharedInstance] available]; - - [callback invoke: [NSNumber numberWithBool: available], nil]; -} - -+ (void)WebViewExposed_updateConversionValue: (NSInteger)conversionValue callback: (USRVWebViewCallback *)callback { - [[USRVSKAdNetworkProxy sharedInstance] updateConversionValue: conversionValue]; - [callback invoke: nil]; -} - -+ (void)WebViewExposed_registerAppForAdNetworkAttribution: (USRVWebViewCallback *)callback { - [[USRVSKAdNetworkProxy sharedInstance] registerAppForAdNetworkAttribution]; - [callback invoke: nil]; -} - -@end diff --git a/SourceCode/Private/Core/SKAdNetwork/USRVSKAdNetworkProxy.h b/SourceCode/Private/Core/SKAdNetwork/USRVSKAdNetworkProxy.h deleted file mode 100644 index af8b79e3..00000000 --- a/SourceCode/Private/Core/SKAdNetwork/USRVSKAdNetworkProxy.h +++ /dev/null @@ -1,11 +0,0 @@ -#import -#import "USRVWebViewApp.h" - -@interface USRVSKAdNetworkProxy : NSObject - -+ (USRVSKAdNetworkProxy *)sharedInstance; -- (BOOL) available; -- (void) updateConversionValue: (NSInteger)conversionValue; -- (void) registerAppForAdNetworkAttribution; - -@end diff --git a/SourceCode/Private/Core/SKAdNetwork/USRVSKAdNetworkProxy.m b/SourceCode/Private/Core/SKAdNetwork/USRVSKAdNetworkProxy.m deleted file mode 100644 index 497444a5..00000000 --- a/SourceCode/Private/Core/SKAdNetwork/USRVSKAdNetworkProxy.m +++ /dev/null @@ -1,105 +0,0 @@ -#import "USRVSKAdNetworkProxy.h" -#import -#import -#import "USRVDevice.h" - -@interface USRVSKAdNetworkProxy () -@property (strong, nonatomic) Class skAdNetworkClass; -@end - -@implementation USRVSKAdNetworkProxy - -- (instancetype)init { - if (self = [super init]) { - if (![USRVSKAdNetworkProxy loadFramework]) { - USRVLogDebug(@"Can't load StoreKit Dll"); - } - - self.skAdNetworkClass = NSClassFromString(@"SKAdNetwork"); - } - - return self; -} - -- (BOOL)available { - return self.skAdNetworkClass != nil; -} - -- (void)updateConversionValue: (NSInteger)conversionValue { - if (!self.available) { - return; - } - - SEL requestSelector = NSSelectorFromString(@"updateConversionValue:"); - - if ([self.skAdNetworkClass respondsToSelector: requestSelector]) { - NSNumber *val = [NSNumber numberWithInteger: conversionValue]; - [self.skAdNetworkClass performSelector: requestSelector - withObject: val]; - } -} - -- (void)registerAppForAdNetworkAttribution { - if (!self.available) { - return; - } - - SEL requestSelector = NSSelectorFromString(@"registerAppForAdNetworkAttribution:"); - - if ([self.skAdNetworkClass respondsToSelector: requestSelector]) { - [self.skAdNetworkClass performSelector: requestSelector]; - } -} - -+ (USRVSKAdNetworkProxy *)sharedInstance { - static USRVSKAdNetworkProxy *instance = nil; - static dispatch_once_t onceToken; - - dispatch_once(&onceToken, ^{ - instance = [[USRVSKAdNetworkProxy alloc] init]; - }); - return instance; -} - -+ (BOOL)isFrameworkPresent { - id attClass = objc_getClass("SKAdNetwork"); - - if (attClass) { - return YES; - } - - return NO; -} - -+ (BOOL)loadFramework { - NSString *frameworkLocation; - - if (![USRVSKAdNetworkProxy isFrameworkPresent]) { - USRVLogDebug(@"StoreKit.framework is not present, trying to load it."); - - if ([USRVDevice isSimulator]) { - NSString *frameworkPath = [[NSProcessInfo processInfo] environment][@"DYLD_FALLBACK_FRAMEWORK_PATH"]; - - if (frameworkPath) { - frameworkLocation = [NSString pathWithComponents: @[frameworkPath, @"StoreKit.framework", @"SkAdNetwork"]]; - } - } else { - frameworkLocation = [NSString stringWithFormat: @"/System/Library/Frameworks/StoreKit.framework/SkAdNetwork"]; - } - - dlopen([frameworkLocation cStringUsingEncoding: NSUTF8StringEncoding], RTLD_LAZY); - - if (![USRVSKAdNetworkProxy isFrameworkPresent]) { - USRVLogError(@"StoreKit.framework still not present!"); - return NO; - } else { - USRVLogDebug(@"Succesfully loaded StoreKit.framework"); - return YES; - } - } else { - USRVLogDebug(@"StoreKit.framework already present"); - return YES; - } -} /* loadFramework */ - -@end diff --git a/SourceCode/Private/Core/UADSServiceProvider.m b/SourceCode/Private/Core/UADSServiceProvider.m index 41dcc104..e39a1ef4 100644 --- a/SourceCode/Private/Core/UADSServiceProvider.m +++ b/SourceCode/Private/Core/UADSServiceProvider.m @@ -11,6 +11,7 @@ #import "UADSWebRequestFactorySwiftAdapter.h" #import "UADSDeviceInfoReaderBuilder.h" #import "UADSSharedSessionIdReader.h" +#import "USRVJsonStorageAggregator.h" @interface UADSServiceProvider () @property (nonatomic, strong) idperformanceLogger; @@ -63,6 +64,21 @@ - (void)didReceivePrivacy: (NSDictionary *) privacy { [_privacyStorage saveResponse: [UADSInitializationResponse newFromDictionary:privacy]]; } +- (id)getValueFromJSONStorageFor: (NSString *)key { + return [USRVJsonStorageAggregator.defaultAggregator getValueForKey: key]; +} + +- (id)storageContent { + return [USRVJsonStorageAggregator.defaultAggregator getContents]; +} + +- (void)deleteKeyFromJSONStorageFor: (NSString *)key { + [[USRVStorageManager getStorage: kUnityServicesStorageTypePrivate] deleteKey:key]; +} +-(void)setValueToJSONStorage:(id)value for: (NSString *)key { + [[USRVStorageManager getStorage: kUnityServicesStorageTypePrivate] set:key value: value]; +} + - (id)hbTokenReader { @synchronized (self) { if (!_hbTokenReader) { @@ -102,6 +118,7 @@ - (UADSHeaderBiddingTokenReaderBuilder *)tokenBuilder { tokenReaderBuilder.gameSessionIdReader = self.gameSessionIdReader; tokenReaderBuilder.scar = [UADSGMAScar sharedInstance]; tokenReaderBuilder.requestFactory = self.webViewRequestFactory; + tokenReaderBuilder.sharedSessionIdReader = self.sharedSessionIdReader; return tokenReaderBuilder; } @@ -162,25 +179,27 @@ - (UADSHeaderBiddingTokenReaderBuilder *)tokenBuilder { builder.logger = self.logger; builder.currentTimeStampReader = [UADSCurrentTimestampBase new]; builder.gameSessionIdReader = self.gameSessionIdReader; + builder.sharedSessionIdReader = self.sharedSessionIdReader; return builder; } - (id)configurationLoader { - UADSCClientConfigBase *config = [UADSCClientConfigBase defaultWithExperiments: self.experiments]; + UADSCClientConfigBase *config = [UADSCClientConfigBase defaultWithExperiments: self.experiments]; - - UADSConfigurationLoaderBuilder *builder = [UADSConfigurationLoaderBuilder newWithConfig: config - andWebRequestFactory: self.webViewRequestFactory - metricSender: self.metricSender]; - - builder.privacyStorage = self.privacyStorage; - builder.logger = self.logger; - builder.configurationSaver = self.configurationSaver; - builder.currentTimeStampReader = [UADSCurrentTimestampBase new]; - builder.retryInfoReader = self.retryReader; - builder.gameSessionIdReader = self.gameSessionIdReader; - builder.metricsSender = self.metricSender; - return builder.configurationLoader; + + UADSConfigurationLoaderBuilder *builder = [UADSConfigurationLoaderBuilder newWithConfig: config + andWebRequestFactory: self.webViewRequestFactory + metricSender: self.metricSender]; + + builder.privacyStorage = self.privacyStorage; + builder.logger = self.logger; + builder.configurationSaver = self.configurationSaver; + builder.currentTimeStampReader = [UADSCurrentTimestampBase new]; + builder.retryInfoReader = self.retryReader; + builder.gameSessionIdReader = self.gameSessionIdReader; + builder.metricsSender = self.metricSender; + builder.sharedSessionIdReader = self.sharedSessionIdReader; + return builder.configurationLoader; } - (UADSConfigurationExperiments *)experiments { diff --git a/SourceCode/Private/Core/UnityAdsCoreProxy/Initialize/UADSSDKInitializerProxy.m b/SourceCode/Private/Core/UnityAdsCoreProxy/Initialize/UADSSDKInitializerProxy.m index 50643eab..f82b2449 100644 --- a/SourceCode/Private/Core/UnityAdsCoreProxy/Initialize/UADSSDKInitializerProxy.m +++ b/SourceCode/Private/Core/UnityAdsCoreProxy/Initialize/UADSSDKInitializerProxy.m @@ -1,4 +1,5 @@ #import "UADSSDKInitializerProxy.h" +#import "NSPrimitivesBox.h" static NSString *const kInitializeMethodName = @"initializeWithGameID:testMode:completion:error:"; @@ -13,8 +14,9 @@ -(void)initializeWithGameID: (NSString *)gameId completion: (UADSVoidClosure)completion error: (UADSNSErrorCompletion)error { + NSPrimitivesBox *box = [NSPrimitivesBox newWithBytes: &testMode objCType: @encode(BOOL)]; [self callInstanceMethod: kInitializeMethodName - args:@[gameId, @(testMode), completion, error]]; + args:@[gameId, box, completion, error]]; } diff --git a/SourceCode/Private/Core/UnityAdsCoreProxy/ServiceProvider/UADSServiceProviderProxy.h b/SourceCode/Private/Core/UnityAdsCoreProxy/ServiceProvider/UADSServiceProviderProxy.h index 08126b2e..9b8ef61e 100644 --- a/SourceCode/Private/Core/UnityAdsCoreProxy/ServiceProvider/UADSServiceProviderProxy.h +++ b/SourceCode/Private/Core/UnityAdsCoreProxy/ServiceProvider/UADSServiceProviderProxy.h @@ -7,6 +7,7 @@ NS_ASSUME_NONNULL_BEGIN typedef NSDictionary * _Nonnull (^UADSInfoGetter)(bool); +typedef void (^UADSTokenCompletion)(NSDictionary *_Nonnull); @protocol UADSNativeNetworkLayerProvider - (UADSCommonNetworkProxy *)nativeNetworkLayer; @@ -20,6 +21,9 @@ typedef NSDictionary * _Nonnull (^UADSInfoGetter)(bool); - (UADSSDKInitializerProxy *)sdkInitializerWithFactory: (USRVInitializeStateFactory *)factory; - (void)setDebugMode: (BOOL)isDebugMode; - (InitializationState)currentState; +- (NSNumber *)gameSessionId; +- (NSString *)sessionId; +- (void)getToken:(UADSTokenCompletion)completion; @end NS_ASSUME_NONNULL_END diff --git a/SourceCode/Private/Core/UnityAdsCoreProxy/ServiceProvider/UADSServiceProviderProxy.m b/SourceCode/Private/Core/UnityAdsCoreProxy/ServiceProvider/UADSServiceProviderProxy.m index 007325c0..eee742f1 100644 --- a/SourceCode/Private/Core/UnityAdsCoreProxy/ServiceProvider/UADSServiceProviderProxy.m +++ b/SourceCode/Private/Core/UnityAdsCoreProxy/ServiceProvider/UADSServiceProviderProxy.m @@ -11,7 +11,9 @@ static NSString *const GET_CONFIGURATION_SELECTOR = @"configDictionary"; static NSString *const SET_DEBUG_MODE_SELECTOR = @"setDebugMode:"; static NSString *const CURRENT_STATE_KVO = @"currentState"; - +static NSString *const GAME_SESSION_ID_KVO = @"gameSessionId"; +static NSString *const SESSION_ID_KVO = @"sessionId"; +static NSString *const GET_TOKEN_SELECTOR = @"getToken:"; @implementation UADSServiceProviderProxy @@ -60,5 +62,18 @@ - (InitializationState)currentState { return state.intValue; } +- (NSNumber *)gameSessionId { + NSNumber *gameSessionId = [self callInstanceMethodWithReturn:GAME_SESSION_ID_KVO args:@[]]; + return gameSessionId; +} + +- (NSString *)sessionId { + return [self callInstanceMethodWithReturn:SESSION_ID_KVO args:@[]]; +} + + +- (void)getToken:(UADSTokenCompletion)completion { + [self callInstanceMethod:GET_TOKEN_SELECTOR args:@[completion]]; +} @end diff --git a/SourceCode/Private/UnityServicesIdentifiers/UADSIdStore.h b/SourceCode/Private/UnityServicesIdentifiers/UADSIdStore.h deleted file mode 100644 index a9ab6ca4..00000000 --- a/SourceCode/Private/UnityServicesIdentifiers/UADSIdStore.h +++ /dev/null @@ -1,13 +0,0 @@ -#import - -NS_ASSUME_NONNULL_BEGIN - -@protocol UADSIdStore - -- (NSString *_Nullable)getValue; - -- (void)commitValue:(NSString *)value; - -@end - -NS_ASSUME_NONNULL_END diff --git a/SourceCode/Private/UnityServicesIdentifiers/UADSInstallationId.m b/SourceCode/Private/UnityServicesIdentifiers/UADSInstallationId.m deleted file mode 100644 index dc00abe7..00000000 --- a/SourceCode/Private/UnityServicesIdentifiers/UADSInstallationId.m +++ /dev/null @@ -1,93 +0,0 @@ -#import "UADSInstallationId.h" -#import "UADSIdStore.h" -#import "UADSUnityPlayerPrefsStore.h" -#import "UADSUserDefaultsStore.h" - -@interface UADSInstallationId () - -@property(nonatomic, strong) NSString *_Nullable savedInstallationId; -@property(nonatomic, strong) id installationIdStore; -@property(nonatomic, strong) id analyticsIdStore; -@property(nonatomic, strong) id unityAdsIdStore; - -@end - -@implementation UADSInstallationId - -+ (instancetype)shared { - static UADSInstallationId *sharedInstance = nil; - static dispatch_once_t onceToken; - - dispatch_once(&onceToken, ^{ - sharedInstance = [[UADSInstallationId alloc] init]; - }); - return sharedInstance; -} - -- (instancetype)init { - // https://github.cds.internal.unity3d.com/unity/operate-services-sample/blob/c4fad12071bb3a74aa9631c7c4cce12112fd0156/ZippedPackages/com.unity.services.core-1.1.0-pre.8/Runtime/Device/InstallationId.cs - UADSUnityPlayerPrefsStore *installationIdStore = - [[UADSUnityPlayerPrefsStore alloc] initWithKey:@"UnityInstallationId"]; - UADSUnityPlayerPrefsStore *analyticsIdStore = - [[UADSUnityPlayerPrefsStore alloc] initWithKey:@"unity.cloud_userid"]; - UADSUserDefaultsStore *unityAdsIdStore = - [[UADSUserDefaultsStore alloc] initWithKey:@"unityads-idfi"]; - self = [self initWithInstallationIdStore:installationIdStore - analyticsIdStore:analyticsIdStore - unityAdsIdStore:unityAdsIdStore]; - return self; -} - -- (instancetype)initWithInstallationIdStore:(id)installationIdStore - analyticsIdStore:(id)analyticsIdStore - unityAdsIdStore:(id)unityAdsIdStore { - self = [super init]; - - if (self) { - _installationIdStore = installationIdStore; - _analyticsIdStore = analyticsIdStore; - _unityAdsIdStore = unityAdsIdStore; - - [self readInstallationId]; - [self writeInstallationId]; - } - - return self; -} - -- (NSString *)installationId { - return self.savedInstallationId; -} - -- (void)readInstallationId { - // Check core services installation id - NSString *installationId = [self.installationIdStore getValue]; - if (installationId) { - self.savedInstallationId = installationId; - return; - } - // Check analytics - NSString *analyticsId = [self.analyticsIdStore getValue]; - if (analyticsId) { - self.savedInstallationId = analyticsId; - return; - } - // Check Unity Ads - NSString *unityAdsId = [self.unityAdsIdStore getValue]; - if (unityAdsId) { - self.savedInstallationId = unityAdsId; - return; - } - - // Generate id and write it to user defaults if none is found. - NSString *generatedInstallationId = [[NSUUID UUID] UUIDString]; - self.savedInstallationId = generatedInstallationId; -} - -- (void)writeInstallationId { - [self.installationIdStore commitValue:self.savedInstallationId]; - [self.analyticsIdStore commitValue:self.savedInstallationId]; - [self.unityAdsIdStore commitValue:self.savedInstallationId]; -} - -@end diff --git a/SourceCode/Private/UnityServicesIdentifiers/UADSPlist.h b/SourceCode/Private/UnityServicesIdentifiers/UADSPlist.h deleted file mode 100644 index 5344fa5f..00000000 --- a/SourceCode/Private/UnityServicesIdentifiers/UADSPlist.h +++ /dev/null @@ -1,22 +0,0 @@ -#import - -NS_ASSUME_NONNULL_BEGIN - -@interface UADSPlist : NSObject - -+ (BOOL)writePlistIosEleven:(NSDictionary *)mutableDictionary - toFileUrl:(NSURL *)url API_AVAILABLE(ios(11)); - -+ (BOOL)writePlistIosTen:(NSDictionary *)mutableDictionary toFileUrl:(NSURL *)url; - -+ (void)writePlist:(NSDictionary *)mutableDictionary toFileUrl:(NSURL *)url; - -+ (NSDictionary *_Nullable)dictionaryWithContentsOfURLIosEleven:(NSURL *)url API_AVAILABLE(ios(11)); - -+ (NSDictionary *_Nullable)dictionaryWithContentsOfURLIosTen:(NSURL *)url; - -+ (NSDictionary *_Nullable)dictionaryWithContentsOfURL:(NSURL *)url; - -@end - -NS_ASSUME_NONNULL_END diff --git a/SourceCode/Private/UnityServicesIdentifiers/UADSPlist.m b/SourceCode/Private/UnityServicesIdentifiers/UADSPlist.m deleted file mode 100644 index 1dde76e5..00000000 --- a/SourceCode/Private/UnityServicesIdentifiers/UADSPlist.m +++ /dev/null @@ -1,48 +0,0 @@ -#import "UADSPlist.h" - -@implementation UADSPlist - -+ (BOOL)writePlistIosEleven:(NSDictionary *)mutableDictionary - toFileUrl:(NSURL *)url API_AVAILABLE(ios(11)) { - return [mutableDictionary writeToURL:url error:nil]; -} - -+ (BOOL)writePlistIosTen:(NSDictionary *)mutableDictionary toFileUrl:(NSURL *)url { - return [mutableDictionary writeToURL:url atomically:YES]; -} - -+ (void)writePlist:(NSDictionary *)mutableDictionary toFileUrl:(NSURL *)url { - if (@available(iOS 11.0, *)) { - // We don't care if there is an error. - [UADSPlist writePlistIosEleven:mutableDictionary toFileUrl:url]; - } else { - [UADSPlist writePlistIosTen:mutableDictionary toFileUrl:url]; - } -} - -+ (NSDictionary *_Nullable)dictionaryWithContentsOfURLIosEleven:(NSURL *)url - API_AVAILABLE(ios(11)) { - NSError *plistError; - NSDictionary *plistDictionary = [NSDictionary dictionaryWithContentsOfURL:url error:&plistError]; - if (plistError) { - return nil; - } - - return plistDictionary; -} - -+ (NSDictionary *_Nullable)dictionaryWithContentsOfURLIosTen:(NSURL *)url { - NSDictionary *plistDictionary = [NSDictionary dictionaryWithContentsOfURL:url]; - - return plistDictionary; -} - -+ (NSDictionary *_Nullable)dictionaryWithContentsOfURL:(NSURL *)url { - if (@available(iOS 11.0, *)) { - return [UADSPlist dictionaryWithContentsOfURLIosEleven:url]; - } else { - return [UADSPlist dictionaryWithContentsOfURLIosTen:url]; - } -} - -@end diff --git a/SourceCode/Private/UnityServicesIdentifiers/UADSSessionId.m b/SourceCode/Private/UnityServicesIdentifiers/UADSSessionId.m deleted file mode 100644 index 17eabe46..00000000 --- a/SourceCode/Private/UnityServicesIdentifiers/UADSSessionId.m +++ /dev/null @@ -1,36 +0,0 @@ -#import "UADSSessionId.h" -#import "UADSIdStore.h" -#import "UADSUnityPlayerPrefsStore.h" -#import "UADSUserDefaultsStore.h" - -@interface UADSSessionId () - -@property(nonatomic, strong) NSString *_Nullable currentSessionId; - -@end - -@implementation UADSSessionId - -+ (instancetype)shared { - static UADSSessionId *sharedInstance = nil; - static dispatch_once_t onceToken; - - dispatch_once(&onceToken, ^{ - sharedInstance = [[UADSSessionId alloc] init]; - }); - return sharedInstance; -} - -- (instancetype)init { - self = [super init]; - if (self) { - _currentSessionId = [[NSUUID UUID] UUIDString]; - } - return self; -} - -- (NSString *)sessionId { - return self.currentSessionId; -} - -@end diff --git a/SourceCode/Private/UnityServicesIdentifiers/UADSUnityPlayerPrefsStore.h b/SourceCode/Private/UnityServicesIdentifiers/UADSUnityPlayerPrefsStore.h deleted file mode 100644 index d9a971ce..00000000 --- a/SourceCode/Private/UnityServicesIdentifiers/UADSUnityPlayerPrefsStore.h +++ /dev/null @@ -1,12 +0,0 @@ -#import -#import "UADSIdStore.h" - -NS_ASSUME_NONNULL_BEGIN - -@interface UADSUnityPlayerPrefsStore : NSObject - -- (instancetype)initWithKey:(NSString *)key; - -@end - -NS_ASSUME_NONNULL_END diff --git a/SourceCode/Private/UnityServicesIdentifiers/UADSUnityPlayerPrefsStore.m b/SourceCode/Private/UnityServicesIdentifiers/UADSUnityPlayerPrefsStore.m deleted file mode 100644 index 31fe558a..00000000 --- a/SourceCode/Private/UnityServicesIdentifiers/UADSUnityPlayerPrefsStore.m +++ /dev/null @@ -1,65 +0,0 @@ -#import "UADSUnityPlayerPrefsStore.h" -#import "UADSPlist.h" - -@interface UADSUnityPlayerPrefsStore () - -@property(nonatomic, strong) NSString *key; - -@end - -@implementation UADSUnityPlayerPrefsStore - -- (instancetype)initWithKey:(NSString *)key { - self = [super init]; - if (self) { - _key = key; - } - return self; -} - -- (NSString *_Nullable)getValue { - NSDictionary *plistDictionary = [self plistDictionary]; - id value = [plistDictionary valueForKey:self.key]; - if (value && [value isKindOfClass:[NSString class]]) { - return (NSString *)value; - } - - return nil; -} - -- (void)commitValue:(NSString *)value { - NSDictionary *plistDictionary = [self plistDictionary]; - NSURL *plistFileUrl = [self plistFileUrl]; - - if (plistFileUrl) { - NSMutableDictionary *mutablePlistDictionary = [plistDictionary mutableCopy]; - [mutablePlistDictionary setValue:value forKey:self.key]; - [UADSPlist writePlist:mutablePlistDictionary toFileUrl:plistFileUrl]; - } -} - -- (NSDictionary *)plistDictionary { - NSURL *fileUrl = [self plistFileUrl]; - NSDictionary *plistDictionary = [UADSPlist dictionaryWithContentsOfURL:fileUrl]; - if (!plistDictionary) { - return [[NSDictionary alloc] init]; - } - - return plistDictionary; -} - -- (NSURL *_Nullable)plistFileUrl { - NSURL *_Nullable url = [NSURL fileURLWithPath:[self plistFilePath]]; - return url; -} - -// The file path According to the Unity PlayerPrefs Documenation : -// https://docs.unity3d.com/ScriptReference/PlayerPrefs.html -// ~/Library/Preferences/com.ExampleCompanyName.ExampleProductName.plist -- (NSString *_Nullable)plistFilePath { - NSString *bundleIdentifier = [[NSBundle mainBundle] bundleIdentifier]; - return [[NSString stringWithFormat:@"~/Library/Preferences/%@.plist", bundleIdentifier] - stringByExpandingTildeInPath]; -} - -@end diff --git a/SourceCode/Private/UnityServicesIdentifiers/UADSUserDefaultsStore.h b/SourceCode/Private/UnityServicesIdentifiers/UADSUserDefaultsStore.h deleted file mode 100644 index 7ccde291..00000000 --- a/SourceCode/Private/UnityServicesIdentifiers/UADSUserDefaultsStore.h +++ /dev/null @@ -1,12 +0,0 @@ -#import -#import "UADSIdStore.h" - -NS_ASSUME_NONNULL_BEGIN - -@interface UADSUserDefaultsStore : NSObject - -- (instancetype)initWithKey:(NSString *)key; - -@end - -NS_ASSUME_NONNULL_END diff --git a/SourceCode/Private/UnityServicesIdentifiers/UADSUserDefaultsStore.m b/SourceCode/Private/UnityServicesIdentifiers/UADSUserDefaultsStore.m deleted file mode 100644 index 4ef0fc1b..00000000 --- a/SourceCode/Private/UnityServicesIdentifiers/UADSUserDefaultsStore.m +++ /dev/null @@ -1,29 +0,0 @@ -#import "UADSUserDefaultsStore.h" - -@interface UADSUserDefaultsStore () - -@property(nonatomic, strong) NSString *key; - -@end - -@implementation UADSUserDefaultsStore - -- (instancetype)initWithKey:(NSString *)key { - self = [super init]; - if (self) { - _key = key; - } - return self; -} - -- (NSString *_Nullable)getValue { - NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults]; - return [userDefaults stringForKey:self.key]; -} - -- (void)commitValue:(NSString *)value { - NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults]; - [userDefaults setObject:value forKey:self.key]; -} - -@end diff --git a/SourceCode/Public/UnityAds.h b/SourceCode/Public/UnityAds.h index 9717cfd5..a7aaeeb1 100644 --- a/SourceCode/Public/UnityAds.h +++ b/SourceCode/Public/UnityAds.h @@ -33,7 +33,5 @@ FOUNDATION_EXPORT const unsigned char UnityAdsModuleVersionString[]; #import #import #import -#import -#import #endif /* UnityAds_h */ diff --git a/SourceCode/Public/UnityServices.m b/SourceCode/Public/UnityServices.m index fa55be8d..ae855a9d 100644 --- a/SourceCode/Public/UnityServices.m +++ b/SourceCode/Public/UnityServices.m @@ -124,19 +124,34 @@ + (void)newStart: (NSString *)gameId [UnityServices setDebugMode: [USRVSdkProperties getDebugMode]]; [USRVClientProperties setGameId: gameId]; [USRVSdkProperties setTestMode: testMode]; - + [UADSServiceProviderContainer.sharedInstance.serviceProvider.sdkInitializer initializeWithGameID: gameId - testMode:testMode - completion:^{ - [USRVSdkProperties setInitializationState: INITIALIZED_SUCCESSFULLY]; + testMode:testMode + completion:^{ + [USRVSdkProperties setInitializationState: INITIALIZED_SUCCESSFULLY]; - } error:^(NSError * _Nonnull error) { - - [USRVSdkProperties setInitializationState: INITIALIZED_FAILED]; - }]; + } error:^(NSError * _Nonnull error) { + [self onInitError:error]; + }]; } } ++ (void)onInitError: (NSError *)error { + [UADSServiceProviderContainer.sharedInstance.serviceProvider.hbTokenReader setInitToken: nil]; + [UADSServiceProviderContainer.sharedInstance.serviceProvider.hbTokenReader deleteTokens]; + + [USRVSdkProperties setInitializationState: INITIALIZED_FAILED]; + + [[USRVInitializationNotificationCenter sharedInstance] triggerSdkInitializeDidFail: @"Unity Ads SDK failed to initialize" + code: error.code]; + + dispatch_async(dispatch_get_main_queue(), ^{ + [USRVSdkProperties notifyInitializationFailed: kUnityInitializationErrorInternalError + withErrorMessage: error.localizedDescription]; + }); + +} + + (BOOL)getDebugMode { return [USRVSdkProperties getDebugMode]; } diff --git a/SourceCode/Public/UnityServicesIdentifiers/UADSInstallationId.h b/SourceCode/Public/UnityServicesIdentifiers/UADSInstallationId.h deleted file mode 100644 index 40617a9c..00000000 --- a/SourceCode/Public/UnityServicesIdentifiers/UADSInstallationId.h +++ /dev/null @@ -1,26 +0,0 @@ -#import - -NS_ASSUME_NONNULL_BEGIN - -/** - * UADSInstallationId handles generating or retrieving an installation id across Unity services. - */ -@interface UADSInstallationId : NSObject - -/** - * Static method to return a singleton instance of UADSInstallationId. - * - * @return UADSInstallationId - */ -+ (instancetype)shared; - -/** - * Method to get the string installation id. - * - * @return NSString - */ -- (NSString *)installationId; - -@end - -NS_ASSUME_NONNULL_END diff --git a/SourceCode/Public/UnityServicesIdentifiers/UADSSessionId.h b/SourceCode/Public/UnityServicesIdentifiers/UADSSessionId.h deleted file mode 100644 index fac620d8..00000000 --- a/SourceCode/Public/UnityServicesIdentifiers/UADSSessionId.h +++ /dev/null @@ -1,27 +0,0 @@ -#import - -NS_ASSUME_NONNULL_BEGIN - -/** - * UADSSessionId handles generating a shared user sessionId to be used across Unity services. - * Use this id to tie data from the same session together. - */ -@interface UADSSessionId : NSObject - -/** - * Static method to return a singleton instance of UADSSessionId. - * - * @return UADSSessionId - */ -+ (instancetype)shared; - -/** - * Method to get the string session UUID. - * - * @return NSString - */ -- (NSString *)sessionId; - -@end - -NS_ASSUME_NONNULL_END diff --git a/SourceCode/Swift/DeviceInfo/DeviceInfoBodyReaderBuilder.swift b/SourceCode/Swift/DeviceInfo/DeviceInfoBodyReaderBuilder.swift new file mode 100644 index 00000000..1c5843f8 --- /dev/null +++ b/SourceCode/Swift/DeviceInfo/DeviceInfoBodyReaderBuilder.swift @@ -0,0 +1,83 @@ +import Foundation +import AVFoundation +import UIKit + +extension WebUserAgentReaderBase { + static var unityAdsAgent: WebUserAgentReader { + WebUserAgentReaderBase(lastKnownOSKey: Constants.UserDefaultsKeys.LastKnownSystemVersion, + userAgentValueKey: Constants.UserDefaultsKeys.LastKnownUserAgentKey) + } +} + +final class DeviceInfoBodyReaderBuilder: DeviceInfoBodyReaderProvider { + + private let baseConfig: Config + private(set) var getLegacyInfo: ClosureWithReturn? + private let deviceInfoReader: DeviceInfoReader + init(baseConfig: Config) { + self.baseConfig = baseConfig + + let deviceInfoConfig = DeviceInfoReaderBase.Config(timeReader: baseConfig.timeReader, + logger: baseConfig.logger, + userAgentReader: WebUserAgentReaderBase.unityAdsAgent, + sessionInfoProvider: baseConfig.sessionInfoStorage, + gameSettingsReader: baseConfig.gameSettingsReader, + appStartTimeProvider: baseConfig.sdkStateStorage, + telephonyInfoProvider: baseConfig.telephonyInfoProvider) + deviceInfoReader = DeviceInfoReaderBase(config: deviceInfoConfig) + } + + var deviceInfoBodyReader: DeviceInfoBodyStrategy { + self.reader(using: baseConfig) + } + + func setLegacyInfoGetter(_ closure: ClosureWithReturn?) { + getLegacyInfo = closure + } + +} + +extension DeviceInfoBodyReaderBuilder { + private func reader(using config: Config) -> DeviceInfoBodyStrategy { + let minStorageReader = JSONStorageContentNormalizer.minStorageContentReader(with: config.persistenceStorage) + let extendedStorageReader = JSONStorageContentNormalizer.extendedStorageContentReader(with: config.persistenceStorage) + + let strategyConfig = DeviceInfoBodyStrategyBase.Config(sessionInfoStorage: config.sessionInfoStorage, + trackingStatusReader: config.trackingStatusReader, + gameIdProvider: config.gameSettingsReader, + deviceInfoReader: deviceInfoReader, + privacyReader: config.sdkStateStorage, + piiDataProvider: config.piiDataProvider, + minStorageContentReader: minStorageReader, + extendedStorageContentReader: extendedStorageReader) + + var base: DeviceInfoBodyStrategy = DeviceInfoBodyStrategyBase(config: strategyConfig) + + base = DeviceInfoBodyReaderWithMetrics(original: base, + measurer: baseConfig.performanceMeasurer, + metricsSender: baseConfig.metricsSender) + let decoratorConfig = DeviceInfoObjBridgeDecorator.Config(logger: config.logger, + experimentsReader: config.sdkStateStorage, + original: base, + getLegacyInfo: getLegacyInfo) + return DeviceInfoObjBridgeDecorator(config: decoratorConfig) + } +} + +extension DeviceInfoBodyReaderBuilder { + typealias TimeInfoReader = BootTimeReader & TimeZoneReader & TimeReader + struct Config { + let sessionInfoStorage: SessionInfoReader + let trackingStatusReader: TrackingStatusReader + let gameSettingsReader: SDKGameSettingsProvider + let sdkStateStorage: PrivacyStateReader & ExperimentsReader & AppStartTimeProvider + var piiDataProvider: UIDevicePIIDataProvider = UIDevice.current + let persistenceStorage: JSONStorageBridge + let logger: Logger + let timeReader: TimeInfoReader + let telephonyInfoProvider: TelephonyInfoProvider & CountryCodeProvider + let performanceMeasurer: PerformanceMeasurer + let metricsSender: MetricSender + } + +} diff --git a/SourceCode/Swift/Initialization/InitializationStateStorage/SDKStateStorage.swift b/SourceCode/Swift/Initialization/InitializationStateStorage/SDKStateStorage.swift index 9c70b54e..581111d0 100644 --- a/SourceCode/Swift/Initialization/InitializationStateStorage/SDKStateStorage.swift +++ b/SourceCode/Swift/Initialization/InitializationStateStorage/SDKStateStorage.swift @@ -4,29 +4,39 @@ protocol InitializationStateSubject { func subscribe(_ block: @escaping ResultClosure) } +protocol AppStartTimeSaver { + func save(startTime: TimeInterval) +} final class SDKStateStorage: GenericMediator>, InitializationStateSubject, MetricsSenderBatchConditionSubject, UnityAdsConfigurationProvider, UnityAdsLocalConfigurationLoader, RetriesInfoStorage { + let retriesInfoStorage: RetriesInfoWriter & RetriesInfoReader = RetriesInfoStorageBase() typealias ConfigProvider = UnityAdsConfigurationProvider & UnityAdsLocalConfigurationLoader & UnityAdsConfigSubject & ExperimentsReader - @Atomic var currentState: SDKInitializerBase.State = .notInitialized { - didSet { - notifyStateChange() - } + @Atomic private var startTimeStamp: TimeInterval = 0 + + @Atomic private var initializeState: SDKInitializerBase.State = .notInitialized + + private let privacyStorage = PrivacyStateStorage() + + private(set) var configProvider: ConfigProvider + + init(configProvider: ConfigProvider) { + self.configProvider = configProvider } var webViewConfig: UnityAdsConfig.Network.WebView { - guard !privacyStorage.privacyResponse.webViewConfig.url.isEmpty else { + guard !privacyStorage.$privacyResponse.load().webViewConfig.url.isEmpty else { return config.network.webView } - return privacyStorage.privacyResponse.webViewConfig + return privacyStorage.$privacyResponse.load().webViewConfig } var config: UnityAdsConfig { @@ -34,13 +44,12 @@ final class SDKStateStorage: GenericMediator>, set { configProvider.config = newValue } } - private let privacyStorage = PrivacyStateStorage() - - private(set) var configProvider: ConfigProvider - let retriesInfoStorage: RetriesInfoWriter & RetriesInfoReader = RetriesInfoStorageBase() - - init(configProvider: ConfigProvider) { - self.configProvider = configProvider + var currentState: SDKInitializerBase.State { + get { _initializeState.load() } + set { + _initializeState.mutate({ $0 = newValue }) + notifyStateChange() + } } // Metric Condition subscribes to be able to release batch on failure or success. @@ -67,6 +76,8 @@ final class SDKStateStorage: GenericMediator>, } extension SDKStateStorage: PrivacyStateReader, PrivacyResponseSaver { + var shouldSendNonBehavioural: Bool { privacyStorage.shouldSendNonBehavioural } + var privacyState: PrivacyState { privacyStorage.privacyState } func save(response: PrivacyResponse) { @@ -88,19 +99,6 @@ extension SDKStateStorage: ExperimentsReader, SessionTokenReader { } } -final class PrivacyStateStorage: GenericMediator>, - PrivacyStateReader, - PrivacyResponseSaver { - @Atomic var privacyResponse: PrivacyResponse = .empty - - var privacyState: PrivacyState { privacyResponse.state } - - func save(response: PrivacyResponse) { - privacyResponse = response - notifyObservers(with: .success(privacyResponse)) - } -} - extension SDKStateStorage { func retryInfo() -> [String: String] { retriesInfoStorage.retryInfo() @@ -110,3 +108,14 @@ extension SDKStateStorage { retriesInfoStorage.set(retried: retried, task: task) } } + +extension SDKStateStorage: AppStartTimeSaver, AppStartTimeProvider { + + var appStartTime: TimeInterval { + _startTimeStamp.load() + } + + func save(startTime: TimeInterval) { + _startTimeStamp.mutate({ $0 = startTime }) + } +} diff --git a/SourceCode/Swift/Initialization/Legacy/InitializationTaskFactoryBase.swift b/SourceCode/Swift/Initialization/Legacy/InitializationTaskFactoryBase.swift index e84adc40..f7dc6b18 100644 --- a/SourceCode/Swift/Initialization/Legacy/InitializationTaskFactoryBase.swift +++ b/SourceCode/Swift/Initialization/Legacy/InitializationTaskFactoryBase.swift @@ -3,25 +3,37 @@ import Foundation final class InitializationTaskFactoryBase: TaskFactory { typealias SettingsProvider = LoggerSettingsReader private let downloaderBuilder: WebViewDownloadBuilder - private let networkSenderProvider: MetricsSenderProvider & UnityAdsNetworkSenderProvider + private let metricSenderProvider: MetricsSenderProvider private let objcFactory: USRVInitializeStateFactory private let performanceMeasurer: PerformanceMeasurer private let sdkStateStorage: SDKStateStorage private let settingsProvider: SettingsProvider private var networkConfig: UnityAdsConfig.Network { sdkStateStorage.networkConfig } + private let keyValueStorage: KeyValueStorage + private let cleanupKeys: [String] + private let deviceInfoReader: DeviceInfoBodyStrategy + private let networkSenderProvider: UnityAdsNetworkSenderProvider init(downloaderBuilder: WebViewDownloadBuilder, - metricSenderProvider: MetricsSenderProvider & UnityAdsNetworkSenderProvider, + metricSenderProvider: MetricsSenderProvider, + networkSenderProvider: UnityAdsNetworkSenderProvider, sdkStateStorage: SDKStateStorage, performanceMeasurer: PerformanceMeasurer, stateFactoryObjc: USRVInitializeStateFactory = .init(), - settingsProvider: SettingsProvider) { + settingsProvider: SettingsProvider, + keyValueStorage: KeyValueStorage, + cleanupKeys: [String], + deviceInfoReader: DeviceInfoBodyStrategy) { self.downloaderBuilder = downloaderBuilder self.objcFactory = stateFactoryObjc - self.networkSenderProvider = metricSenderProvider + self.metricSenderProvider = metricSenderProvider + self.networkSenderProvider = networkSenderProvider self.performanceMeasurer = performanceMeasurer self.sdkStateStorage = sdkStateStorage self.settingsProvider = settingsProvider + self.keyValueStorage = keyValueStorage + self.cleanupKeys = cleanupKeys + self.deviceInfoReader = deviceInfoReader } func task(of type: InitTaskState) -> Task { @@ -51,7 +63,7 @@ extension InitializationTaskFactoryBase { extension InitializationTaskFactoryBase { var metricSender: MetricSender { - networkSenderProvider.metricsSender + metricSenderProvider.metricsSender } var requestRetryConfig: RetriableOperationConfig { @@ -76,7 +88,13 @@ extension InitializationTaskFactoryBase { case .reset: let legacy = taskForObjcType(type) return useNewTasksFlow ? PreviousSessionCleanupTask(loggerSettingsReader: settingsProvider, - legacyTask: legacy) : legacy + legacyTask: legacy, + storage: keyValueStorage, + cleanupKeys: cleanupKeys) : legacy + case .initModules: + let legacy = taskForObjcType(type) + return useNewTasksFlow ? InitModulesTask(legacyTask: legacy, + deviceInfoReader: deviceInfoReader) : legacy default: return taskForObjcType(type) } diff --git a/SourceCode/Swift/Initialization/Legacy/InitializationTaskFactoryStrategy.swift b/SourceCode/Swift/Initialization/Legacy/InitializationTaskFactoryStrategy.swift index 56b5888c..32172675 100644 --- a/SourceCode/Swift/Initialization/Legacy/InitializationTaskFactoryStrategy.swift +++ b/SourceCode/Swift/Initialization/Legacy/InitializationTaskFactoryStrategy.swift @@ -5,18 +5,26 @@ final class InitializationTaskFactoryStrategy: TaskFactory { private let factoryBase: InitializationTaskFactoryBase init(downloaderBuilder: WebViewDownloadBuilder, - metricSenderProvider: MetricsSenderProvider & UnityAdsNetworkSenderProvider, + metricSenderProvider: MetricsSenderProvider, + networkSenderProvider: UnityAdsNetworkSenderProvider, sdkStateStorage: SDKStateStorage, performanceMeasurer: PerformanceMeasurer, stateFactoryObjc: USRVInitializeStateFactory = .init(), - settingsProvider: SettingsProvider) { + settingsProvider: SettingsProvider, + keyValueStorage: KeyValueStorage, + cleanupKeys: [String], + deviceInfoReader: DeviceInfoBodyStrategy) { self.factoryBase = .init(downloaderBuilder: downloaderBuilder, metricSenderProvider: metricSenderProvider, + networkSenderProvider: networkSenderProvider, sdkStateStorage: sdkStateStorage, performanceMeasurer: performanceMeasurer, stateFactoryObjc: stateFactoryObjc, - settingsProvider: settingsProvider) + settingsProvider: settingsProvider, + keyValueStorage: keyValueStorage, + cleanupKeys: cleanupKeys, + deviceInfoReader: deviceInfoReader) } func task(of type: InitTaskCategory) -> Task { diff --git a/SourceCode/Swift/Initialization/SDKInitializerBase.swift b/SourceCode/Swift/Initialization/SDKInitializerBase.swift index e38f474d..609a9531 100644 --- a/SourceCode/Swift/Initialization/SDKInitializerBase.swift +++ b/SourceCode/Swift/Initialization/SDKInitializerBase.swift @@ -17,8 +17,8 @@ final class SDKInitializerBase: SDKInitializer { } private var initConfig: SDKInitializerConfig { - get { settingsStorage.currentInitConfig } - set { settingsStorage.currentInitConfig = newValue } + get { settingsStorage.$currentInitConfig.load() } + set { settingsStorage.$currentInitConfig.mutate({ $0 = newValue }) } } init(task: Task, @@ -37,6 +37,12 @@ final class SDKInitializerBase: SDKInitializer { private extension SDKInitializerBase { func startInitialization(with config: SDKInitializerConfig, completion: @escaping ResultClosure) { completions = completions.appended(completion) + + if !isGameIdValid(config) { + notifySavedCompletionsAndClean(with: .failure(InvalidGameId())) + return + } + switch state { case .notInitialized: changeStatusAndStartTheTask(config: config) @@ -47,7 +53,6 @@ private extension SDKInitializerBase { case .initialized: notifySavedCompletionsAndClean(with: VoidSuccess) } - } func changeStatusAndStartTheTask(config: SDKInitializerConfig) { @@ -55,6 +60,10 @@ private extension SDKInitializerBase { startTask() } + func isGameIdValid(_ config: SDKInitializerConfig) -> Bool { + return Int(config.gameID) != nil + } + func setInProgress(for config: SDKInitializerConfig) { initConfig = config state = .inProcess @@ -85,9 +94,11 @@ private extension SDKInitializerBase { public struct SDKInitializerConfig { public let gameID: String - - public init(gameID: String) { + public let isTestModeEnabled: Bool + public init(gameID: String, + isTestModeEnabled: Bool) { self.gameID = gameID + self.isTestModeEnabled = isTestModeEnabled } } @@ -111,3 +122,9 @@ extension SDKInitializerBase { case initialized } } + +struct InvalidGameId: LocalizedError { + var errorDescription: String? { + return "GameId should be a number" + } +} diff --git a/SourceCode/Swift/Initialization/SharedSessionId/SharedSessionIdReader.swift b/SourceCode/Swift/Initialization/SharedSessionId/SharedSessionIdReader.swift deleted file mode 100644 index a92135e2..00000000 --- a/SourceCode/Swift/Initialization/SharedSessionId/SharedSessionIdReader.swift +++ /dev/null @@ -1,11 +0,0 @@ -import Foundation - -protocol SharedSessionIdReader { - var sessionId: String { get } -} - -class SharedSessionIdReaderBase: SharedSessionIdReader { - var sessionId: String { - UADSSessionId.shared().sessionId() - } -} diff --git a/SourceCode/Swift/Initialization/Tasks/InitModulesTask.swift b/SourceCode/Swift/Initialization/Tasks/InitModulesTask.swift new file mode 100644 index 00000000..99e932ac --- /dev/null +++ b/SourceCode/Swift/Initialization/Tasks/InitModulesTask.swift @@ -0,0 +1,25 @@ +import Foundation + +final class InitModulesTask: PerformanceMeasurableTask { + var startEventName: String? + var resultMetrics: ResultMetrics.Type { Constants.Metrics.Task.InitModules.self } + + private let legacyTask: PerformanceMeasurableTask + private let deviceInfoReader: DeviceInfoBodyStrategy + + init(legacyTask: PerformanceMeasurableTask, + deviceInfoReader: DeviceInfoBodyStrategy) { + self.legacyTask = legacyTask + self.deviceInfoReader = deviceInfoReader + } + + func start(completion: @escaping ResultClosure) { + initDeviceStaticInfo() + legacyTask.start(completion: completion) + } + + private func initDeviceStaticInfo() { + deviceInfoReader.initializeStaticInfo() + } + +} diff --git a/SourceCode/Swift/Initialization/Tasks/PreviousSessionCleanupTask.swift b/SourceCode/Swift/Initialization/Tasks/PreviousSessionCleanupTask.swift index e4e13a4d..248a4e1a 100644 --- a/SourceCode/Swift/Initialization/Tasks/PreviousSessionCleanupTask.swift +++ b/SourceCode/Swift/Initialization/Tasks/PreviousSessionCleanupTask.swift @@ -6,16 +6,23 @@ final class PreviousSessionCleanupTask: PerformanceMeasurableTask { private let loggerSettingsReader: LoggerSettingsReader private let fileManager: FileManager private let legacyTask: PerformanceMeasurableTask + private let storage: KeyValueStorage + private let cleanupKeys: [String] init(loggerSettingsReader: LoggerSettingsReader, fileManager: FileManager = .default, - legacyTask: PerformanceMeasurableTask) { + legacyTask: PerformanceMeasurableTask, + storage: KeyValueStorage, + cleanupKeys: [String]) { self.loggerSettingsReader = loggerSettingsReader self.fileManager = fileManager self.legacyTask = legacyTask + self.storage = storage + self.cleanupKeys = cleanupKeys } func start(completion: @escaping ResultClosure) { try? fileManager.deleteFile(at: loggerSettingsReader.logsFileURL) + cleanupKeys.forEach { storage.delete(forKey: $0) } legacyTask.start(completion: completion) } diff --git a/SourceCode/Swift/Initialization/Tasks/PrivacyFetchTask.swift b/SourceCode/Swift/Initialization/Tasks/PrivacyFetchTask.swift index ef39d119..f7fe5303 100644 --- a/SourceCode/Swift/Initialization/Tasks/PrivacyFetchTask.swift +++ b/SourceCode/Swift/Initialization/Tasks/PrivacyFetchTask.swift @@ -9,6 +9,7 @@ final class PrivacyFetchTask: PerformanceMeasurableTask { private let asyncReader: PrivacyAsyncReader private let storage: PrivacyCRUD + private let codesToFail = [PrivacyError.gameIdDisabled.rawValue] init(asyncReader: PrivacyAsyncReader, storage: PrivacyCRUD) { self.asyncReader = asyncReader self.storage = storage @@ -20,12 +21,32 @@ final class PrivacyFetchTask: PerformanceMeasurableTask { return } - asyncReader.getPrivacyData { [storage] result in + asyncReader.getPrivacyData { [storage] (result: UResult) in result.do(storage.save) .map({ _ in }) - .recover({ _ in }) + .flatMapError(self.failErrorIfNeed) .sink(completion) } } + private func failErrorIfNeed(_ error: Error) -> UResult { + guard let error = error as? NetworkResponseError, + let errorCode = error.errorCode, + codesToFail.contains(errorCode), + let privacyErrorCode = PrivacyError(rawValue: errorCode) else { + return VoidSuccess + } + return .failure(privacyErrorCode) + } +} + +enum PrivacyError: Int, LocalizedError { + case gameIdDisabled = 423 + + var errorDescription: String? { + switch self { + case .gameIdDisabled: + return "GameId disabled" + } + } } diff --git a/SourceCode/Swift/Initialization/Tasks/StartInitTask.swift b/SourceCode/Swift/Initialization/Tasks/StartInitTask.swift index 1852abc4..a9d05c42 100644 --- a/SourceCode/Swift/Initialization/Tasks/StartInitTask.swift +++ b/SourceCode/Swift/Initialization/Tasks/StartInitTask.swift @@ -4,11 +4,53 @@ final class StartInitTask: PerformanceMeasurableTask { var startEventName: String? = Constants.Metrics.Task.Initializer.Started var resultMetrics: ResultMetrics.Type { Constants.Metrics.Task.Initializer.self } private let runner: SyncTaskRunner - init(factory: F, sequence: [F.Element]) { + private let timeReader: TimeReader + private let appStartTimeSaver: AppStartTimeSaver + private let logger: Logger + private let settingProvider: SDKGameSettingsProvider + private let sessionInfoReader: SessionInfoReader + + init(factory: F, + sequence: [F.Element], + timeReader: TimeReader, + appStartTimeSaver: AppStartTimeSaver, + logger: Logger, + settingProvider: SDKGameSettingsProvider, + sessionInfoReader: SessionInfoReader) { self.runner = .init(factory: factory, sequence: sequence) + self.timeReader = timeReader + self.appStartTimeSaver = appStartTimeSaver + self.logger = logger + self.settingProvider = settingProvider + self.sessionInfoReader = sessionInfoReader } func start(completion: @escaping ResultClosure) { + appStartTimeSaver.save(startTime: timeReader.currentTimestamp(in: .milliseconds)) + logger.info(message: initLogMessage) runner.start(completion: completion) } } + +extension StartInitTask { + + var initLogMessage: String { + "Initializing Unity Ads \(versionName) \(versionNumber) with game id \(settingProvider.gameID) in \(mode) mode, session \(sessionId)" + } + + var versionName: String { + Version().versionName + } + + var versionNumber: Int { + Version().versionNumber + } + + var mode: String { + settingProvider.isTestModeEnabled ? "test" : "production" + } + + var sessionId: String { + sessionInfoReader.sessionID + } +} diff --git a/SourceCode/Swift/Network/UnityAdsEventsNetworkServicesFactory.swift b/SourceCode/Swift/Network/UnityAdsEventsNetworkServicesFactory.swift new file mode 100644 index 00000000..34e7f705 --- /dev/null +++ b/SourceCode/Swift/Network/UnityAdsEventsNetworkServicesFactory.swift @@ -0,0 +1,77 @@ +import Foundation + +protocol MetricsSenderProvider { + var metricsSender: MetricSender { get } +} +protocol DiagnosticMetricsSenderProvider { + var diagnosticMetricSender: MetricSender { get } +} + +final class UnityAdsEventsNetworkServicesFactory: MetricsSenderProvider, DiagnosticMetricsSenderProvider { + + let metricsSender: MetricSender + let diagnosticMetricSender: MetricSender + let config: Config + let urlSession: URLSession + init(config: Config) { + self.config = config + urlSession = URLSession(configuration: config.settingsReader.metricSessionConfiguration) + let networkBuilder = CoreNetworkServicesBuilder(session: urlSession, + configurationProvider: config.configProvider, + metricsCollector: nil, + metricsSender: nil) + + let metricsAdapter = MetricsAdapter(deviceInfoReader: config.uiDeviceInfoProvider, + telephonyProvider: config.teleponyProvider, + metricsMetaDataReader: config.metricsDataReader, + allowedResourceTypes: config.settingsReader.metricsResourceTypes, + retriesInfoReader: config.retriesReader, + gameSettingsReader: config.settingsReader, + sessionId: config.sessionInfoReader.sessionID) + let factoryConfig = UnityAdsEventsRequestFactory.Config(configurationProvider: config.configProvider, + metricsAdapter: metricsAdapter) + let networkSenderBuilder = networkBuilder.createNetworkSenderBuilder(with: config.codes) + + let factory = UnityAdsEventsRequestFactory(config: factoryConfig) + let metricsSenderBuilder = MetricsSenderBuilder(metricsConfigReader: config.configProvider, + unityAdsRequestFactory: factory, + networkBuilder: networkSenderBuilder, + conditionSubject: config.configProvider, + logger: config.logger, + metricAdapter: metricsAdapter) + + metricsSender = metricsSenderBuilder.metricsSender + diagnosticMetricSender = metricsSenderBuilder.networkDiagnosticMetricsSender + } +} + +extension UnityAdsEventsNetworkServicesFactory { + var unityAdsMetricsNativeNetwork: UnityAdsWebViewNetwork { + .init(networkSender: metricsNetworkServicesBuilder.sender(withAllowedCodes: config.codes, retryConfig: nil), + networkDownloader: metricsNetworkServicesBuilder.downloader(withAllowedCodes: [], + baseDirectory: config.filePaths.baseDir, + retryConfig: nil)) + } + + private var metricsNetworkServicesBuilder: CoreNetworkServicesBuilder { + .init(session: urlSession, + configurationProvider: config.configProvider, + metricsCollector: nil, + metricsSender: nil) + } +} + +extension UnityAdsEventsNetworkServicesFactory { + struct Config { + let configProvider: UnityAdsConfigurationProvider & MetricsSenderBatchConditionSubject + let uiDeviceInfoProvider: UIDeviceInfoProvider = UIDevice.current + let metricsDataReader: ExperimentsReader & SessionTokenReader + let retriesReader: RetriesInfoReader + let logger: Logger + let settingsReader: NetworkSettingsProvider & SDKGameSettingsProvider + var sessionInfoReader: SessionInfoReader + var codes: [Int] = Array((200...299)) + var filePaths: FilePaths = FilePaths() + var teleponyProvider: TelephonyNetworkStatusProvider = TelephonyNetworkStatusProvider() + } +} diff --git a/SourceCode/Swift/Network/UnityAdsNetworkServicesFactory.swift b/SourceCode/Swift/Network/UnityAdsNetworkServicesFactory.swift index ae942601..d315555a 100644 --- a/SourceCode/Swift/Network/UnityAdsNetworkServicesFactory.swift +++ b/SourceCode/Swift/Network/UnityAdsNetworkServicesFactory.swift @@ -1,9 +1,5 @@ import Foundation -protocol MetricsSenderProvider { - var metricsSender: MetricSender { get } -} - protocol UnityAdsNetworkSenderProvider { func networkSender(includeRetryLogic: Bool, collectCompressionMetrics: Bool) -> UnityAdsNetworkSender } @@ -19,7 +15,7 @@ protocol NetworkSettingsProvider { Factory that creates network services for swift layer as well as objc layer. Services can be used with metrics or without them. */ -final class UnityAdsNetworkServicesFactory: MetricsSenderProvider { +final class UnityAdsNetworkServicesFactory { typealias ConfigProvider = UnityAdsConfigurationProvider & MetricsSenderBatchConditionSubject & ExperimentsReader & @@ -27,48 +23,37 @@ final class UnityAdsNetworkServicesFactory: MetricsSenderProvider { RetriesInfoStorage typealias SettingsProvider = LoggerSettingsReader & NetworkSettingsProvider & - SDKGameIdProvider + SDKGameSettingsProvider private let configurationProvider: ConfigProvider private let metricsCollector: URLSessionTaskMetricCollector = URLSessionTaskMetricCollectorBase() - private var metricSession: URLSession private var mainSession: URLSession private let allowedCodes: [Int] private let filePaths = FilePaths() - private let metricsAdapter: MetricsAdapter private let performanceMeasurer: PerformanceMeasurer - let metricsSender: MetricSender - let diagnosticMetricsSender: MetricSender - let deviceInfoReader: DeviceInfoReader & LegacyDeviceInfoReader + let metricSenderProvider: MetricsSenderProvider & DiagnosticMetricsSenderProvider + let deviceInfoReaderProvider: DeviceInfoBodyReaderProvider private let configEndpointProvider: ConfigEndpointProvider - + private let telephonyProvider: TelephonyNetworkStatusProvider init(settingsProvider: SettingsProvider, configurationProvider: ConfigProvider, - deviceInfoReader: DeviceInfoReader & LegacyDeviceInfoReader, + deviceInfoReaderProvider: DeviceInfoBodyReaderProvider, performanceMeasurer: PerformanceMeasurer, - logger: Logger) { + logger: Logger, + metricSenderProvider: MetricsSenderProvider & DiagnosticMetricsSenderProvider, + telephonyProvider: TelephonyNetworkStatusProvider = TelephonyNetworkStatusProvider()) { self.configurationProvider = configurationProvider - self.deviceInfoReader = deviceInfoReader + self.deviceInfoReaderProvider = deviceInfoReaderProvider self.allowedCodes = settingsProvider.responseSuccessCodes + self.telephonyProvider = telephonyProvider mainSession = URLSession(configuration: settingsProvider.mainSessionConfiguration, delegate: metricsCollector, delegateQueue: nil) - metricSession = URLSession(configuration: settingsProvider.metricSessionConfiguration) - self.metricsAdapter = MetricsAdapter(deviceInfoReader: deviceInfoReader, - metricsMetaDataReader: self.configurationProvider, - allowedResourceTypes: settingsProvider.metricsResourceTypes, - retriesInfoReader: configurationProvider, - gameId: settingsProvider.gameID, - sessionId: SharedSessionIdReaderBase().sessionId) - self.configEndpointProvider = EndpointProviderBase(worldZoneReader: WorldZoneReaderBase(countryCodeProvider: deviceInfoReader)) - let metricSenderBuilder = createMetricsSenderBuilder(session: metricSession, - configProvider: configurationProvider, - metricsAdapter: self.metricsAdapter, - deviceInfoReader: deviceInfoReader, - logger: logger) - metricsSender = metricSenderBuilder.metricsSender - diagnosticMetricsSender = metricSenderBuilder.networkDiagnosticMetricsSender + let deviceInfoReader = deviceInfoReaderProvider.deviceInfoBodyReader + self.configEndpointProvider = EndpointProviderBase(worldZoneReader: WorldZoneReaderBase(countryCodeProvider: telephonyProvider)) + + self.metricSenderProvider = metricSenderProvider self.performanceMeasurer = performanceMeasurer } } @@ -113,31 +98,23 @@ extension UnityAdsNetworkServicesFactory { networkDownloader: coreNetworkServicesBuilder.downloader(withAllowedCodes: [], baseDirectory: filePaths.baseDir, retryConfig: nil)) } - var unityAdsMetricsNativeNetwork: UnityAdsWebViewNetwork { - .init(networkSender: metricsNetworkServicesBuilder.sender(withAllowedCodes: allowedCodes, retryConfig: nil), - networkDownloader: metricsNetworkServicesBuilder.downloader(withAllowedCodes: [], baseDirectory: filePaths.baseDir, retryConfig: nil)) - } } extension UnityAdsNetworkServicesFactory { private func unityAdsRequestFactory(collectCompressionMetrics: Bool) -> UnityAdsRequestFactory { - .init(configurationProvider: configurationProvider, - adapter: metricsAdapter, - deviceInfoReader: deviceInfoReader, - bodyCompressor: bodyCompressor(includeMetrics: collectCompressionMetrics)) + .init(config: .init(configurationProvider: configurationProvider, + deviceInfoReaderProvider: deviceInfoReaderProvider, + bodyCompressor: bodyCompressor(includeMetrics: collectCompressionMetrics), + countryCodeProvider: telephonyProvider)) } private func bodyCompressor(includeMetrics: Bool) -> DataCompressor { let original = GZipCompressor() return includeMetrics ? DataCompressorWithMetrics(original: original, measurer: performanceMeasurer, - metricsSender: metricsSender) : original - - } + metricsSender: metricSenderProvider.metricsSender) : original - private var metricsNetworkBuilder: NetworkSenderBuilder { - metricsNetworkServicesBuilder.createNetworkSenderBuilder(with: allowedCodes) } private var unityAdsDownloader: UnityAdsNetworkDownloader { @@ -152,67 +129,6 @@ extension UnityAdsNetworkServicesFactory { .init(session: mainSession, configurationProvider: configurationProvider, metricsCollector: metricsCollector, - metricsSender: diagnosticMetricsSender) + metricsSender: metricSenderProvider.diagnosticMetricSender) } - - private var metricsNetworkServicesBuilder: CoreNetworkServicesBuilder { - .init(session: metricSession, - configurationProvider: configurationProvider, - metricsCollector: nil, - metricsSender: nil) - } - -} - -private func createMetricsSender(session: URLSession, - configProvider: UnityAdsConfigurationProvider & MetricsSenderBatchConditionSubject, - metricsAdapter: MetricsAdapter, - deviceInfoReader: DeviceInfoReader & LegacyDeviceInfoReader, - logger: Logger, - codes: [Int] = Array((200...299))) -> MetricSender { - - let networkBuilder = CoreNetworkServicesBuilder(session: session, - configurationProvider: configProvider, - metricsCollector: nil, - metricsSender: nil) - - let unityAdsRequestFactory = UnityAdsRequestFactory(configurationProvider: configProvider, - adapter: metricsAdapter, - deviceInfoReader: deviceInfoReader, - bodyCompressor: GZipCompressor()) - let networkSenderBuilder = networkBuilder.createNetworkSenderBuilder(with: codes) - - let metricsSenderBuilder = MetricsSenderBuilder(metricsConfigReader: configProvider, - unityAdsRequestFactory: unityAdsRequestFactory, - networkBuilder: networkSenderBuilder, - conditionSubject: configProvider, - logger: logger, - metricAdapter: metricsAdapter) - return metricsSenderBuilder.networkDiagnosticMetricsSender -} - -private func createMetricsSenderBuilder(session: URLSession, - configProvider: UnityAdsConfigurationProvider & MetricsSenderBatchConditionSubject, - metricsAdapter: MetricsAdapter, - deviceInfoReader: DeviceInfoReader & LegacyDeviceInfoReader, - logger: Logger, - codes: [Int] = Array((200...299))) -> MetricsSenderBuilder { - - let networkBuilder = CoreNetworkServicesBuilder(session: session, - configurationProvider: configProvider, - metricsCollector: nil, - metricsSender: nil) - - let unityAdsRequestFactory = UnityAdsRequestFactory(configurationProvider: configProvider, - adapter: metricsAdapter, - deviceInfoReader: deviceInfoReader, - bodyCompressor: GZipCompressor()) - let networkSenderBuilder = networkBuilder.createNetworkSenderBuilder(with: codes) - - return MetricsSenderBuilder(metricsConfigReader: configProvider, - unityAdsRequestFactory: unityAdsRequestFactory, - networkBuilder: networkSenderBuilder, - conditionSubject: configProvider, - logger: logger, - metricAdapter: metricsAdapter) } diff --git a/SourceCode/Swift/ObjBridges/DeviceInfo/DeviceInfoObjBridge.swift b/SourceCode/Swift/ObjBridges/DeviceInfo/DeviceInfoObjBridge.swift new file mode 100644 index 00000000..c0e8e919 --- /dev/null +++ b/SourceCode/Swift/ObjBridges/DeviceInfo/DeviceInfoObjBridge.swift @@ -0,0 +1,42 @@ +import Foundation + +final class DeviceInfoObjBridgeDecorator: DeviceInfoBodyStrategy { + func initializeStaticInfo() { + guard shouldUseNewImplementation else { return } + config.original.initializeStaticInfo() + } + + private let config: Config + init(config: Config) { + self.config = config + } + + func getDeviceInfoBody(of type: DeviceInfoType) -> [String: Any] { + guard shouldUseNewImplementation else { + return getLegacyDeviceInfo(of: type) + + } + return config.original.getDeviceInfoBody(of: type) + } + + private var shouldUseNewImplementation: Bool { + config.experimentsReader.experiments?.isSwiftDeviceInfoEnabled.value ?? false + } + + private func getLegacyDeviceInfo(of type: DeviceInfoType) -> [String: Any] { + guard let getLegacyInfo = config.getLegacyInfo else { + config.logger.fatal(message: "Legacy Device Info Closure is Not set") + return [:] + } + return getLegacyInfo(type == .extended) + } +} + +extension DeviceInfoObjBridgeDecorator { + struct Config { + let logger: Logger + let experimentsReader: ExperimentsReader + let original: DeviceInfoBodyStrategy + let getLegacyInfo: ClosureWithReturn? + } +} diff --git a/SourceCode/Swift/ObjBridges/Initialization/SDKInitializerOBJBridge.swift b/SourceCode/Swift/ObjBridges/Initialization/SDKInitializerOBJBridge.swift index fa44c470..54608878 100644 --- a/SourceCode/Swift/ObjBridges/Initialization/SDKInitializerOBJBridge.swift +++ b/SourceCode/Swift/ObjBridges/Initialization/SDKInitializerOBJBridge.swift @@ -12,7 +12,7 @@ final class SDKInitializerOBJBridge: NSObject { testMode: Bool, completion: @escaping VoidClosure, error: @escaping Closure) { - let config = SDKInitializerConfig(gameID: gameID) + let config = SDKInitializerConfig(gameID: gameID, isTestModeEnabled: testMode) sdkInitializer.initialize(with: config) { result in result.do(completion) .onFailure(error) diff --git a/SourceCode/Swift/ObjBridges/JSONStorage/JSONStorageBridge.swift b/SourceCode/Swift/ObjBridges/JSONStorage/JSONStorageBridge.swift new file mode 100644 index 00000000..b2f95cc2 --- /dev/null +++ b/SourceCode/Swift/ObjBridges/JSONStorage/JSONStorageBridge.swift @@ -0,0 +1,28 @@ +import Foundation + +final class JSONStorageBridge: KeyValueStorage, StorageContentReader { + + var jsonStorageReaderClosure: ClosureWithReturn? + + var jsonStorageSaverClosure: Closure<(String, Any)>? + + var jsonStorageDeleteClosure: Closure<(String)>? + + var jsonStorageReaderContentClosure: VoidClosureWithReturn<[String: Any]>? + + func getValue(for key: String) -> T? { + jsonStorageReaderClosure?(key) as? T + } + + func saveValue(value: T, forKey key: String) { + jsonStorageSaverClosure?((key, value)) + } + + func delete(forKey key: String) { + jsonStorageDeleteClosure?(key) + } + + var allContent: [String: Any] { + jsonStorageReaderContentClosure?() ?? [:] + } + } diff --git a/SourceCode/Swift/ObjBridges/JSONStorage/JSONStorageContentNormalizer.swift b/SourceCode/Swift/ObjBridges/JSONStorage/JSONStorageContentNormalizer.swift new file mode 100644 index 00000000..43ab41cf --- /dev/null +++ b/SourceCode/Swift/ObjBridges/JSONStorage/JSONStorageContentNormalizer.swift @@ -0,0 +1,103 @@ +import Foundation + +final class JSONStorageContentNormalizer: StorageContentReader { + private let config: Config + init(config: Config) { + self.config = config + } + + var allContent: [String: Any] { + var mergedDictionary = [String: Any]() + + config.original.allContent.forEach { pair in + processRootPair(&mergedDictionary, pair: pair) + } + return mergedDictionary + } + + func processRootPair(_ output: inout [String: Any], pair: (key: String, value: Any)) { + guard shouldIncludeRoot(key: pair.key) else { return } + guard let value = pair.value as? [String: Any] else { + output[pair.key] = pair.value + return + } + normalize(dictionary: value, output: &output, withParentKey: pair.key) + } + + func normalize(dictionary: [String: Any], + output: inout [String: Any], + withParentKey parentKey: String = "") { + dictionary.forEach { pair in + processPair(&output, parentKey: parentKey, pair: pair) + } + } + + private func shouldIncludeRoot(key: String) -> Bool { + guard !config.excludeKeys.contains(key) else { return false } + guard !config.rootLevelKeysInclude.isEmpty else { return true } + return config.rootLevelKeysInclude.contains(key) + } + + private func processPair(_ output: inout [String: Any], + parentKey: String = "", + pair: (key: String, value: Any)) { + guard !config.excludeKeys.contains(pair.key) else { return } + let newKey = newKey(for: pair.key, parentKey: parentKey) + guard let dictionary = pair.value as? [String: Any] else { + output[newKey] = pair.value + return + } + normalize(dictionary: dictionary, output: &output, withParentKey: newKey) + } + + private func newKey(for key: String, parentKey: String) -> String { + guard !parentKey.isEmpty else { return key } + return config.reduceKeys.contains(key) ? parentKey : "\(parentKey)\(config.separator)\(key)" + } +} + +extension JSONStorageContentNormalizer { + struct Config { + var separator = "." + let original: StorageContentReader + let rootLevelKeysInclude: [String] + let excludeKeys: [String] + let reduceKeys: [String] + } +} + +extension JSONStorageContentNormalizer { + static func minStorageContentReader(with storage: StorageContentReader) -> StorageContentReader { + JSONStorageContentNormalizer(config: .init(original: storage, + rootLevelKeysInclude: + [ + JSONStorageKeys.Privacy, + JSONStorageKeys.GDPR, + JSONStorageKeys.Unity, + JSONStorageKeys.PIPL + ], + excludeKeys: [ "ts" ], + reduceKeys: [ "value" ])) + } + + static func extendedStorageContentReader(with storage: StorageContentReader) -> StorageContentReader { + JSONStorageContentNormalizer(config: .init(original: storage, + rootLevelKeysInclude: + [ + JSONStorageKeys.Mediation, + JSONStorageKeys.Framework, + JSONStorageKeys.Adapter, + JSONStorageKeys.Configuration, + JSONStorageKeys.User, + JSONStorageKeys.UnifiedConfig + ], + excludeKeys: [ "ts", + JSONStorageKeys.Exclude, + JSONStorageKeys.PII, + "nonBehavioral", + "nonbehavioral" + ], + reduceKeys: [ "value" ])) + } + +} diff --git a/SourceCode/Swift/ObjBridges/ServiceProvider/ServiceProviderObjCBridge.swift b/SourceCode/Swift/ObjBridges/ServiceProvider/ServiceProviderObjCBridge.swift index 206d6766..9bbeeb36 100644 --- a/SourceCode/Swift/ObjBridges/ServiceProvider/ServiceProviderObjCBridge.swift +++ b/SourceCode/Swift/ObjBridges/ServiceProvider/ServiceProviderObjCBridge.swift @@ -1,11 +1,15 @@ import Foundation +// swiftlint:disable type_body_length @objc protocol ServiceProviderObjCBridgeDelegate: AnyObject { func getDeviceInfo(extended: Bool) -> [String: Any] - func getGameSessionId() -> String func didCompleteInit(_ config: [String: Any]) func didReceivePrivacy(_ privacy: [String: Any]) + func getValueFromJSONStorage(for key: String) -> Any? + func setValueToJSONStorage(_ value: Any?, for key: String) + func deleteKeyFromJSONStorage(for key: String) + func storageContent() -> [String: Any] } @objc @@ -13,7 +17,7 @@ final class ServiceProviderObjCBridge: NSObject { private(set) weak var delegate: ServiceProviderObjCBridgeDelegate? - var serviceProvider = UnityAdsServiceProvider() { + var serviceProvider = UnityAdsServiceProvider(skdSettingsStorage: .init()) { didSet { // this is required only for tests until we have objc legacy code and swift subscribeDelegate() @@ -64,7 +68,19 @@ final class ServiceProviderObjCBridge: NSObject { @objc func setDebugMode(_ debugMode: Bool) { - serviceProvider.logLevel = debugMode ? .trace : .fatal + serviceProvider.logLevel = debugMode ? .trace : .info + } + + @objc + func getToken(_ completion: Closure<[String: Any]>) { + do { + try serviceProvider.headerBiddingTokenReader.getToken({ token in + let tokenDict = (try? token.convertIntoDictionary()) ?? [:] + completion(tokenDict) + }) + } catch { + completion([:]) + } } } @@ -83,6 +99,16 @@ extension ServiceProviderObjCBridge { } } +extension ServiceProviderObjCBridge { + @objc var gameSessionId: String { + "\(serviceProvider.sessionInfoStorage.gameSessionID)" + } + + @objc var sessionId: String { + serviceProvider.sessionInfoStorage.sessionID + } +} + private extension ServiceProviderObjCBridge { func subscribeDelegate() { @@ -90,6 +116,22 @@ private extension ServiceProviderObjCBridge { return delegate?.getDeviceInfo(extended: $0) ?? [:] }) + serviceProvider.setLegacyJSONSaverClosure { [weak delegate] in + delegate?.setValueToJSONStorage($0.1, for: $0.0) + } + + serviceProvider.setLegacyJSONReaderClosure { [weak delegate] in + return delegate?.getValueFromJSONStorage(for: $0) + } + + serviceProvider.jsonStorageObjCBridge.jsonStorageReaderContentClosure = { [weak delegate] in + delegate?.storageContent() ?? [:] + } + + serviceProvider.setLegacyJSONKeyDeleteClosure { [weak delegate] in + delegate?.deleteKeyFromJSONStorage(for: $0) + } + serviceProvider.subscribeToPrivacyComplete { [weak delegate] privacyResponse in delegate?.didReceivePrivacy(privacyResponse) } diff --git a/SourceCode/Swift/Settings/SDKSettingsStorage.swift b/SourceCode/Swift/Settings/SDKSettingsStorage.swift index b59cdc5c..9309e36e 100644 --- a/SourceCode/Swift/Settings/SDKSettingsStorage.swift +++ b/SourceCode/Swift/Settings/SDKSettingsStorage.swift @@ -1,17 +1,9 @@ import Foundation -protocol PrivacyStateReader { - var privacyState: PrivacyState { get } -} - -protocol PrivacyResponseSaver { - func save(response: PrivacyResponse) -} - final class SDKSettingsStorage: LoggerLevelReader, LoggerSettingsReader, NetworkSettingsProvider, - SDKGameIdProvider { + SDKGameSettingsProvider { var metricSessionConfiguration: URLSessionConfiguration = .ephemeral @@ -21,15 +13,28 @@ final class SDKSettingsStorage: LoggerLevelReader, var metricsResourceTypes: [Int] = [1] // corresponds to .networkLoad - @Atomic var allowDumpToFile: Bool = false - @Atomic var currentLevel: LogLevel = .fatal - @Atomic var currentInitConfig: SDKInitializerConfig = .init(gameID: "") + var allowDumpToFile: Bool { + get { _logsIntoFile.load() } + set { _logsIntoFile.mutate({ $0 = newValue }) } + } + @Atomic private var logsIntoFile: Bool = false + var currentLevel: LogLevel { + get { _logLevel.load() } + set { _logLevel.mutate({ $0 = newValue }) } + } + @Atomic private var logLevel: LogLevel = .fatal + + @Atomic var currentInitConfig: SDKInitializerConfig = .init(gameID: "", isTestModeEnabled: true) var logsFileURL: URL { filePaths.diagnosticDump } let filePaths = FilePaths() var gameID: String { - currentInitConfig.gameID + _currentInitConfig.load().gameID + } + + var isTestModeEnabled: Bool { + _currentInitConfig.load().isTestModeEnabled } } diff --git a/SourceCode/Swift/Token/HeaderBiddingToken.swift b/SourceCode/Swift/Token/HeaderBiddingToken.swift new file mode 100644 index 00000000..ec99f039 --- /dev/null +++ b/SourceCode/Swift/Token/HeaderBiddingToken.swift @@ -0,0 +1,32 @@ +import Foundation + +enum HeaderBiddingTokenType: Int, Codable { + case native = 0 + case remote = 1 +} + +struct HeaderBiddingToken: DictionaryConvertible { + let value: String + let type: HeaderBiddingTokenType + let uuidString: String + let info: [String: Any] + let customPrefix: String + + enum CodingKeys: CodingKey { + case value + case type + case uuidString + case info + case customPrefix + } + + func convertIntoDictionary() throws -> [String: Any] { + var dict = [String: Any]() + dict.set(value, forCoding: CodingKeys.value) + dict.set(type.rawValue, forCoding: CodingKeys.type) + dict.set(uuidString, forCoding: CodingKeys.uuidString) + dict.set(info, forCoding: CodingKeys.info) + dict.set(customPrefix, forCoding: CodingKeys.customPrefix) + return dict + } +} diff --git a/SourceCode/Swift/Token/HeaderBiddingTokenReader.swift b/SourceCode/Swift/Token/HeaderBiddingTokenReader.swift new file mode 100644 index 00000000..c8e82644 --- /dev/null +++ b/SourceCode/Swift/Token/HeaderBiddingTokenReader.swift @@ -0,0 +1,37 @@ +import Foundation + +protocol HeaderBiddingTokenReader { + func getToken(_ completion: Closure) throws +} + +final class HeaderBiddingTokenReaderBase: HeaderBiddingTokenReader { + private let config: Config + + init(_ config: Config) { + self.config = config + } + + func getToken(_ completion: Closure) throws { + var info = config.deviceInfoReader.getDeviceInfoBody(of: .extended) + let uniqueId = config.uniqueIdGenerator.uniqueID + if config.experiments.experiments?.scarHbStrategyType != .disabled { + info["tid"] = uniqueId + } + let tokenValue = try config.compressor.compressedInfoString(info) + let prefixedTokenValue = config.customPrefix + tokenValue + let token = HeaderBiddingToken(value: prefixedTokenValue, + type: .native, + uuidString: uniqueId, + info: info, + customPrefix: config.customPrefix) + completion(token) + } + + struct Config { + let deviceInfoReader: DeviceInfoBodyStrategy + let compressor: StringCompressor + let customPrefix: String + let uniqueIdGenerator: UniqueGenerator + let experiments: ExperimentsReader + } +} diff --git a/SourceCode/Swift/UnityAdsServiceProvider.swift b/SourceCode/Swift/UnityAdsServiceProvider.swift index b20d3d88..4269a598 100644 --- a/SourceCode/Swift/UnityAdsServiceProvider.swift +++ b/SourceCode/Swift/UnityAdsServiceProvider.swift @@ -1,12 +1,12 @@ import Foundation - -class UnityAdsServiceProvider { - +// swiftlint:disable type_body_length +final class UnityAdsServiceProvider { + typealias TimeInfoReader = BootTimeReader & TimeZoneReader & TimeReader var sdkStateStorage: SDKStateStorage var skdSettingsStorage: SDKSettingsStorage - var deviceInfoReader: DeviceInfoReader & LegacyDeviceInfoReader var allowedNetworkCodes = Array(200...299) var legacyStateFactory = USRVInitializeStateFactory() + var sessionInfoStorage: SessionInfoReader let performanceMeasurer: PerformanceMeasurer // probably should use a struct to represent System? @@ -17,28 +17,65 @@ class UnityAdsServiceProvider { var logger: Logger private let networkServicesFactory: UnityAdsNetworkServicesFactory - private let timeReader: TimeReader + private let eventsNetworkServicesFactory: UnityAdsEventsNetworkServicesFactory private let syncQueue: DispatchQueue = .init(label: "Sync.queue") - - init(skdSettingsStorage: SDKSettingsStorage = .init()) { - timeReader = TimeReaderBase() + let jsonStorageObjCBridge = JSONStorageBridge() + let timeInfoReader: TimeInfoReader + let trackingStatusReader: TrackingStatusReader = TrackingStatusReaderBase() + let headerBiddingTokenReader: HeaderBiddingTokenReader + private let deviceInfoReaderBuilder: DeviceInfoBodyReaderBuilder + init(skdSettingsStorage: SDKSettingsStorage = .init(), + timeReader: TimeInfoReader = TimeReaderBase(), + telephonyProvider: TelephonyInfoProvider & CountryCodeProvider = TelephonyNetworkStatusProvider()) { self.skdSettingsStorage = skdSettingsStorage - + self.timeInfoReader = timeReader let loggerStrategy = LoggerStrategy(settingsReader: skdSettingsStorage) logger = LoggerWithGate(loggerLevelReader: skdSettingsStorage, original: loggerStrategy) - deviceInfoReader = defaultDeviceInfoReader(withLogger: logger) - let fileStorage = SDKConfigurationFileStorage(filePaths: skdSettingsStorage.filePaths, logger: logger) + let fileStorage = SDKConfigurationFileStorage(filePaths: skdSettingsStorage.filePaths, + logger: logger) let sdkConfigurationStorage = SDKConfigurationInMemoryStorage(fileStorage: fileStorage) sdkStateStorage = SDKStateStorage(configProvider: sdkConfigurationStorage) - performanceMeasurer = .init(timeReader: timeReader) + sessionInfoStorage = SessionInfoStorage(settings: .defaultSettings(privateStorage: jsonStorageObjCBridge)) + + performanceMeasurer = .init(timeReader: timeInfoReader) + + let eventsServicesConfig = UnityAdsEventsNetworkServicesFactory.Config(configProvider: sdkStateStorage, + metricsDataReader: sdkStateStorage, + retriesReader: sdkStateStorage, + logger: logger, + settingsReader: skdSettingsStorage, + sessionInfoReader: sessionInfoStorage) + + eventsNetworkServicesFactory = UnityAdsEventsNetworkServicesFactory(config: eventsServicesConfig) + let builderConfig = DeviceInfoBodyReaderBuilder.Config(sessionInfoStorage: sessionInfoStorage, + trackingStatusReader: trackingStatusReader, + gameSettingsReader: skdSettingsStorage, + sdkStateStorage: sdkStateStorage, + persistenceStorage: jsonStorageObjCBridge, + logger: logger, + timeReader: timeReader, + telephonyInfoProvider: telephonyProvider, + performanceMeasurer: performanceMeasurer, + metricsSender: eventsNetworkServicesFactory.metricsSender) + deviceInfoReaderBuilder = DeviceInfoBodyReaderBuilder(baseConfig: builderConfig) + networkServicesFactory = .init(settingsProvider: skdSettingsStorage, configurationProvider: sdkStateStorage, - deviceInfoReader: deviceInfoReader, + deviceInfoReaderProvider: deviceInfoReaderBuilder, performanceMeasurer: performanceMeasurer, - logger: logger) + logger: logger, + metricSenderProvider: eventsNetworkServicesFactory) + + let hbTokenConfig = HeaderBiddingTokenReaderBase.Config( + deviceInfoReader: deviceInfoReaderBuilder.deviceInfoBodyReader, + compressor: Base64GzipCompressor(dataCompressor: GZipCompressor()), + customPrefix: "1:", + uniqueIdGenerator: IdentifiersGeneratorBase(), + experiments: sdkConfigurationStorage) + headerBiddingTokenReader = HeaderBiddingTokenReaderBase(hbTokenConfig) } private var _sdkInitializer: SDKInitializer? @@ -46,13 +83,27 @@ class UnityAdsServiceProvider { var sdkInitializer: SDKInitializer { syncQueue.sync { getOrCreateInitializer() } } +} +extension UnityAdsServiceProvider { func updateConfiguration(_ config: UnityAdsConfig) { sdkStateStorage.config = config } func setLegacyInfoClosure(_ closure: ClosureWithReturn?) { - deviceInfoReader.setLegacyInfoGetter(closure) + deviceInfoReaderBuilder.setLegacyInfoGetter(closure) + } + + func setLegacyJSONReaderClosure(_ closure: ClosureWithReturn?) { + jsonStorageObjCBridge.jsonStorageReaderClosure = closure + } + + func setLegacyJSONSaverClosure(_ closure: Closure<(String, Any?)>?) { + jsonStorageObjCBridge.jsonStorageSaverClosure = closure + } + + func setLegacyJSONKeyDeleteClosure(_ closure: Closure?) { + jsonStorageObjCBridge.jsonStorageDeleteClosure = closure } } @@ -109,19 +160,25 @@ extension UnityAdsServiceProvider { } var unityAdsMetricsNativeNetwork: UnityAdsWebViewNetwork { - networkServicesFactory.unityAdsMetricsNativeNetwork + eventsNetworkServicesFactory.unityAdsMetricsNativeNetwork } } extension UnityAdsServiceProvider { private var initTaskRunner: Task { TaskPerformanceDecorator(original: mainTask, - metricSender: networkServicesFactory.metricsSender, + metricSender: eventsNetworkServicesFactory.metricsSender, performanceMeasurer: performanceMeasurer) } private var mainTask: PerformanceMeasurableTask { - StartInitTask(factory: initTaskFactory, sequence: sequence) + StartInitTask(factory: initTaskFactory, + sequence: sequence, + timeReader: timeInfoReader, + appStartTimeSaver: sdkStateStorage, + logger: logger, + settingProvider: skdSettingsStorage, + sessionInfoReader: sessionInfoStorage) } private var sequence: [InitTaskCategory] { @@ -137,17 +194,29 @@ extension UnityAdsServiceProvider { var initTaskFactory: InitializationTaskFactoryStrategy { .init(downloaderBuilder: networkServicesFactory.webViewDownloaderBuilder, - metricSenderProvider: networkServicesFactory, + metricSenderProvider: eventsNetworkServicesFactory, + networkSenderProvider: networkServicesFactory, sdkStateStorage: sdkStateStorage, performanceMeasurer: performanceMeasurer, stateFactoryObjc: legacyStateFactory, - settingsProvider: skdSettingsStorage) + settingsProvider: skdSettingsStorage, + keyValueStorage: jsonStorageObjCBridge, + cleanupKeys: [JSONStorageKeys.GameSessionID], + deviceInfoReader: deviceInfoReaderBuilder.deviceInfoBodyReader) } } -private func defaultDeviceInfoReader(withLogger logger: Logger) -> DeviceInfoReader & LegacyDeviceInfoReader { - let webUserAgent = WebUserAgentReaderBase(lastKnownOSKey: Constants.UserDefaultsKeys.LastKnownSystemVersion, - userAgentValueKey: Constants.UserDefaultsKeys.LastKnownUserAgentKey) - return DeviceInfoReaderBase(logger: logger, userAgentReader: webUserAgent) +extension SessionInfoStorage.Settings { + static func defaultSettings(privateStorage: KeyValueStorage, + idGenerator: IdentifiersGenerator = IdentifiersGeneratorBase()) -> Self { + .init(privateStorage: privateStorage, + gameSessionIDKey: JSONStorageKeys.GameSessionID, + sessionIDKey: JSONStorageKeys.SessionID, + userIDKey: JSONStorageKeys.UserID, + idfiIDKey: JSONStorageKeys.IDFI, + auIDKey: JSONStorageKeys.AUID, + userNonBehavioralFlagKey: JSONStorageKeys.UserNonBehavioralValue, + idGenerator: idGenerator) + } } diff --git a/Tests/.swiftlint.yml b/Tests/.swiftlint.yml index 5b08a4d8..d7ce9704 100644 --- a/Tests/.swiftlint.yml +++ b/Tests/.swiftlint.yml @@ -2,6 +2,7 @@ disabled_rules: # rule identifiers to exclude from running - generic_type_name - identifier_name - discouraged_direct_init + - blanket_disable_command # - type_name opt_in_rules: # some rules are only opt-in - empty_count @@ -26,14 +27,13 @@ opt_in_rules: # some rules are only opt-in - multiline_function_chains - multiline_parameters - number_separator - - unused_import - - unused_capture_list - - unused_declaration - unused_setter_value - yoda_condition analyzer_rules: # Rules run by `swiftlint analyze` (experimental) - explicit_self + - unused_import + - unused_declaration # configurable rules can be customized from this configuration file # binary rules can set their severity level nesting: diff --git a/Tests/Categories/UnityAds+Testability.m b/Tests/Categories/UnityAds+Testability.m index 04d6cf27..3c0d009c 100644 --- a/Tests/Categories/UnityAds+Testability.m +++ b/Tests/Categories/UnityAds+Testability.m @@ -4,6 +4,7 @@ #import "USRVWebViewApp.h" #import "USRVWebViewAsyncOperationStorage.h" #import "USRVWebViewAsyncOperation.h" +#import "UADSServiceProviderContainer.h" @class UnityAds; @class USRVSdkProperties; @@ -18,7 +19,16 @@ + (void)resetForTest { [USRVWebViewApp setCurrentApp: nil]; [USRVWebViewAsyncOperationStorage.sharedInstance resetForTesting]; [USRVWebViewAsyncOperation signalLock]; - + [USRVInvocation setClassTable: [[USRVConfiguration new] getWebAppApiClassList]]; + [self deleteConfigFile]; + [UADSServiceProviderContainer sharedInstance].serviceProvider = [UADSServiceProvider new]; +} + ++ (void)deleteConfigFile { + NSString *fileName = [USRVSdkProperties getLocalConfigFilepath]; + + [[NSFileManager defaultManager] removeItemAtPath: fileName + error: nil]; } @end diff --git a/Tests/UnityAdsInitializationLegacyTests/InitializeTests.m b/Tests/UnityAdsInitializationLegacyTests/InitializeTests.m index 65abbfd9..faefddd6 100644 --- a/Tests/UnityAdsInitializationLegacyTests/InitializeTests.m +++ b/Tests/UnityAdsInitializationLegacyTests/InitializeTests.m @@ -29,6 +29,7 @@ @interface InitializeTests : XCTestCase @implementation InitializeTests - (void)setUp { + UADSServiceProviderContainer.sharedInstance.serviceProvider = [UADSServiceProvider new]; [self cleanupCache]; [super setUp]; } diff --git a/Tests/UnityAdsPerformanceTests/Swift/Initialization/InitializationPerformanceTest.swift b/Tests/UnityAdsPerformanceTests/Swift/Initialization/InitializationPerformanceTest.swift index d4c1bc13..9a917d08 100644 --- a/Tests/UnityAdsPerformanceTests/Swift/Initialization/InitializationPerformanceTest.swift +++ b/Tests/UnityAdsPerformanceTests/Swift/Initialization/InitializationPerformanceTest.swift @@ -40,13 +40,13 @@ final class InitializationPerformanceTest: SDKInitializerLegacyIntegrationTestsB } func test_get_token_during_swift_new_task_initializing() throws { - try run_get_token_during_initializing(with: ["s_init": true, "s_ntf": true], + try run_get_token_during_initializing(with: ["s_init": true, "s_ntf": true, "s_din": true], metrics: ExpectedMetrics.SequentialFlow.HappyPath, expectedDiagnostic: true) } func test_get_token_during_swift_parallel_initializing() throws { - try run_get_token_during_initializing(with: ["s_init": true, "s_pte": true], + try run_get_token_during_initializing(with: ["s_init": true, "s_pte": true, "s_din": true], metrics: ExpectedMetrics.ParallelFlow.HappyPath, expectedDiagnostic: true) } @@ -59,7 +59,7 @@ final class InitializationPerformanceTest: SDKInitializerLegacyIntegrationTestsB var metrics = metrics metrics.append(contentsOf: [ .legacy(.nativeTokenAvailable), - .legacy(.latency(.intoCollection)), + .legacy(.latency(.infoCollection)), .legacy(.latency(.infoCompression))]) try? runFlow(sdkMetrics: metrics, experiments: experiments, @@ -81,7 +81,8 @@ final class InitializationPerformanceTest: SDKInitializerLegacyIntegrationTestsB try? runFlow(sdkMetrics: ExpectedMetrics.LegacyFlow.HappyPath, experiments: [:], expectNetworkDiagnostic: false, - legacyFlow: true) + legacyFlow: true, + validateTimeStamp: false) } } @@ -99,7 +100,7 @@ final class InitializationPerformanceTest: SDKInitializerLegacyIntegrationTestsB measure(metrics: metrics, options: testOptions) { try? runFlow(sdkMetrics: ExpectedMetrics.SequentialFlow.HappyPath, - experiments: ["s_init": true, "s_ntf": true], + experiments: ["s_init": true, "s_ntf": true, "s_din": true], expectNetworkDiagnostic: true) } @@ -109,7 +110,7 @@ final class InitializationPerformanceTest: SDKInitializerLegacyIntegrationTestsB measure(metrics: metrics, options: testOptions) { try? runFlow(sdkMetrics: ExpectedMetrics.ParallelFlow.HappyPath, - experiments: ["s_init": true, "s_pte": true], + experiments: ["s_init": true, "s_pte": true, "s_din": true], expectNetworkDiagnostic: true) } } @@ -133,6 +134,7 @@ extension InitializationPerformanceTest { expectNetworkDiagnostic: Bool, legacyFlow: Bool = false, parallelToInit: VoidClosure? = nil, + validateTimeStamp: Bool = true, line: UInt = #line, file: StaticString = #file) throws { let overrideJson = ["hash": configMockFactory.longWebViewDataDataHash] @@ -154,7 +156,8 @@ extension InitializationPerformanceTest { expectedNumberOfRequests: responses.count, multithreadCount: 1, metrics: sdkMetrics, - expectDiagnostic: expectNetworkDiagnostic) + expectDiagnostic: expectNetworkDiagnostic, + validateStartTimeStamp: validateTimeStamp) try executeTest(with: testConfig, file: file, line: line, diff --git a/Tests/UnityAdsTests-Bridging-Header.h b/Tests/UnityAdsTests-Bridging-Header.h index 87430071..0b3d2c72 100644 --- a/Tests/UnityAdsTests-Bridging-Header.h +++ b/Tests/UnityAdsTests-Bridging-Header.h @@ -44,10 +44,6 @@ #import "UADSTsiMetric.h" #import "UADSPrivacyMetrics.h" #import "USRVApiSdk.h" -#import "UADSInstallationIdExtension.h" -#import "UADSPlist.h" -#import "UADSUnityPlayerPrefsStore.h" -#import "UADSUserDefaultsStore.h" #import "USRVInitializeStateCreate.h" #import "USRVInitializeStateReset.h" #import "USRVInitializeStateLoadCache.h" @@ -58,7 +54,11 @@ #import "USRVInitializeStateLoadConfigFile.h" #import "USRVInitializeStateLoadWeb.h" #import "UADSInitializeEventsMetricSender.h" +#import "USRVJsonStorageAggregator.h" +#import "USRVStorageManager.h" // TESTING SPECIFIC #import "UnityAds+Testability.h" #import "TestUtilities.h" #import "USRVWebViewCallbackMock.h" +#import "UADSDeviceTestsHelper.h" + diff --git a/Tests/UnityAdsTests/Core/Configuration/Mocks/UADSPIITrackingStatusReaderMock.m b/Tests/UnityAdsTests/Core/Configuration/Mocks/UADSPIITrackingStatusReaderMock.m index 6ca1ef71..d739d7f6 100644 --- a/Tests/UnityAdsTests/Core/Configuration/Mocks/UADSPIITrackingStatusReaderMock.m +++ b/Tests/UnityAdsTests/Core/Configuration/Mocks/UADSPIITrackingStatusReaderMock.m @@ -12,9 +12,9 @@ - (UADSPrivacyMode)privacyMode { return self.expectedMode; } -- (BOOL)userNonBehavioralFlag { +- (NSNumber *)userNonBehavioralFlag { _userBehavioralCount += 1; - return self.expectedUserBehaviouralFlag ? : false; + return self.expectedUserBehaviouralFlag ? @(self.expectedUserBehaviouralFlag) : nil; } @end diff --git a/Tests/UnityAdsTests/Core/Configuration/SDKConfigurationReader/ConfigurationLoader/Decorators/UADSConfigurationLoaderWithPrivacyTestCase.m b/Tests/UnityAdsTests/Core/Configuration/SDKConfigurationReader/ConfigurationLoader/Decorators/UADSConfigurationLoaderWithPrivacyTestCase.m index 481b0ab0..8fa39135 100644 --- a/Tests/UnityAdsTests/Core/Configuration/SDKConfigurationReader/ConfigurationLoader/Decorators/UADSConfigurationLoaderWithPrivacyTestCase.m +++ b/Tests/UnityAdsTests/Core/Configuration/SDKConfigurationReader/ConfigurationLoader/Decorators/UADSConfigurationLoaderWithPrivacyTestCase.m @@ -44,6 +44,15 @@ - (void)test_network_error_doesnt_call_loader_and_saver_hardware_error { errorPrivacy: self.privacyErrorMock]; } +- (void)test_game_disabled_error_doesnt_call_loader_and_saver { + [self runFlowWithPrivacyCodeAndValidate: 0 + allowTrackingFlag: false + expectedSaverCalls: 0 + privacyCalls: 1 + loaderCalled: 0 + errorPrivacy: uads_privacyGameDisabledError]; +} + - (void)test_privacy_error_doesnt_block_loader_request_but_calls_saver { [self runFlowWithPrivacyCodeAndValidate: 0 allowTrackingFlag: false diff --git a/Tests/UnityAdsTests/Core/Configuration/SDKConfigurationReader/ConfigurationLoader/Mocks/UADSPrivacyStorageMock.h b/Tests/UnityAdsTests/Core/Configuration/SDKConfigurationReader/ConfigurationLoader/Mocks/UADSPrivacyStorageMock.h index 19f7e4bb..67fe4902 100644 --- a/Tests/UnityAdsTests/Core/Configuration/SDKConfigurationReader/ConfigurationLoader/Mocks/UADSPrivacyStorageMock.h +++ b/Tests/UnityAdsTests/Core/Configuration/SDKConfigurationReader/ConfigurationLoader/Mocks/UADSPrivacyStorageMock.h @@ -5,6 +5,7 @@ NS_ASSUME_NONNULL_BEGIN @interface UADSPrivacyStorageMock : NSObject @property (nonatomic, strong) NSArray *responses; @property (nonatomic, assign) UADSPrivacyResponseState expectedState; +@property (nonatomic) BOOL shouldSendUserNonBehavioral; @end NS_ASSUME_NONNULL_END diff --git a/Tests/UnityAdsTests/Core/Configuration/SDKConfigurationReader/ConfigurationLoader/Mocks/UADSPrivacyStorageMock.m b/Tests/UnityAdsTests/Core/Configuration/SDKConfigurationReader/ConfigurationLoader/Mocks/UADSPrivacyStorageMock.m index f09e86bc..24a4330d 100644 --- a/Tests/UnityAdsTests/Core/Configuration/SDKConfigurationReader/ConfigurationLoader/Mocks/UADSPrivacyStorageMock.m +++ b/Tests/UnityAdsTests/Core/Configuration/SDKConfigurationReader/ConfigurationLoader/Mocks/UADSPrivacyStorageMock.m @@ -7,6 +7,7 @@ - (instancetype)init if (self) { self.responses = [NSArray new]; + self.shouldSendUserNonBehavioral = false; } return self; diff --git a/Tests/UnityAdsTests/Core/Configuration/SDKConfigurationReader/ConfigurationLoader/UADSConfigurationLoaderIntegrationMetricsBatchTests.m b/Tests/UnityAdsTests/Core/Configuration/SDKConfigurationReader/ConfigurationLoader/UADSConfigurationLoaderIntegrationMetricsBatchTests.m index db249e6e..fa7bdece 100644 --- a/Tests/UnityAdsTests/Core/Configuration/SDKConfigurationReader/ConfigurationLoader/UADSConfigurationLoaderIntegrationMetricsBatchTests.m +++ b/Tests/UnityAdsTests/Core/Configuration/SDKConfigurationReader/ConfigurationLoader/UADSConfigurationLoaderIntegrationMetricsBatchTests.m @@ -2,6 +2,7 @@ #import "UADSConfigurationLoaderIntegrationMetricsBatchTests.h" #import "UADSMetricSenderWithBatch.h" #import "UADSLoggerMock.h" +#import "XCTestCase+Convenience.h" @interface UADSConfigurationLoaderIntegrationMetricsBatchTests () @property (nonatomic, strong) id configCRUD; @@ -17,12 +18,14 @@ - (void)setUp { } - (void)test_config_failure_triggers_batcher_to_send_metrics_by_saving_empty_config { + self.webRequestFactoryMock.expectedRequestData = @[[NSData new], [NSData new], [NSData new]]; //privacy + config + fallback id sut = [self callSUTExpectingFailWithConfig: [self factoryConfigWithExperiments: @{}]]; [self.saverMock saveConfiguration: [USRVConfiguration newFromJSON: @{}]]; - - [NSThread sleepForTimeInterval: 1]; + XCTestExpectation *exp = [self defaultExpectation]; + self.metricsSenderMock.exp = exp; + [self waitForExpectations:@[exp] timeout: 1]; [self validateCreatedRequestAtIndex: 0 withExpectedHostHame: self.expectedHostName andExpectedQueries: nil]; @@ -45,4 +48,11 @@ - (void)test_config_failure_triggers_batcher_to_send_metrics_by_saving_empty_con andLogger: [UADSLoggerMock new]]; } +- (void)deleteConfigFile { + NSString *fileName = [USRVSdkProperties getLocalConfigFilepath]; + + [[NSFileManager defaultManager] removeItemAtPath: fileName + error: nil]; +} + @end diff --git a/Tests/UnityAdsTests/Core/Configuration/SDKConfigurationReader/ConfigurationLoader/UADSConfigurationLoaderIntegrationPrivacyRequestTests.m b/Tests/UnityAdsTests/Core/Configuration/SDKConfigurationReader/ConfigurationLoader/UADSConfigurationLoaderIntegrationPrivacyRequestTests.m index d801cc75..1c65a273 100644 --- a/Tests/UnityAdsTests/Core/Configuration/SDKConfigurationReader/ConfigurationLoader/UADSConfigurationLoaderIntegrationPrivacyRequestTests.m +++ b/Tests/UnityAdsTests/Core/Configuration/SDKConfigurationReader/ConfigurationLoader/UADSConfigurationLoaderIntegrationPrivacyRequestTests.m @@ -16,17 +16,18 @@ - (void)test_default_should_call_privacy_request { ]; [self.deviceInfoTester commitAllTestData]; - + [self.deviceInfoTester commitNonBehavioral:true]; + [self callSUTExpectingSuccessWithConfig: [self factoryConfigWithExperiments: @{}]]; - NSArray *expectedKeys = self.deviceInfoTester.allExpectedKeysFromMinInfo; + NSArray *expectedKeys = [self.deviceInfoTester allExpectedKeysFromMinInfoWithUserNonBehavioral:true]; [self validateCreatedRequestAtIndex: 0 withExpectedHostHame: self.expectedHostName andBodyDataKeys: [self appendCommonTo: expectedKeys]]; - NSArray *expectedWithPII = [[self.deviceInfoTester allExpectedKeys] arrayByAddingObjectsFromArray: self.deviceInfoTester.piiDecisionContentData.allKeys]; + NSArray *expectedWithPII = [[self.deviceInfoTester allExpectedKeysWithNonBehavioral: false] arrayByAddingObjectsFromArray: self.deviceInfoTester.piiDecisionContentData.allKeys]; expectedWithPII = [self appendCommonTo: expectedWithPII]; @@ -54,12 +55,13 @@ - (void)test_if_privacy_succeeds_loader_calls_it_once_per_session { ]; [self.deviceInfoTester commitAllTestData]; + [self.deviceInfoTester commitNonBehavioral:true]; [self callSUTExpectingSuccessWithConfig: [self factoryConfigWithExperiments: @{}]]; [self callSUTExpectingSuccessWithConfig: [self factoryConfigWithExperiments: @{}]]; // privacy request - NSArray *expectedKeys = self.deviceInfoTester.allExpectedKeysFromMinInfo; + NSArray *expectedKeys = [self.deviceInfoTester allExpectedKeysFromMinInfoWithUserNonBehavioral:true]; [self validateCreatedRequestAtIndex: 0 withExpectedHostHame: self.expectedHostName @@ -67,7 +69,7 @@ - (void)test_if_privacy_succeeds_loader_calls_it_once_per_session { //first config request - NSArray *expectedWithPII = [[self.deviceInfoTester allExpectedKeys] arrayByAddingObjectsFromArray: self.deviceInfoTester.piiDecisionContentData.allKeys]; + NSArray *expectedWithPII = [[self.deviceInfoTester allExpectedKeysWithNonBehavioral: false] arrayByAddingObjectsFromArray: self.deviceInfoTester.piiDecisionContentData.allKeys]; expectedWithPII = [self appendCommonTo: expectedWithPII]; @@ -101,10 +103,11 @@ - (void)test_default_privacy_request_broken_should_not_include_pii { ]; [self.deviceInfoTester commitAllTestData]; + [self.deviceInfoTester commitNonBehavioral:true]; [self callSUTExpectingSuccessWithConfig: [self factoryConfigWithExperiments: @{}]]; - NSArray *expectedKeys = self.deviceInfoTester.allExpectedKeysFromMinInfo; + NSArray *expectedKeys = [self.deviceInfoTester allExpectedKeysFromMinInfoWithUserNonBehavioral:true]; [self validateCreatedRequestAtIndex: 0 withExpectedHostHame: self.expectedHostName @@ -113,7 +116,7 @@ - (void)test_default_privacy_request_broken_should_not_include_pii { [self validateCreatedRequestAtIndex: 1 withExpectedHostHame: self.expectedHostName - andBodyDataKeys: [self appendCommonTo: self.deviceInfoTester.allExpectedKeys]]; + andBodyDataKeys: [self appendCommonTo: [self.deviceInfoTester allExpectedKeysWithNonBehavioral: false]]]; [self validateCreateRequestCalledNumberOfTimes: 2]; [self validateConfigWasSavedToPersistenceNumberOfTimes: 1]; diff --git a/Tests/UnityAdsTests/Core/Configuration/SDKConfigurationReader/ConfigurationLoader/UADSConfigurationLoaderIntegrationTestsBase.m b/Tests/UnityAdsTests/Core/Configuration/SDKConfigurationReader/ConfigurationLoader/UADSConfigurationLoaderIntegrationTestsBase.m index 5fa3b3da..3256d293 100644 --- a/Tests/UnityAdsTests/Core/Configuration/SDKConfigurationReader/ConfigurationLoader/UADSConfigurationLoaderIntegrationTestsBase.m +++ b/Tests/UnityAdsTests/Core/Configuration/SDKConfigurationReader/ConfigurationLoader/UADSConfigurationLoaderIntegrationTestsBase.m @@ -100,6 +100,7 @@ - (UADSConfigurationLoaderBuilder *)sutBuilderForConfig: (id)c builder.currentTimeStampReader = [UADSCurrentTimestampMock new]; builder.retryInfoReader = [UADSRetryInfoReaderMock newWithInfo: _deviceInfoTester.retryTags]; builder.gameSessionIdReader = [UADSGameSessionIdReaderBase new]; + builder.sharedSessionIdReader = [UADSSharedSessionIdReaderBase new]; return builder; } diff --git a/Tests/UnityAdsTests/Core/Configuration/USRVConfigurationRequestFactoryBaseTestCase.m b/Tests/UnityAdsTests/Core/Configuration/USRVConfigurationRequestFactoryBaseTestCase.m index 4e5df276..d5be97c8 100644 --- a/Tests/UnityAdsTests/Core/Configuration/USRVConfigurationRequestFactoryBaseTestCase.m +++ b/Tests/UnityAdsTests/Core/Configuration/USRVConfigurationRequestFactoryBaseTestCase.m @@ -126,6 +126,7 @@ - (void)test_body_contains_gzip_data_for_privacy_type { builder.currentTimeStampReader = _timestampMock; builder.noCompression = !compressed; builder.configurationSaver = [UADSConfigurationCRUDBase new]; + builder.sharedSessionIdReader = [UADSSharedSessionIdReaderBase new]; return [builder requestFactoryWithExtendedInfo: true]; } diff --git a/Tests/UnityAdsTests/Core/Data/USRVJsonUtilitiesTests.m b/Tests/UnityAdsTests/Core/Data/USRVJsonUtilitiesTests.m index 1e212a03..77f07d75 100644 --- a/Tests/UnityAdsTests/Core/Data/USRVJsonUtilitiesTests.m +++ b/Tests/UnityAdsTests/Core/Data/USRVJsonUtilitiesTests.m @@ -41,6 +41,7 @@ - (void)setUp { } - (void)tearDown { + [USRVJsonUtilities setMockException: nil]; [self resetUnityAds]; } diff --git a/Tests/UnityAdsTests/Core/Device/DeviceTestsHelper/UADSDeviceTestsHelper.h b/Tests/UnityAdsTests/Core/Device/DeviceTestsHelper/UADSDeviceTestsHelper.h index d5db2b5b..d684b47e 100644 --- a/Tests/UnityAdsTests/Core/Device/DeviceTestsHelper/UADSDeviceTestsHelper.h +++ b/Tests/UnityAdsTests/Core/Device/DeviceTestsHelper/UADSDeviceTestsHelper.h @@ -24,15 +24,17 @@ NS_ASSUME_NONNULL_BEGIN - (NSString *) idfiMockValue; - (void) setAnalyticSessionID; - (void) setAnalyticUserID; +- (void)setAUID; - (NSString *) analyticSessionMockValue; - (NSString *) analyticUserMockValue; - (NSDictionary *)expectedMergedDataRealStorage; - (NSArray *) expectedKeysFromDefaultInfo; -- (NSArray *) expectedKeysFromDefaultMinInfo; +- (NSArray *) expectedKeysFromDefaultInfoWithUserNonBehavioral:(BOOL)withUserNonBehavioral; +- (NSArray *) expectedKeysFromDefaultMinInfoWithUserNonBehavioral:(BOOL)withUserNonBehavioral; - (NSArray *) allExpectedKeys; +- (NSArray *)allExpectedKeysWithNonBehavioral: (BOOL)withUserNonBehavioral; - (void) setPIIDataToStorage; -- (void) commitPrivacyMode: (UADSPrivacyMode)mode - andNonBehavioral: (BOOL)flag; +- (void) commitNonBehavioral: (BOOL)flag; - (void)validateDataContains: (NSDictionary *)data allKeys: (NSArray *)keys; - (NSDictionary *) piiDecisionContentData; - (void)saveExpectedContentToJSONStorage: (NSDictionary *)content; @@ -43,7 +45,7 @@ NS_ASSUME_NONNULL_BEGIN - (UADSMetric *) infoCollectionLatencyMetrics; - (UADSMetric *) infoCompressionLatencyMetrics; - (UADSMetric *) privacyRequestLatencyMetrics; -- (NSArray *) allExpectedKeysFromMinInfo; +- (NSArray *)allExpectedKeysFromMinInfoWithUserNonBehavioral:(BOOL)withUserNonBehavioral; - (UADSMetric *)privacyRequestFailureWithReason: (UADSPrivacyLoaderError)reason; - (UADSMetric *)configLatencyFailureMetricWithReason: (UADSConfigurationLoaderError)reason; - (UADSMetric *) configLatencySuccessMetric; diff --git a/Tests/UnityAdsTests/Core/Device/DeviceTestsHelper/UADSDeviceTestsHelper.m b/Tests/UnityAdsTests/Core/Device/DeviceTestsHelper/UADSDeviceTestsHelper.m index fd12c3ea..f5d0f1e2 100644 --- a/Tests/UnityAdsTests/Core/Device/DeviceTestsHelper/UADSDeviceTestsHelper.m +++ b/Tests/UnityAdsTests/Core/Device/DeviceTestsHelper/UADSDeviceTestsHelper.m @@ -130,13 +130,8 @@ - (void)commitUserData { value : @(true)]; } -- (void)commitPrivacyMode: (UADSPrivacyMode)mode - andNonBehavioral: (BOOL)flag { +- (void)commitNonBehavioral: (BOOL)flag { UADSMetaData *privacyData = [UADSMetaData new]; - - [privacyData set: @"privacy.mode" - value : uads_privacyModeString(mode)]; - [privacyData set: @"user.nonBehavioral" value : @(flag)]; [privacyData commit]; @@ -170,6 +165,7 @@ - (void)commitUserDefaultsTestData { [self setIDFI]; [self setAnalyticSessionID]; [self setAnalyticUserID]; + [self setAUID]; } - (USRVStorage *)privateStorage { @@ -207,8 +203,8 @@ - (NSDictionary *)expectedMergedDataRealStorage { }]; } -- (NSArray *)allExpectedKeysFromMinInfo { - return [self.expectedKeysFromDefaultMinInfo arrayByAddingObjectsFromArray: self.expectedMinimumDataRealStorage.allKeys]; +- (NSArray *)allExpectedKeysFromMinInfoWithUserNonBehavioral:(BOOL)withUserNonBehavioral { + return [[self expectedKeysFromDefaultMinInfoWithUserNonBehavioral:withUserNonBehavioral] arrayByAddingObjectsFromArray: self.expectedMinimumDataRealStorage.allKeys]; } - (NSDictionary *)expectedMinimumDataRealStorage { @@ -258,10 +254,16 @@ - (void)setAnalyticUserID { forKey: kUADSStorageAnalyticUserKey]; } +- (void)setAUID { + [USRVPreferences setString: self.analyticUserMockValue + forKey: kUADSStorageAUIDKey]; +} + - (void)resetUserDefaults { [USRVPreferences removeKey: kUADSStorageAnalyticSessionKey]; [USRVPreferences removeKey: kUADSStorageAnalyticUserKey]; [USRVPreferences removeKey: kUADSStorageIDFIKey]; + [USRVPreferences removeKey: kUADSStorageAUIDKey]; [NSUserDefaults resetStandardUserDefaults]; } @@ -292,8 +294,8 @@ - (void)saveExpectedContentToJSONStorage: (NSDictionary *)content { } } -- (NSArray *)expectedKeysFromDefaultMinInfo { - return @[ +- (NSArray *)expectedKeysFromDefaultMinInfoWithUserNonBehavioral:(BOOL)withUserNonBehavioral { + NSArray * keys = @[ kUADSDeviceInfoIDFIKey, kUADSDeviceInfoReaderPlatformKey, kUADSDeviceInfoLimitAdTrackingKey, @@ -301,73 +303,85 @@ - (NSArray *)expectedKeysFromDefaultMinInfo { kUADSDeviceInfoGameIDKey, UADSJsonStorageKeyNames.webViewDataGameSessionIdKey, kUADSDeviceInfoReaderSDKVersionNameKey, - kUADSDeviceInfoReaderSDKVersionKey, - UADSJsonStorageKeyNames.userNonBehavioralFlagKey + kUADSDeviceInfoReaderSDKVersionKey ]; + + if (withUserNonBehavioral) { + keys = [keys arrayByAddingObject:UADSJsonStorageKeyNames.userNonBehavioralFlagKey]; + } + + return keys; +} +- (NSArray *) expectedKeysFromDefaultInfoWithUserNonBehavioral:(BOOL)withUserNonBehavioral { + return [[self expectedKeysFromDefaultMinInfoWithUserNonBehavioral:withUserNonBehavioral] arrayByAddingObjectsFromArray: @[ + kUADSDeviceInfoReaderBundleIDKey, + kUADSDeviceInfoReaderBundleVersionKey, + kUADSDeviceInfoReaderConnectionTypeKey, + kUADSDeviceInfoReaderNetworkTypeKey, + kUADSDeviceInfoReaderScreenHeightKey, + kUADSDeviceInfoReaderScreenWidthKey, + kUADSDeviceInfoReaderEncryptedKey, + kUADSDeviceInfoReaderRootedKey, + kUADSDeviceInfoReaderOSVersionKey, + kUADSDeviceInfoReaderDeviceModelKey, + kUADSDeviceInfoReaderLanguageKey, + kUADSDeviceInfoReaderIsTestModeKey, + kUADSDeviceInfoReaderFreeMemoryKey, + kUADSDeviceInfoReaderBatteryStatusKey, + kUADSDeviceInfoReaderBatteryLevelKey, + kUADSDeviceInfoReaderScreenBrightnessKey, + kUADSDeviceInfoReaderVolumeKey, + kUADSDeviceInfoDeviceFreeSpaceKey, + kUADSDeviceInfoDeviceTotalSpaceKey, + kUADSDeviceInfoDeviceTotalMemoryKey, + kUADSDeviceInfoDeviceDeviceNameKey, + kUADSDeviceInfoDeviceLocaleListKey, + kUADSDeviceInfoDeviceCurrentUiThemeKey, + kUADSDeviceInfoDeviceAdNetworkPlistKey, + kUADSDeviceInfoDeviceIsWiredHeadsetOnKey, + kUADSDeviceInfoDeviceSystemBootTimeKey, + kUADSDeviceInfoDeviceNetworkOperatorKey, + kUADSDeviceInfoDeviceNetworkOperatorNameKey, + kUADSDeviceInfoDeviceScreenScaleKey, + kUADSDeviceInfoIsSimulatorKey, + kUADSDeviceInfoLimitTimeZoneKey, + kUADSDeviceInfoLimitStoresKey, + kUADSDeviceInfoCPUCountKey, + kUADSDeviceInfoWebViewAgentKey, + kUADSDeviceInfoAppStartTimestampKey, + kUADSDeviceInfoAppInForegroundKey, + kUADSDeviceInfoCurrentTimestampKey, + kUADSDeviceInfoTimeZoneOffsetKey, + kUADSDeviceInfoBuiltSDKVersionKey, + kUADSDeviceInfoAnalyticSessionIDKey, + kUADSDeviceInfoAnalyticUserIDKey, + kUADSDeviceInfoSessionIdKey, + kUADSDeviceInfoReaderAUIDKey + ]]; } - - (NSArray *)expectedKeysFromDefaultInfo { - return [self.expectedKeysFromDefaultMinInfo arrayByAddingObjectsFromArray: @[ - kUADSDeviceInfoReaderBundleIDKey, - kUADSDeviceInfoReaderBundleVersionKey, - kUADSDeviceInfoReaderConnectionTypeKey, - kUADSDeviceInfoReaderNetworkTypeKey, - kUADSDeviceInfoReaderScreenHeightKey, - kUADSDeviceInfoReaderScreenWidthKey, - kUADSDeviceInfoReaderEncryptedKey, - kUADSDeviceInfoReaderRootedKey, - kUADSDeviceInfoReaderOSVersionKey, - kUADSDeviceInfoReaderDeviceModelKey, - kUADSDeviceInfoReaderLanguageKey, - kUADSDeviceInfoReaderIsTestModeKey, - kUADSDeviceInfoReaderFreeMemoryKey, - kUADSDeviceInfoReaderBatteryStatusKey, - kUADSDeviceInfoReaderBatteryLevelKey, - kUADSDeviceInfoReaderScreenBrightnessKey, - kUADSDeviceInfoReaderVolumeKey, - kUADSDeviceInfoDeviceFreeSpaceKey, - kUADSDeviceInfoDeviceTotalSpaceKey, - kUADSDeviceInfoDeviceTotalMemoryKey, - kUADSDeviceInfoDeviceDeviceNameKey, - kUADSDeviceInfoDeviceLocaleListKey, - kUADSDeviceInfoDeviceCurrentUiThemeKey, - kUADSDeviceInfoDeviceAdNetworkPlistKey, - kUADSDeviceInfoDeviceIsWiredHeadsetOnKey, - kUADSDeviceInfoDeviceSystemBootTimeKey, - kUADSDeviceInfoDeviceNetworkOperatorKey, - kUADSDeviceInfoDeviceNetworkOperatorNameKey, - kUADSDeviceInfoDeviceScreenScaleKey, - kUADSDeviceInfoIsSimulatorKey, - kUADSDeviceInfoLimitTimeZoneKey, - kUADSDeviceInfoLimitStoresKey, - kUADSDeviceInfoCPUCountKey, - kUADSDeviceInfoWebViewAgentKey, - kUADSDeviceInfoAppStartTimestampKey, - kUADSDeviceInfoAppInForegroundKey, - kUADSDeviceInfoCurrentTimestampKey, - kUADSDeviceInfoTimeZoneOffsetKey, - kUADSDeviceInfoBuiltSDKVersionKey, - kUADSDeviceInfoAnalyticSessionIDKey, - kUADSDeviceInfoAnalyticUserIDKey - ]]; + return [self expectedKeysFromDefaultInfoWithUserNonBehavioral: true]; } +- (NSArray *)allExpectedKeysWithNonBehavioral: (BOOL)withUserNonBehavioral { + return [[self expectedKeysFromDefaultInfoWithUserNonBehavioral: withUserNonBehavioral] arrayByAddingObjectsFromArray:self.expectedMergedDataRealStorage.allKeys]; +}; - (NSArray *)allExpectedKeys { - return [self.expectedKeysFromDefaultInfo arrayByAddingObjectsFromArray: self.expectedMergedDataRealStorage.allKeys]; + return [self allExpectedKeysWithNonBehavioral: true]; } - (void)validateDataContains: (NSDictionary *)data allKeys: (NSArray *)keys { NSUInteger counter = data.allKeys.count > keys.count ? data.allKeys.count : keys.count; NSArray *inputSorted = data.allKeys.defaultSorted; NSArray *expected = keys.defaultSorted; - + for (int i = 0; i < counter; i++) { id receivedElement = [inputSorted uads_getItemSafelyAtIndex: i]; id expectedElement = [expected uads_getItemSafelyAtIndex: i]; XCTAssertEqualObjects(receivedElement, expectedElement, @"Expect %@ to be equal to %@ at index: %i", receivedElement, expectedElement, i); - + if (![receivedElement isEqual: expectedElement]) { break; } @@ -399,7 +413,7 @@ - (UADSMetric *)privacyRequestLatencyMetrics { - (UADSMetric *)privacyRequestFailureWithReason: (UADSPrivacyLoaderError)reason { NSMutableDictionary *tags = [NSMutableDictionary dictionary]; - + tags[@"reason"] = uads_privacyErrorTypeToString(reason); [tags addEntriesFromDictionary: self.retryTags]; return [UADSPrivacyMetrics newPrivacyRequestErrorLatency: tags]; diff --git a/Tests/UnityAdsTests/Core/Device/HeaderBiddingTokenReader/UADSAsyncTokenWithPrivacyIntegrationTests.m b/Tests/UnityAdsTests/Core/Device/HeaderBiddingTokenReader/UADSAsyncTokenWithPrivacyIntegrationTests.m index c882584c..d6756830 100644 --- a/Tests/UnityAdsTests/Core/Device/HeaderBiddingTokenReader/UADSAsyncTokenWithPrivacyIntegrationTests.m +++ b/Tests/UnityAdsTests/Core/Device/HeaderBiddingTokenReader/UADSAsyncTokenWithPrivacyIntegrationTests.m @@ -34,6 +34,11 @@ - (void)setUp { _configurationReaderMock = [UADSConfigurationReaderMock new]; [self deleteConfigFile]; [_infoTester clearAllStorages]; + UADSServiceProviderContainer.sharedInstance.serviceProvider = _serviceProvider; +} + +- (void)tearDown { + UADSServiceProviderContainer.sharedInstance.serviceProvider = [UADSServiceProvider new]; } - (void)test_returns_null_invalid_token_when_sdk_not_initialized { @@ -75,6 +80,7 @@ - (void)run_test_with_privacy_wait: (BOOL)privacyWait makeConfigFail: (BOOL)configFail shouldReturnContextual: (BOOL)isContextual { [_infoTester commitAllTestData]; + [_infoTester commitNonBehavioral:true]; self.webRequestFactoryMock.expectedRequestData = @[ privacyFail ? [NSData new] : _configTester.successPayloadPrivacy.uads_jsonData, configFail ? [NSData new] : _configTester.successPayload.uads_jsonData @@ -130,7 +136,7 @@ - (void)validateIfTokenContextual: (UADSHeaderBiddingToken *)token isContextual: } - (NSArray *)contextualTokenKeys { - return _infoTester.allExpectedKeys; + return [_infoTester allExpectedKeysWithNonBehavioral: false]; } - (NSArray *)behavioralTokenKeys { diff --git a/Tests/UnityAdsTests/Core/Device/HeaderBiddingTokenReader/UADSHeaderBiddingTokenReaderSwiftBridgeTestCase.m b/Tests/UnityAdsTests/Core/Device/HeaderBiddingTokenReader/UADSHeaderBiddingTokenReaderSwiftBridgeTestCase.m new file mode 100644 index 00000000..10c93c7c --- /dev/null +++ b/Tests/UnityAdsTests/Core/Device/HeaderBiddingTokenReader/UADSHeaderBiddingTokenReaderSwiftBridgeTestCase.m @@ -0,0 +1,38 @@ +#import +#import "UADSHeaderBiddingTokenReaderSwiftBridge.h" + +@interface UADSHeaderBiddingTokenReaderSwiftBridgeTestCase : XCTestCase + +@end + +@implementation UADSHeaderBiddingTokenReaderSwiftBridgeTestCase + +- (void)setUp { + [self saveConfigurationWithSwiftDeviceInfo:true]; +} + +- (void)tearDown { +} + +- (void)test_native_generator_in_swift_returns_token { + UADSHeaderBiddingTokenReaderSwiftBridge *bridge = [UADSHeaderBiddingTokenReaderSwiftBridge new]; + XCTestExpectation *exp = [self expectationWithDescription:@""]; + [bridge getToken:^(UADSHeaderBiddingToken * _Nullable token) { + XCTAssertNotNil(token.value); + XCTAssertGreaterThan(token.info.count, 1); + [exp fulfill]; + }]; + [self waitForExpectations:@[exp] timeout:1000.0]; +} + +- (void)saveConfigurationWithSwiftDeviceInfo:(BOOL)sDin { + USRVConfiguration *config = [USRVConfiguration newFromJSON:@{ + @"expo": @{@"s_din": @{ @"value": @(sDin)}}, + @"url": @"webviewurl", + @"hash": @"hash" + }]; + + [config saveToDisk]; +} + +@end diff --git a/Tests/UnityAdsTests/Core/Device/UADSDeviceInfoReaderExtendedIntegrationTestsCase.m b/Tests/UnityAdsTests/Core/Device/UADSDeviceInfoReaderExtendedIntegrationTestsCase.m index 2827d872..6ffeb5d3 100644 --- a/Tests/UnityAdsTests/Core/Device/UADSDeviceInfoReaderExtendedIntegrationTestsCase.m +++ b/Tests/UnityAdsTests/Core/Device/UADSDeviceInfoReaderExtendedIntegrationTestsCase.m @@ -21,7 +21,9 @@ @implementation UADSDeviceInfoReaderExtendedIntegrationTestsCase - (void)test_contains_default_device_info { [self.tester commitUserDefaultsTestData]; - NSArray *allKeys = self.tester.expectedKeysFromDefaultInfo; + [self setExpectedUserBehaviouralFlag: NO]; + + NSArray *allKeys = [self.tester expectedKeysFromDefaultInfoWithUserNonBehavioral: false]; [self.tester validateDataContains: [self getDataFromSut] allKeys: allKeys]; @@ -33,19 +35,21 @@ - (void)test_contains_default_device_info { - (void)test_contains_attributes_from_the_storage { [self.tester commitAllTestData]; + [self setExpectedUserBehaviouralFlag: NO]; [self.tester validateDataContains: [self getDataFromSut] - allKeys: [self expectedKeysNoPIIIncludeNonBehavioral: YES]]; + allKeys: [self allExpectedKeysWithNonBehavioral: false]]; [self validateMetrics: @[ self.tester.infoCollectionLatencyMetrics ]]; } -- (void)test_tracking_is_disabled_doesnt_contain_pii_attributes { +- (void)test_tracking_is_disabled_doesnt_contain_pii_attributes_no_nonbehavioural { [self.tester commitAllTestData]; + [self setExpectedUserBehaviouralFlag: NO]; [self setPrivacyResponseState: kUADSPrivacyResponseDenied]; - NSArray *allKeys = [self expectedKeysNoPIIIncludeNonBehavioral: YES]; + NSArray *allKeys = [self allExpectedKeysWithNonBehavioral: false]; [self.tester validateDataContains: [self getDataFromSut] allKeys: allKeys]; @@ -54,14 +58,44 @@ - (void)test_tracking_is_disabled_doesnt_contain_pii_attributes { ]]; } -- (void)test_tracking_is_enabled_contains_pii_attributes { + +- (void)test_tracking_is_disabled_doesnt_contain_pii_attributes_with_nonbehavioural { + [self.tester commitAllTestData]; + [self setExpectedUserBehaviouralFlag: NO]; + [self setShouldSendNonBehavioural: true]; + [self setPrivacyResponseState: kUADSPrivacyResponseDenied]; + NSArray *allKeys = [self allExpectedKeysWithNonBehavioral: true]; + + [self.tester validateDataContains: [self getDataFromSut] + allKeys: allKeys]; + [self validateMetrics: @[ + self.tester.infoCollectionLatencyMetrics + ]]; +} + +- (void)test_tracking_is_enabled_contains_pii_attributes_no_nonbehavioral { [self.tester commitAllTestData]; [self setPrivacyResponseState: kUADSPrivacyResponseAllowed]; - [self setExpectedPrivacyModeTo: kUADSPrivacyModeMixed - withUserBehaviouralFlag: NO]; + [self setExpectedUserBehaviouralFlag: NO]; + + NSArray *allKeys = [self expectedKeysWithPIIWithNonBehavioral: false]; + + [self.tester validateDataContains: [self getDataFromSut] + allKeys: allKeys]; + + [self validateMetrics: @[ + self.tester.infoCollectionLatencyMetrics + ]]; +} + +- (void)test_tracking_is_enabled_contains_pii_attributes_with_nonbehavioral { + [self.tester commitAllTestData]; + [self setPrivacyResponseState: kUADSPrivacyResponseAllowed]; + [self setShouldSendNonBehavioural: true]; + [self setExpectedUserBehaviouralFlag: NO]; - NSArray *allKeys = [self expectedKeysWithPIIIncludeNonBehavioral: YES]; + NSArray *allKeys = [self expectedKeysWithPIIWithNonBehavioral: true]; [self.tester validateDataContains: [self getDataFromSut] allKeys: allKeys]; diff --git a/Tests/UnityAdsTests/Core/Device/UADSDeviceInfoReaderIntegrationTestsCaseBase.h b/Tests/UnityAdsTests/Core/Device/UADSDeviceInfoReaderIntegrationTestsCaseBase.h index 0772432e..2985e259 100644 --- a/Tests/UnityAdsTests/Core/Device/UADSDeviceInfoReaderIntegrationTestsCaseBase.h +++ b/Tests/UnityAdsTests/Core/Device/UADSDeviceInfoReaderIntegrationTestsCaseBase.h @@ -14,15 +14,16 @@ - (NSDictionary *)getDataFromSut; - (BOOL) isDeviceInfoReaderExtended; - (void) validateMetrics: (NSArray *)expectedMetrics; -- (void)setExpectedPrivacyModeTo: (UADSPrivacyMode)mode - withUserBehaviouralFlag: (BOOL)flag; +- (void)setExpectedUserBehaviouralFlag: (BOOL)flag; - (NSDictionary *) piiExpectedData; - (void)setPrivacyResponseState: (UADSPrivacyResponseState)state; -- (NSArray *) expectedKeysNoPII; -- (NSArray *)expectedKeysWithPIIIncludeNonBehavioral: (BOOL)include; -- (NSArray *)expectedKeysMinIncludeNonBehavioral: (BOOL)include; -- (NSArray *)expectedKeysNoPIIIncludeNonBehavioral: (BOOL)include; +- (NSArray *) allExpectedKeys; +- (NSArray *)expectedKeysWithPIIWithNonBehavioral: (BOOL)withUserNonBehavioral; +- (NSArray *)expectedMinKeys; +- (NSArray *)expectedMinKeysWithoutNonBehavioral; +- (NSArray *)allExpectedKeysWithNonBehavioral: (BOOL)withUserNonBehavioral; - (NSDictionary *) piiFullContentData; +- (void)setShouldSendNonBehavioural: (BOOL)flag; @end #endif /* UADSDeviceInfoReaderIntegrationTestsCaseBase_h */ diff --git a/Tests/UnityAdsTests/Core/Device/UADSDeviceInfoReaderIntegrationTestsCaseBase.m b/Tests/UnityAdsTests/Core/Device/UADSDeviceInfoReaderIntegrationTestsCaseBase.m index 8a36cce9..5c29c36b 100644 --- a/Tests/UnityAdsTests/Core/Device/UADSDeviceInfoReaderIntegrationTestsCaseBase.m +++ b/Tests/UnityAdsTests/Core/Device/UADSDeviceInfoReaderIntegrationTestsCaseBase.m @@ -23,6 +23,7 @@ - (NSDictionary *)getDataFromSut { builder.privacyReader = self.privacyStorageMock; builder.currentTimeStampReader = [UADSCurrentTimestampMock new]; builder.gameSessionIdReader = [UADSGameSessionIdReaderBase new]; + builder.sharedSessionIdReader = [UADSSharedSessionIdReaderBase new]; id reader = builder.defaultReader; return [reader getDeviceInfoForGameMode: UADSGameModeMix]; @@ -36,10 +37,8 @@ - (void)validateMetrics: (NSArray *)expectedMetrics { XCTAssertEqualObjects(self.metricsMock.sentMetrics, expectedMetrics); } -- (void)setExpectedPrivacyModeTo: (UADSPrivacyMode)mode - withUserBehaviouralFlag: (BOOL)flag { - [self.tester commitPrivacyMode: mode - andNonBehavioral: flag]; +- (void)setExpectedUserBehaviouralFlag: (BOOL)flag { + [self.tester commitNonBehavioral: flag]; } - (NSDictionary *)piiExpectedData { @@ -59,31 +58,35 @@ - (NSDictionary *)piiFullContentData { }; } -- (NSArray *)expectedKeysNoPIIIncludeNonBehavioral: (BOOL)include { - return [_tester allExpectedKeys]; +- (NSArray *)allExpectedKeysWithNonBehavioral: (BOOL)withUserNonBehavioral { + return [_tester allExpectedKeysWithNonBehavioral: withUserNonBehavioral]; } - -- (NSArray *)expectedKeysNoPII { +- (NSArray *)allExpectedKeys { return [_tester allExpectedKeys]; } -- (NSArray *)expectedKeysWithPIIIncludeNonBehavioral: (BOOL)include { - NSArray *allKeys = self.expectedKeysNoPII; - +- (NSArray *)expectedKeysWithPIIWithNonBehavioral: (BOOL)withUserNonBehavioral { + NSArray *allKeys = [self allExpectedKeysWithNonBehavioral: withUserNonBehavioral]; allKeys = [allKeys arrayByAddingObjectsFromArray: self.piiExpectedData.allKeys]; - allKeys = [allKeys arrayByAddingObjectsFromArray: [self.tester expectedPrivacyModeKey]]; return allKeys; } -- (NSArray *)expectedKeysMinIncludeNonBehavioral: (BOOL)include { - NSArray *allKeys = self.tester.allExpectedKeysFromMinInfo; +- (NSArray *)expectedMinKeys { + return [self.tester allExpectedKeysFromMinInfoWithUserNonBehavioral:true]; +} - allKeys = [allKeys arrayByAddingObjectsFromArray: [self.tester expectedPrivacyModeKey]]; - return allKeys; +- (NSArray *)expectedMinKeysWithoutNonBehavioral { + return [self.tester allExpectedKeysFromMinInfoWithUserNonBehavioral:false]; } - (void)setPrivacyResponseState: (UADSPrivacyResponseState)state { self.privacyStorageMock.expectedState = state; } +- (void)setShouldSendNonBehavioural: (BOOL)flag { + self.privacyStorageMock.shouldSendUserNonBehavioral = flag; +} + + + @end diff --git a/Tests/UnityAdsTests/Core/Device/UADSDeviceInfoReaderIntegrationTestsLegacy.m b/Tests/UnityAdsTests/Core/Device/UADSDeviceInfoReaderIntegrationTestsLegacy.m index c071bddd..6cb2711e 100644 --- a/Tests/UnityAdsTests/Core/Device/UADSDeviceInfoReaderIntegrationTestsLegacy.m +++ b/Tests/UnityAdsTests/Core/Device/UADSDeviceInfoReaderIntegrationTestsLegacy.m @@ -10,8 +10,10 @@ @implementation UADSDeviceInfoReaderIntegrationTestsLegacy - (void)test_contains_default_device_info { [self.tester commitUserDefaultsTestData]; + [self.tester commitNonBehavioral:true]; + [self.tester validateDataContains: [self getDataFromSut] - allKeys: self.tester.expectedKeysFromDefaultInfo]; + allKeys: [self.tester expectedKeysFromDefaultInfoWithUserNonBehavioral: false]]; [self validateMetrics: @[ self.tester.infoCollectionLatencyMetrics @@ -20,7 +22,9 @@ - (void)test_contains_default_device_info { - (void)test_contains_attributes_from_the_storage { [self.tester commitAllTestData]; - NSArray *allKeys = [self.tester allExpectedKeys]; + [self.tester commitNonBehavioral:true]; + + NSArray *allKeys = [self.tester allExpectedKeysWithNonBehavioral: false]; [self.tester validateDataContains: [self getDataFromSut] allKeys: allKeys]; @@ -35,17 +39,10 @@ - (void)test_does_not_contain_attributes_from_PII_passed_by_web_view_when_non_be [[self.tester privateStorage] set: [UADSJsonStorageKeyNames piiContainerKey] value : self.piiFullContentData]; - BOOL nonBehaviouralFlag = YES; - - [self setExpectedPrivacyModeTo: kUADSPrivacyModeMixed - withUserBehaviouralFlag: nonBehaviouralFlag]; - - NSArray *allKeys = [self.tester allExpectedKeys]; - - allKeys = [allKeys arrayByAddingObjectsFromArray: [self.tester expectedPrivacyModeKey]]; + [self setExpectedUserBehaviouralFlag: YES]; [self.tester validateDataContains: [self getDataFromSut] - allKeys: allKeys]; + allKeys: [self.tester allExpectedKeysWithNonBehavioral: false]]; } @end diff --git a/Tests/UnityAdsTests/Core/Device/UADSDeviceInfoReaderMinIntegrationTestsCase.m b/Tests/UnityAdsTests/Core/Device/UADSDeviceInfoReaderMinIntegrationTestsCase.m index cb9bc491..6bced9f1 100644 --- a/Tests/UnityAdsTests/Core/Device/UADSDeviceInfoReaderMinIntegrationTestsCase.m +++ b/Tests/UnityAdsTests/Core/Device/UADSDeviceInfoReaderMinIntegrationTestsCase.m @@ -13,11 +13,26 @@ - (BOOL)isDeviceInfoReaderExtended { return false; } -- (void)test_contains_minimum_required_info_include_non_behavioural { +- (void)test_contains_minimum_required_info_include_non_behavioural_true { [self.tester commitAllTestData]; - [self setExpectedPrivacyModeTo: kUADSPrivacyModeMixed withUserBehaviouralFlag: true]; + [self setExpectedUserBehaviouralFlag: true]; [self.tester validateDataContains: [self getDataFromSut] - allKeys: [self expectedKeysMinIncludeNonBehavioral: true]]; + allKeys: [self expectedMinKeys]]; + [self validateMetrics: @[]]; +} + +- (void)test_contains_minimum_required_info_include_non_behavioural_false { + [self.tester commitAllTestData]; + [self setExpectedUserBehaviouralFlag: false]; + [self.tester validateDataContains: [self getDataFromSut] + allKeys: [self expectedMinKeys]]; + [self validateMetrics: @[]]; +} + +- (void)test_contains_minimum_required_info_does_not_include_non_behavioural { + [self.tester commitAllTestData]; + [self.tester validateDataContains: [self getDataFromSut] + allKeys: [self expectedMinKeysWithoutNonBehavioral]]; [self validateMetrics: @[]]; } diff --git a/Tests/UnityAdsTests/Core/Device/UADSGameSessionIdReaderBaseTestsCase.m b/Tests/UnityAdsTests/Core/Device/UADSGameSessionIdReaderBaseTestsCase.m index 7d2e6ba0..e84390dd 100644 --- a/Tests/UnityAdsTests/Core/Device/UADSGameSessionIdReaderBaseTestsCase.m +++ b/Tests/UnityAdsTests/Core/Device/UADSGameSessionIdReaderBaseTestsCase.m @@ -3,6 +3,7 @@ #import "USRVStorageManager.h" #import "UADSJsonStorageKeyNames.h" #import "XCTestCase+Convenience.h" +#import "UADSServiceProviderContainer.h" @interface UADSGameSessionIdReaderBaseTestsCase : XCTestCase @@ -12,6 +13,11 @@ @implementation UADSGameSessionIdReaderBaseTestsCase - (void)setUp { [self.privateStorage deleteKey: UADSJsonStorageKeyNames.webViewDataGameSessionIdKey]; + UADSServiceProviderContainer.sharedInstance.serviceProvider = [UADSServiceProvider new]; +} + +- (void)tearDown { + [self.privateStorage deleteKey: UADSJsonStorageKeyNames.webViewDataGameSessionIdKey]; } - (void)test_game_session_id_is_generated_once_and_saved_to_storage { @@ -19,8 +25,8 @@ - (void)test_game_session_id_is_generated_once_and_saved_to_storage { XCTAssertNil([self.privateStorage getValueForKey: UADSJsonStorageKeyNames.webViewDataGameSessionIdKey]); NSNumber *gameSessionId = [sut gameSessionId]; - - XCTAssertEqual([self.privateStorage getValueForKey: UADSJsonStorageKeyNames.webViewDataGameSessionIdKey], gameSessionId); + NSNumber *savedGameSessionId = [self.privateStorage getValueForKey: UADSJsonStorageKeyNames.webViewDataGameSessionIdKey]; + XCTAssertEqualObjects(savedGameSessionId, gameSessionId, "GameSessionId should be saved to storage"); XCTAssertEqual(gameSessionId, [sut gameSessionId], "Should not generate a new value"); } diff --git a/Tests/UnityAdsTests/InvocationTests.m b/Tests/UnityAdsTests/InvocationTests.m index 4eae9bde..93e0778c 100644 --- a/Tests/UnityAdsTests/InvocationTests.m +++ b/Tests/UnityAdsTests/InvocationTests.m @@ -2,6 +2,7 @@ #import #import "UnityAdsTests-Bridging-Header.h" #import "XCTestCase+Convenience.h" +#import "UnityAds+Testability.h" @interface InvocationTestsWebView : WKWebView @property (nonatomic, assign) BOOL jsInvoked; @@ -66,6 +67,8 @@ + (void)WebViewExposed_apiTestMethodNoParams: (USRVWebViewCallback *)callback { - (void)setUp { [super setUp]; + + [UnityAds resetForTest]; USRVWebViewApp *webViewApp = [[USRVWebViewApp alloc] init]; @@ -104,6 +107,8 @@ - (void)setUp { - (void)tearDown { [super tearDown]; + + [UnityAds resetForTest]; } - (void)testBasicInvocation { diff --git a/Tests/UnityAdsTests/Metrics/UADSMetricSenderTestCase.m b/Tests/UnityAdsTests/Metrics/UADSMetricSenderTestCase.m index d99dbd49..d4e4b333 100644 --- a/Tests/UnityAdsTests/Metrics/UADSMetricSenderTestCase.m +++ b/Tests/UnityAdsTests/Metrics/UADSMetricSenderTestCase.m @@ -38,11 +38,13 @@ - (void)setUp { [self clearMediationMetadata]; [USRVSdkProperties setTestMode: false]; self.sut = _serviceProvider.metricSender; + UADSServiceProviderContainer.sharedInstance.serviceProvider = _serviceProvider; } - (void)tearDown { [super tearDown]; [self deleteConfigFile]; + UADSServiceProviderContainer.sharedInstance.serviceProvider = [UADSServiceProvider new]; } - (void)test_sends_proper_performance_metrics_payload { diff --git a/Tests/UnityAdsTests/Swift/DeviceInfoBodyReader/DeviceInfoBodyReaderIntegrationTestsCaseBase.swift b/Tests/UnityAdsTests/Swift/DeviceInfoBodyReader/DeviceInfoBodyReaderIntegrationTestsCaseBase.swift new file mode 100644 index 00000000..f505c9d6 --- /dev/null +++ b/Tests/UnityAdsTests/Swift/DeviceInfoBodyReader/DeviceInfoBodyReaderIntegrationTestsCaseBase.swift @@ -0,0 +1,158 @@ +import XCTest +@testable import UnityAds + +class DeviceInfoBodyReaderIntegrationTestsCaseBase: XCTestCase { + + var tester = UADSDeviceTestsHelper() + var telephonyProviderMock = TelephonyInfoProviderMock() + var serviceProvider = UnityAdsServiceProvider() + var aggregator = USRVJsonStorageAggregator.default() + var jsonStorageBridge: JSONStorageBridge { + serviceProvider.jsonStorageObjCBridge + } + var sdkStateStorageMock = SDKStateStorageMock() + var metricsSenderMock = MetricsSenderMock() + var timeReaderMock = TimeReaderMock() + var minContentReader: StorageContentReader { + JSONStorageContentNormalizer.minStorageContentReader(with: jsonStorageBridge) + } + var extendedContentReader: StorageContentReader { + JSONStorageContentNormalizer.extendedStorageContentReader(with: jsonStorageBridge) + } + override func setUp() { + serviceProvider = UnityAdsServiceProvider(telephonyProvider: telephonyProviderMock) + sdkStateStorageMock = .init() + jsonStorageBridge.jsonStorageReaderClosure = {[weak aggregator] in + aggregator?.getValueForKey($0) + } + + jsonStorageBridge.jsonStorageReaderContentClosure = { [weak aggregator] in + (aggregator?.getContents() as? [String: Any]) ?? [:] + } + + telephonyProviderMock = .init() + tester.clearAllStorages() + } + + var deviceInfoType: DeviceInfoType = .extended + + var dataFromSut: [String: Any] { + let sessionInfoStorage = SessionInfoStorage(settings: .defaultSettings(privateStorage: jsonStorageBridge)) + let trackingStatusReader = TrackingStatusReaderBase() + let gameIdProvider = SDKGameSettingsProviderMock() + + let builderConfig = DeviceInfoBodyReaderBuilder.Config(sessionInfoStorage: sessionInfoStorage, + trackingStatusReader: trackingStatusReader, + gameSettingsReader: gameIdProvider, + sdkStateStorage: sdkStateStorageMock, + persistenceStorage: jsonStorageBridge, + logger: ConsoleLogger(), + timeReader: timeReaderMock, + telephonyInfoProvider: telephonyProviderMock, + performanceMeasurer: PerformanceMeasurer(timeReader: timeReaderMock), + metricsSender: metricsSenderMock) + + let builder = DeviceInfoBodyReaderBuilder(baseConfig: builderConfig) + + return builder.deviceInfoBodyReader.getDeviceInfoBody(of: deviceInfoType) + } + + var piiExpectedData: [String: String] { + [ + JSONStorageKeys.VendorIdentifier: "vendorIdentifier", + JSONStorageKeys.AdvertisingTrackingId: "advertisingTrackingId" + ] + } + + var allExpectedKeys: [Any] { + tester.allExpectedKeys() + } + + func allExpectedKeys(includeNonBehavioral: Bool) -> [Any] { + tester.allExpectedKeys(withNonBehavioral: includeNonBehavioral) + } + + func allExpectedKeysWithPII(includeNonBehavioral: Bool) -> [Any] { + var allKeys = tester.allExpectedKeys(withNonBehavioral: includeNonBehavioral) + allKeys.append(contentsOf: Array(piiExpectedData.keys)) + return allKeys + + } + var expectedKeysWithPII: [Any] { + var allKeys = allExpectedKeys + allKeys.append(contentsOf: Array(piiExpectedData.keys)) + return allKeys + } + + var expectedMinKeys: [Any] { + tester.allExpectedKeysFromMinInfo(withUserNonBehavioral: true) + } + + var expectedMinKeysWithoutNonBehavioral: [Any] { + tester.allExpectedKeysFromMinInfo(withUserNonBehavioral: false) + } + + func setExpectedUserBehavioralFlag(_ flag: Bool) { + tester.commitNonBehavioral(flag) + } + + func setPrivacyState(_ state: PrivacyState) { + sdkStateStorageMock.privacyState = state + } + + func setShouldSendNonBehavioural(_ flag: Bool) { + sdkStateStorageMock.shouldSendNonBehavioural = true + } + + func commitAllTestData() { + tester.commitAllTestData() + } + + func validateMetrics(_ expected: [MetricsType], file: StaticString = #filePath, line: UInt = #line) { + XCTAssertEqual(expected, metricsSenderMock.metricsStorage, file: file, line: line) + } +} + +final class SDKGameSettingsProviderMock: SDKGameSettingsProvider { + var gameID: String = "1234567890" + var isTestModeEnabled: Bool = true +} + +final class TelephonyInfoProviderMock: TelephonyInfoProvider & CountryCodeProvider { + var dynamicInfo: TelephonyInfoDynamicInfo { + .init(networkStatusString: "networkStatusString", + networkType: 1, + operatorName: "operatorName", + operatorCode: "operatorCode") + } + + var countryCode: String { + "countryCode" + } + +} + +final class MetricsSenderMock: MetricSender { + + private(set) var metricsStorage: [MetricsType] = [] + var expectedResult: UResult = VoidSuccess + func send(metrics: [MetricsType], completion: @escaping ResultClosure) { + metricsStorage.append(contentsOf: metrics) + completion(expectedResult) + } +} + +final class SDKStateStorageMock: PrivacyStateReader, ExperimentsReader, AppStartTimeProvider { + var shouldSendNonBehavioural: Bool = false + + var privacyState: PrivacyState = .denied + + var experiments: ConfigExperiments? { + try? .init(dictionary: ["s_din": true]) + } + + var appStartTime: TimeInterval { 1 } + + let privacyStorage = PrivacyStateStorage() + +} diff --git a/Tests/UnityAdsTests/Swift/DeviceInfoBodyReader/ExtendedDeviceInfoBodyReaderIntegrationTestsCaseBase.swift b/Tests/UnityAdsTests/Swift/DeviceInfoBodyReader/ExtendedDeviceInfoBodyReaderIntegrationTestsCaseBase.swift new file mode 100644 index 00000000..e3a55f85 --- /dev/null +++ b/Tests/UnityAdsTests/Swift/DeviceInfoBodyReader/ExtendedDeviceInfoBodyReaderIntegrationTestsCaseBase.swift @@ -0,0 +1,67 @@ +import XCTest +@testable import UnityAds + +class ExtendedDeviceInfoBodyReaderIntegrationTestsCaseBase: DeviceInfoBodyReaderIntegrationTestsCaseBase { + + func test_contains_default_device_info_no_nonbehavioural() { + tester.commitUserDefaultsTestData() + tester.commitNonBehavioral(true) + tester.validateDataContains(dataFromSut, + allKeys: tester.expectedKeysFromDefaultInfo(withUserNonBehavioral: false)) + validateMetrics([successLatencyMetric]) + } + + func test_contains_attributes_from_storage_no_non_behavioural() { + commitAllTestData() + tester.commitNonBehavioral(true) + tester.validateDataContains(dataFromSut, + allKeys: self.allExpectedKeys(includeNonBehavioral: false)) + validateMetrics([successLatencyMetric]) + } + + func test_tracking_is_disabled_does_not_contain_pii_attributes_no_non_behavioural() { + commitAllTestData() + tester.commitNonBehavioral(true) + setPrivacyState(.denied) + + tester.validateDataContains(dataFromSut, + allKeys: self.allExpectedKeys(includeNonBehavioral: false)) + validateMetrics([successLatencyMetric]) + } + + func test_tracking_is_disabled_does_not_contain_pii_attributes_include_non_behavioural() { + commitAllTestData() + tester.commitNonBehavioral(true) + setPrivacyState(.denied) + setShouldSendNonBehavioural(true) + + tester.validateDataContains(dataFromSut, + allKeys: self.allExpectedKeys(includeNonBehavioral: true)) + validateMetrics([successLatencyMetric]) + } + + func test_tracking_is_enabled_contains_pii_attributes_no_non_behavioral() { + commitAllTestData() + setPrivacyState(.allowed) + setExpectedUserBehavioralFlag(false) + + tester.validateDataContains(dataFromSut, + allKeys: self.allExpectedKeysWithPII(includeNonBehavioral: false)) + validateMetrics([successLatencyMetric]) + } + + func test_tracking_is_enabled_contains_pii_attributes_include_non_behavioral() { + commitAllTestData() + setPrivacyState(.allowed) + setExpectedUserBehavioralFlag(false) + setShouldSendNonBehavioural(true) + + tester.validateDataContains(dataFromSut, + allKeys: self.allExpectedKeysWithPII(includeNonBehavioral: true)) + validateMetrics([successLatencyMetric]) + } + + var successLatencyMetric: MetricsType { + .performance(.init(name: Constants.Metrics.Collection.Success, duration: 0, info: [:])) + } +} diff --git a/Tests/UnityAdsTests/Swift/DeviceInfoBodyReader/MinDeviceInfoBodyReaderIntegrationTestsCase.swift b/Tests/UnityAdsTests/Swift/DeviceInfoBodyReader/MinDeviceInfoBodyReaderIntegrationTestsCase.swift new file mode 100644 index 00000000..b4ce0799 --- /dev/null +++ b/Tests/UnityAdsTests/Swift/DeviceInfoBodyReader/MinDeviceInfoBodyReaderIntegrationTestsCase.swift @@ -0,0 +1,28 @@ +import XCTest +@testable import UnityAds + +class MinDeviceInfoBodyReaderIntegrationTestsCase: DeviceInfoBodyReaderIntegrationTestsCaseBase { + + func test_contains_minimum_required_info_include_non_behavioural_true() { + deviceInfoType = .minimal + commitAllTestData() + setExpectedUserBehavioralFlag(true) + tester.validateDataContains(dataFromSut, allKeys: expectedMinKeys) + validateMetrics([]) + } + + func test_contains_minimum_required_info_include_non_behavioural_false() { + deviceInfoType = .minimal + commitAllTestData() + setExpectedUserBehavioralFlag(false) + tester.validateDataContains(dataFromSut, allKeys: expectedMinKeys) + validateMetrics([]) + } + + func test_contains_minimum_required_info_does_notinclude_non_behavioural() { + deviceInfoType = .minimal + commitAllTestData() + tester.validateDataContains(dataFromSut, allKeys: expectedMinKeysWithoutNonBehavioral) + validateMetrics([]) + } +} diff --git a/Tests/UnityAdsTests/Swift/Initialization/IntegrationTests/LegacyFlow/SDKInitializerLegacyIntegrationTests.swift b/Tests/UnityAdsTests/Swift/Initialization/IntegrationTests/LegacyFlow/SDKInitializerLegacyIntegrationTests.swift index b2191e1b..25abda2c 100644 --- a/Tests/UnityAdsTests/Swift/Initialization/IntegrationTests/LegacyFlow/SDKInitializerLegacyIntegrationTests.swift +++ b/Tests/UnityAdsTests/Swift/Initialization/IntegrationTests/LegacyFlow/SDKInitializerLegacyIntegrationTests.swift @@ -48,7 +48,7 @@ class SDKInitializerLegacyIntegrationTests: SDKInitializerLegacyIntegrationTests var sdkMetrics: [SDKMetricType] = [ .legacy(.initStarted), - .legacy(.latency(.intoCollection)), + .legacy(.latency(.infoCollection)), .legacy(.latency(.infoCompression)), .legacy(.missed(.token)), .legacy(.missed(.stateID)), @@ -100,7 +100,7 @@ class SDKInitializerLegacyIntegrationTests: SDKInitializerLegacyIntegrationTests ] let configRequestMetrics: [SDKMetricType] = [ - .legacy(.latency(.intoCollection)), + .legacy(.latency(.infoCollection)), .legacy(.latency(.infoCompression)), .legacy(.latency(.configRequestFailure)) @@ -181,7 +181,7 @@ class SDKInitializerLegacyIntegrationTests: SDKInitializerLegacyIntegrationTests let allConfigMetrics: [SDKMetricType] = stride(from: 0, to: configResponses.count, by: 1).flatMap({_ in [ - .legacy(.latency(.intoCollection)), + .legacy(.latency(.infoCollection)), .legacy(.latency(.infoCompression)), .legacy(.latency(.configRequestFailure)) ] @@ -218,7 +218,7 @@ class SDKInitializerLegacyIntegrationTests: SDKInitializerLegacyIntegrationTests var sdkMetrics: [SDKMetricType] = [ .legacy(.initStarted), - .legacy(.latency(.intoCollection)), + .legacy(.latency(.infoCollection)), .legacy(.latency(.infoCompression)), .legacy(.latency(.configRequestSuccess)), .legacy(.missed(.token)), @@ -270,7 +270,7 @@ class SDKInitializerLegacyIntegrationTests: SDKInitializerLegacyIntegrationTests var sdkMetrics: [SDKMetricType] = [ .legacy(.initStarted), - .legacy(.latency(.intoCollection)), + .legacy(.latency(.infoCollection)), .legacy(.latency(.infoCompression)), .legacy(.latency(.configRequestSuccess)), .legacy(.missed(.token)), @@ -316,7 +316,7 @@ class SDKInitializerLegacyIntegrationTests: SDKInitializerLegacyIntegrationTests var sdkMetrics: [SDKMetricType] = [ .legacy(.initStarted), - .legacy(.latency(.intoCollection)), + .legacy(.latency(.infoCollection)), .legacy(.latency(.infoCompression)), .legacy(.latency(.configRequestSuccess)), .legacy(.missed(.token)), @@ -367,7 +367,7 @@ class SDKInitializerLegacyIntegrationTests: SDKInitializerLegacyIntegrationTests var sdkMetrics: [SDKMetricType] = [ .legacy(.initStarted), - .legacy(.latency(.intoCollection)), + .legacy(.latency(.infoCollection)), .legacy(.latency(.infoCompression)), .legacy(.latency(.configRequestSuccess)), .legacy(.missed(.token)), @@ -412,7 +412,7 @@ class SDKInitializerLegacyIntegrationTests: SDKInitializerLegacyIntegrationTests var sdkMetrics: [SDKMetricType] = [ .legacy(.initStarted), - .legacy(.latency(.intoCollection)), + .legacy(.latency(.infoCollection)), .legacy(.latency(.infoCompression)), .legacy(.latency(.configRequestSuccess)), .legacy(.missed(.token)), @@ -454,7 +454,8 @@ class SDKInitializerLegacyIntegrationTests: SDKInitializerLegacyIntegrationTests expectedNumberOfRequests: 0, multithreadCount: stressCount, metrics: [], - expectDiagnostic: true) + expectDiagnostic: true, + validateStartTimeStamp: false) try executeTest(with: testConfig, resultValidation: { XCTAssertSuccess($0) }) @@ -469,7 +470,8 @@ class SDKInitializerLegacyIntegrationTests: SDKInitializerLegacyIntegrationTests expectedNumberOfRequests: 0, multithreadCount: stressCount, metrics: [], - expectDiagnostic: true) + expectDiagnostic: true, + validateStartTimeStamp: false) try executeTest(with: testConfig, resultValidation: { XCTAssertFailure($0, expectedError: "The operation couldn’t be completed. (UnityAdsTests.MockedError error 1.)") diff --git a/Tests/UnityAdsTests/Swift/Initialization/IntegrationTests/ObjCBridges/JSONStorageContentNormalizerTests.swift b/Tests/UnityAdsTests/Swift/Initialization/IntegrationTests/ObjCBridges/JSONStorageContentNormalizerTests.swift new file mode 100644 index 00000000..a2017870 --- /dev/null +++ b/Tests/UnityAdsTests/Swift/Initialization/IntegrationTests/ObjCBridges/JSONStorageContentNormalizerTests.swift @@ -0,0 +1,118 @@ +import XCTest +@testable import UnityAds + +final class JSONStorageContentNormalizerTests: XCTestCase { + + var storageMock = KeyValueStorageMock() + + func test_normalizes_dictionary_nothing_excludes_keys() { + let content = contentFromSutUsing(rootLevelKeysInclude: [], + excludeKeys: [], + skipReduceKeys: []) + XCTAssertEqual(content, expectedFlattenDataSet) + + } + + func test_flat_nested_dictionary_nothing_excludes_keys() { + let content = contentFromSutUsing(rootLevelKeysInclude: [], + excludeKeys: ["ts"], + skipReduceKeys: []) + XCTAssertEqual(content, expectedFlattenDataSetExcludeTS) + } + + func test_flat_nested_dictionary_nothing_excludes_keys_and_reduce_and_filters() { + let content = contentFromSutUsing(rootLevelKeysInclude: ["mediation"], + excludeKeys: ["ts"], + skipReduceKeys: ["value"]) + XCTAssertEqual(content, expectedFlattenDataSetReduced) + } + + private func contentFromSutUsing(rootLevelKeysInclude: [String], + excludeKeys: [String], + skipReduceKeys: [String]) -> [String: String] { + let sut = sutWith(rootLevelKeysInclude: rootLevelKeysInclude, + excludeKeys: excludeKeys, + skipReduceKeys: skipReduceKeys) + return sut.allContent.mapValues { "\($0)" } + } + + private func sutWith(rootLevelKeysInclude: [String], + excludeKeys: [String], + skipReduceKeys: [String]) -> JSONStorageContentNormalizer { + storageMock.storage = testDataSet + return .init(config: .init(original: storageMock, + rootLevelKeysInclude: rootLevelKeysInclude, + excludeKeys: excludeKeys, + reduceKeys: skipReduceKeys)) + } + +} + +extension JSONStorageContentNormalizerTests { + var expectedFlattenDataSetExcludeTS: [String: String] { + [ + "mediation.adapterVersion.value": "adapter_version", + "mediation.name.value": "Mediation name", + "mediation.version.value": "version", + + "framework.name.value": "name", + "framework.version.value": "version" + ].mapValues({ "\($0)" }) + } + + var expectedFlattenDataSetReduced: [String: String] { + [ + "mediation.adapterVersion": "adapter_version", + "mediation.name": "Mediation name", + "mediation.version": "version" + ].mapValues({ "\($0)" }) + } + + var expectedFlattenDataSet: [String: String] { + [ + "mediation.adapterVersion.value": "adapter_version", + "mediation.name.value": "Mediation name", + "mediation.version.value": "version", + + "mediation.adapterVersion.ts": 1_642_615_489_109, + "mediation.name.ts": 1_642_615_489_109, + "mediation.version.ts": 1_642_615_489_109, + + "framework.name.ts": 1_642_615_489_109, + "framework.name.value": "name", + "framework.version.ts": 1_642_615_489_109, + "framework.version.value": "version" + ].mapValues({ "\($0)" }) + } + + var testDataSet: AnyDictionary { + [ + "mediation": [ + "adapterVersion": [ + "ts": 1_642_615_489_109, + "value": "adapter_version" + ], + + "name": [ + "ts": 1_642_615_489_109, + "value": "Mediation name" + ], + "version": [ + "ts": 1_642_615_489_109, + "value": "version" + ] + ], + "framework": [ + "name": [ + "ts": 1_642_615_489_109, + "value": "name" + ], + "version": [ + "ts": 1_642_615_489_109, + "value": "version" + ] + ] + ] + } + +} diff --git a/Tests/UnityAdsTests/Swift/Initialization/IntegrationTests/ObjCBridges/SDKObjCBridgesTests.swift b/Tests/UnityAdsTests/Swift/Initialization/IntegrationTests/ObjCBridges/SDKObjCBridgesTests.swift new file mode 100644 index 00000000..96a6c7bb --- /dev/null +++ b/Tests/UnityAdsTests/Swift/Initialization/IntegrationTests/ObjCBridges/SDKObjCBridgesTests.swift @@ -0,0 +1,51 @@ +import XCTest +@testable import UnityAds +final class SDKObjCBridgesTests: SDKInitializerLegacyIntegrationTestsBase { + + private var jsonStorageAggregator: USRVJsonStorage { + storageManagerType.getStorage(.private) + } + + private var storageManager: USRVStorageManager = USRVStorageManager.sharedInstance() + private var storageManagerType: USRVStorageManager.Type { + type(of: storageManager) + } + let key = "RandomKey" + let testValue = "testValue" + override func setUpWithError() throws { + try super.setUpWithError() + resetStorage() + } + + override func tearDownWithError() throws { + try super.tearDownWithError() + resetStorage() + } + func test_no_value_written() { + let received: String = tester.serviceProvider.jsonStorageObjCBridge.getValue(for: key) ?? "" + XCTAssertEqual("", received) + } + + func test_json_storage_set_in_obj_read_in_swift() { + jsonStorageAggregator.set(key, value: testValue) + let received: String = tester.serviceProvider.jsonStorageObjCBridge.getValue(for: key) ?? "" + XCTAssertEqual(testValue, received) + } + + func test_json_storage_set_in_swift_read_in_objc() { + tester.serviceProvider.jsonStorageObjCBridge.saveValue(value: testValue, forKey: key) + let received: String = jsonStorageAggregator.getValueForKey(key) as? String ?? "" + XCTAssertEqual(testValue, received) + } + + private func resetStorage() { + let paths = [storageManagerType.getStorage(.public), + storageManagerType.getStorage(.private)] + paths.lazy + .compactMap({ $0 }) + .forEach({ + $0.clear() + $0.initStorage() + }) + } +} diff --git a/Tests/UnityAdsTests/Swift/Initialization/IntegrationTests/Parallel/SDKInitializerParallelFlowIntegrationTests.swift b/Tests/UnityAdsTests/Swift/Initialization/IntegrationTests/Parallel/SDKInitializerParallelFlowIntegrationTests.swift index 438acac2..57ae2c73 100644 --- a/Tests/UnityAdsTests/Swift/Initialization/IntegrationTests/Parallel/SDKInitializerParallelFlowIntegrationTests.swift +++ b/Tests/UnityAdsTests/Swift/Initialization/IntegrationTests/Parallel/SDKInitializerParallelFlowIntegrationTests.swift @@ -7,6 +7,7 @@ final class SDKInitializerParallelFlowIntegrationTests: SDKInitializerLegacyInte override var defaultExperiments: [String: Bool] { var dictionary = super.defaultExperiments dictionary["s_pte"] = true + dictionary["s_din"] = true return dictionary } @@ -36,6 +37,44 @@ final class SDKInitializerParallelFlowIntegrationTests: SDKInitializerLegacyInte } + func test_init_fails_when_privacy_fails_with_defined_codes() throws { + let expectedFailureCode = 423 + let expectedConfig = try configMockFactory.defaultUnityAdsConfig(experiments: defaultExperiments) + let privacyResponseError = NSError(domain: "network", code: expectedFailureCode) + let responses: [URLProtocolResponseStub] = [ + .init(error: privacyResponseError) + ] + + var sdkMetrics: [SDKMetricType] = [ + .legacy(.initStarted) + ] + + let sdkPerformanceMetrics: [SDKMetricType] = [ + .requestPerformance(.failure(.privacy)), + .taskPerformance(.failure(.initializer)), + .taskPerformance(.success(.loadLocalConfig)), + .taskPerformance(.failure(.privacyFetch)), + .taskPerformance(.success(.initModules)), + .taskPerformance(.success(.reset)) + ] + + sdkMetrics += sdkPerformanceMetrics + let testConfig = TestConfig(responses: responses, + sdkConfig: expectedConfig, + expectedNumberOfRequests: responses.count, + multithreadCount: 1, + metrics: sdkMetrics, + expectDiagnostic: true) + try executeTest(with: testConfig, + resultValidation: { XCTAssertFailure($0) }, + final: { + + let error = self.extractErrorFromState(self.tester.sdkState) + + XCTAssertEqual(error as? PrivacyError, .gameIdDisabled) + }) + } + func test_init_fails_with_error_when_config_has_corrupted_data() throws { let corruptedConfig = try ["key": "value"].serializedData() @@ -50,8 +89,8 @@ final class SDKInitializerParallelFlowIntegrationTests: SDKInitializerLegacyInte var sdkMetrics: [SDKMetricType] = [ .legacy(.initStarted) ] let configRequestMetrics: [SDKMetricType] = [ - .legacy(.latency(.intoCollection)), .systemPerformance(.success(.compression)), + .systemPerformance(.success(.infoCollection)), .requestPerformance(.failure(.config)) ] @@ -95,8 +134,8 @@ final class SDKInitializerParallelFlowIntegrationTests: SDKInitializerLegacyInte let sdkMetrics: [SDKMetricType] = [ .legacy(.initStarted), - .legacy(.latency(.intoCollection)), .systemPerformance(.success(.compression)), + .systemPerformance(.success(.infoCollection)), .requestPerformance(.failure(.config)), .requestPerformance(.success(.privacy)), .taskPerformance(.success(.webViewDownload)), @@ -135,10 +174,10 @@ final class SDKInitializerParallelFlowIntegrationTests: SDKInitializerLegacyInte let sdkMetrics: [SDKMetricType] = [ .legacy(.initStarted), - .legacy(.latency(.intoCollection)), .legacy(.missed(.token)), .legacy(.missed(.stateID)), .systemPerformance(.success(.compression)), + .systemPerformance(.success(.infoCollection)), .requestPerformance(.success(.privacy)), .requestPerformance(.success(.config)), .taskPerformance(.success(.loadLocalConfig)), @@ -184,10 +223,10 @@ final class SDKInitializerParallelFlowIntegrationTests: SDKInitializerLegacyInte let sdkMetrics: [SDKMetricType] = [ .legacy(.initStarted), - .legacy(.latency(.intoCollection)), .legacy(.missed(.token)), .legacy(.missed(.stateID)), .systemPerformance(.success(.compression)), + .systemPerformance(.success(.infoCollection)), .requestPerformance(.success(.privacy)), .requestPerformance(.success(.config)), .taskPerformance(.success(.loadLocalConfig)), @@ -226,10 +265,10 @@ final class SDKInitializerParallelFlowIntegrationTests: SDKInitializerLegacyInte let sdkMetrics: [SDKMetricType] = [ .legacy(.initStarted), - .legacy(.latency(.intoCollection)), .legacy(.missed(.token)), .legacy(.missed(.stateID)), .systemPerformance(.success(.compression)), + .systemPerformance(.success(.infoCollection)), .taskPerformance(.success(.loadLocalConfig)), .requestPerformance(.success(.privacy)), .requestPerformance(.success(.config)), @@ -273,10 +312,10 @@ final class SDKInitializerParallelFlowIntegrationTests: SDKInitializerLegacyInte let sdkMetrics: [SDKMetricType] = [ .legacy(.initStarted), - .legacy(.latency(.intoCollection)), .legacy(.missed(.token)), .legacy(.missed(.stateID)), .systemPerformance(.success(.compression)), + .systemPerformance(.success(.infoCollection)), .requestPerformance(.success(.privacy)), .requestPerformance(.success(.config)), .taskPerformance(.success(.loadLocalConfig)), @@ -314,13 +353,13 @@ final class SDKInitializerParallelFlowIntegrationTests: SDKInitializerLegacyInte var sdkMetrics: [SDKMetricType] = [ .legacy(.initStarted), - .legacy(.latency(.intoCollection)), .legacy(.missed(.token)), .legacy(.missed(.stateID)) ] let sdkPerformanceMetrics: [SDKMetricType] = [ .systemPerformance(.success(.compression)), + .systemPerformance(.success(.infoCollection)), .requestPerformance(.success(.privacy)), .requestPerformance(.success(.config)), .taskPerformance(.success(.loadLocalConfig)), @@ -357,7 +396,8 @@ final class SDKInitializerParallelFlowIntegrationTests: SDKInitializerLegacyInte expectedNumberOfRequests: 0, multithreadCount: stressCount, metrics: [], - expectDiagnostic: true) + expectDiagnostic: true, + validateStartTimeStamp: false) try executeTest(with: testConfig, resultValidation: { XCTAssertSuccess($0) }) @@ -372,7 +412,8 @@ final class SDKInitializerParallelFlowIntegrationTests: SDKInitializerLegacyInte expectedNumberOfRequests: 0, multithreadCount: stressCount, metrics: [], - expectDiagnostic: true) + expectDiagnostic: true, + validateStartTimeStamp: false) try executeTest(with: testConfig, resultValidation: { XCTAssertFailure($0, expectedError: "The operation couldn’t be completed. (UnityAdsTests.MockedError error 1.)") @@ -397,13 +438,13 @@ final class SDKInitializerParallelFlowIntegrationTests: SDKInitializerLegacyInte var sdkMetrics: [SDKMetricType] = [ .legacy(.initStarted), - .legacy(.latency(.intoCollection)), .legacy(.missed(.token)), .legacy(.missed(.stateID)) ] let sdkPerformanceMetrics: [SDKMetricType] = [ .systemPerformance(.success(.compression)), + .systemPerformance(.success(.infoCollection)), .requestPerformance(.success(.privacy)), .requestPerformance(.success(.config)), .taskPerformance(.success(.loadLocalConfig)), @@ -446,8 +487,8 @@ final class SDKInitializerParallelFlowIntegrationTests: SDKInitializerLegacyInte let configRequestMetrics: [SDKMetricType] = [ .systemPerformance(.success(.compression)), + .systemPerformance(.success(.infoCollection)), .requestPerformance(.success(.config)), - .legacy(.latency(.intoCollection)), .legacy(.missed(.token)), .legacy(.missed(.stateID)) ] @@ -490,8 +531,8 @@ final class SDKInitializerParallelFlowIntegrationTests: SDKInitializerLegacyInte let configRequestMetrics: [SDKMetricType] = [ .systemPerformance(.success(.compression)), + .systemPerformance(.success(.infoCollection)), .requestPerformance(.success(.config)), - .legacy(.latency(.intoCollection)), .legacy(.missed(.token)), .legacy(.missed(.stateID)) ] @@ -536,13 +577,13 @@ final class SDKInitializerParallelFlowIntegrationTests: SDKInitializerLegacyInte var sdkMetrics: [SDKMetricType] = [ .legacy(.initStarted), - .legacy(.latency(.intoCollection)), .legacy(.missed(.token)), .legacy(.missed(.stateID)) ] let sdkPerformanceMetrics: [SDKMetricType] = [ .systemPerformance(.success(.compression)), + .systemPerformance(.success(.infoCollection)), .requestPerformance(.success(.privacy)), .requestPerformance(.success(.config)), .taskPerformance(.success(.loadLocalConfig)), diff --git a/Tests/UnityAdsTests/Swift/Initialization/IntegrationTests/SequentialFlow/SDKInitializerSequentialFlowIntegrationTests.swift b/Tests/UnityAdsTests/Swift/Initialization/IntegrationTests/SequentialFlow/SDKInitializerSequentialFlowIntegrationTests.swift index 6b241fce..d329914e 100644 --- a/Tests/UnityAdsTests/Swift/Initialization/IntegrationTests/SequentialFlow/SDKInitializerSequentialFlowIntegrationTests.swift +++ b/Tests/UnityAdsTests/Swift/Initialization/IntegrationTests/SequentialFlow/SDKInitializerSequentialFlowIntegrationTests.swift @@ -6,9 +6,14 @@ import XCTest class SDKInitializerSequentialFlowIntegrationTests: SDKInitializerLegacyIntegrationTestsBase { + var useSwiftInfoCollection = true + override var defaultExperiments: [String: Bool] { var dictionary = super.defaultExperiments dictionary["s_ntf"] = true + if useSwiftInfoCollection { + dictionary["s_din"] = true + } return dictionary } @@ -27,7 +32,8 @@ class SDKInitializerSequentialFlowIntegrationTests: SDKInitializerLegacyIntegrat expectedNumberOfRequests: responses.count, multithreadCount: 1, metrics: ExpectedMetrics.SequentialFlow.HappyPath, - expectDiagnostic: true) + expectDiagnostic: true, + validateStartTimeStamp: false) try executeTest(with: testConfig, resultValidation: { XCTAssertSuccess($0) }, final: { @@ -48,8 +54,8 @@ class SDKInitializerSequentialFlowIntegrationTests: SDKInitializerLegacyIntegrat var sdkMetrics: [SDKMetricType] = [ .legacy(.initStarted) ] let configRequestMetrics: [SDKMetricType] = [ - .legacy(.latency(.intoCollection)), .systemPerformance(.success(.compression)), + .systemPerformance(.success(.infoCollection)), .requestPerformance(.failure(.config)) ] @@ -89,8 +95,8 @@ class SDKInitializerSequentialFlowIntegrationTests: SDKInitializerLegacyIntegrat var sdkMetrics: [SDKMetricType] = [ .legacy(.initStarted) ] let configRequestMetrics: [SDKMetricType] = [ - .legacy(.latency(.intoCollection)), .systemPerformance(.success(.compression)), + .systemPerformance(.success(.infoCollection)), .requestPerformance(.success(.config)), .legacy(.missed(.token)), .legacy(.missed(.stateID)) @@ -122,6 +128,44 @@ class SDKInitializerSequentialFlowIntegrationTests: SDKInitializerLegacyIntegrat } + func test_init_fails_when_privacy_fails_with_defined_codes() throws { + let expectedFailureCode = 423 + let expectedConfig = try configMockFactory.defaultUnityAdsConfig(experiments: defaultExperiments) + let privacyResponseError = NSError(domain: "network", code: expectedFailureCode) + let responses: [URLProtocolResponseStub] = [ + .init(error: privacyResponseError) + ] + + var sdkMetrics: [SDKMetricType] = [ + .legacy(.initStarted) + ] + + let sdkPerformanceMetrics: [SDKMetricType] = [ + .requestPerformance(.failure(.privacy)), + .taskPerformance(.failure(.initializer)), + .taskPerformance(.success(.loadLocalConfig)), + .taskPerformance(.failure(.privacyFetch)), + .taskPerformance(.success(.initModules)), + .taskPerformance(.success(.reset)) + ] + + sdkMetrics += sdkPerformanceMetrics + let testConfig = TestConfig(responses: responses, + sdkConfig: expectedConfig, + expectedNumberOfRequests: responses.count, + multithreadCount: 1, + metrics: sdkMetrics, + expectDiagnostic: true) + try executeTest(with: testConfig, + resultValidation: { XCTAssertFailure($0) }, + final: { + + let error = self.extractErrorFromState(self.tester.sdkState) + + XCTAssertEqual(error as? PrivacyError, .gameIdDisabled) + }) + } + func test_init_fails_with_error_when_privacy_fails_and_config_has_empty_webview_url() throws { var expectedConfigDict = configMockFactory.defaultConfigJSON(experiments: defaultExperiments) expectedConfigDict["url"] = "" @@ -132,7 +176,7 @@ class SDKInitializerSequentialFlowIntegrationTests: SDKInitializerLegacyIntegrat var sdkMetrics: [SDKMetricType] = [ .legacy(.initStarted) ] let configRequestMetrics: [SDKMetricType] = [ - .legacy(.latency(.intoCollection)), + .systemPerformance(.success(.infoCollection)), .systemPerformance(.success(.compression)), .requestPerformance(.success(.config)), .legacy(.missed(.token)), @@ -177,12 +221,12 @@ class SDKInitializerSequentialFlowIntegrationTests: SDKInitializerLegacyIntegrat var sdkMetrics: [SDKMetricType] = [ .legacy(.initStarted), - .legacy(.latency(.intoCollection)), .legacy(.missed(.token)), .legacy(.missed(.stateID)) ] let sdkPerformanceMetrics: [SDKMetricType] = [ + .systemPerformance(.success(.infoCollection)), .systemPerformance(.success(.compression)), .requestPerformance(.success(.privacy)), .requestPerformance(.success(.config)), @@ -222,8 +266,8 @@ class SDKInitializerSequentialFlowIntegrationTests: SDKInitializerLegacyIntegrat let sdkMetrics: [SDKMetricType] = [ .legacy(.initStarted), - .legacy(.latency(.intoCollection)), .systemPerformance(.success(.compression)), + .systemPerformance(.success(.infoCollection)), .requestPerformance(.failure(.config)), .requestPerformance(.success(.privacy)), .taskPerformance(.success(.loadLocalConfig)), @@ -265,10 +309,10 @@ class SDKInitializerSequentialFlowIntegrationTests: SDKInitializerLegacyIntegrat let sdkMetrics: [SDKMetricType] = [ .legacy(.initStarted), - .legacy(.latency(.intoCollection)), .legacy(.missed(.token)), .legacy(.missed(.stateID)), .systemPerformance(.success(.compression)), + .systemPerformance(.success(.infoCollection)), .requestPerformance(.success(.privacy)), .requestPerformance(.success(.config)), .taskPerformance(.success(.loadLocalConfig)), @@ -314,10 +358,10 @@ class SDKInitializerSequentialFlowIntegrationTests: SDKInitializerLegacyIntegrat let sdkMetrics: [SDKMetricType] = [ .legacy(.initStarted), - .legacy(.latency(.intoCollection)), .legacy(.missed(.token)), .legacy(.missed(.stateID)), .systemPerformance(.success(.compression)), + .systemPerformance(.success(.infoCollection)), .requestPerformance(.success(.privacy)), .requestPerformance(.success(.config)), .taskPerformance(.success(.loadLocalConfig)), @@ -357,10 +401,10 @@ class SDKInitializerSequentialFlowIntegrationTests: SDKInitializerLegacyIntegrat let sdkMetrics: [SDKMetricType] = [ .legacy(.initStarted), - .legacy(.latency(.intoCollection)), .legacy(.missed(.token)), .legacy(.missed(.stateID)), .systemPerformance(.success(.compression)), + .systemPerformance(.success(.infoCollection)), .taskPerformance(.success(.loadLocalConfig)), .requestPerformance(.success(.privacy)), .requestPerformance(.success(.config)), @@ -389,7 +433,11 @@ class SDKInitializerSequentialFlowIntegrationTests: SDKInitializerLegacyIntegrat }) } - func test_init_succeed_no_web_view_download_when_the_same_in_cache() throws { + func test_init_succeed_no_web_view_download_when_the_same_in_cache_legacy_info() throws { + useSwiftInfoCollection = false + let config = try configMockFactory.defaultUnityAdsConfig(experiments: defaultExperiments) + try saveConfigToFile(config) + resetTester() let expectedNumberOfRequests = 2 try tester.saveDefaultFakeWebViewDataToFile() @@ -405,7 +453,7 @@ class SDKInitializerSequentialFlowIntegrationTests: SDKInitializerLegacyIntegrat let sdkMetrics: [SDKMetricType] = [ .legacy(.initStarted), - .legacy(.latency(.intoCollection)), + .legacy(.latency(.infoCollection)), .legacy(.missed(.token)), .legacy(.missed(.stateID)), .systemPerformance(.success(.compression)), @@ -446,13 +494,13 @@ class SDKInitializerSequentialFlowIntegrationTests: SDKInitializerLegacyIntegrat var sdkMetrics: [SDKMetricType] = [ .legacy(.initStarted), - .legacy(.latency(.intoCollection)), .legacy(.missed(.token)), .legacy(.missed(.stateID)) ] let sdkPerformanceMetrics: [SDKMetricType] = [ .systemPerformance(.success(.compression)), + .systemPerformance(.success(.infoCollection)), .requestPerformance(.success(.privacy)), .requestPerformance(.success(.config)), .taskPerformance(.success(.loadLocalConfig)), @@ -489,7 +537,8 @@ class SDKInitializerSequentialFlowIntegrationTests: SDKInitializerLegacyIntegrat expectedNumberOfRequests: 0, multithreadCount: stressCount, metrics: [], - expectDiagnostic: true) + expectDiagnostic: true, + validateStartTimeStamp: false) try executeTest(with: testConfig, resultValidation: { XCTAssertSuccess($0) }) @@ -504,7 +553,8 @@ class SDKInitializerSequentialFlowIntegrationTests: SDKInitializerLegacyIntegrat expectedNumberOfRequests: 0, multithreadCount: stressCount, metrics: [], - expectDiagnostic: true) + expectDiagnostic: true, + validateStartTimeStamp: false) try executeTest(with: testConfig, resultValidation: { XCTAssertFailure($0, expectedError: "The operation couldn’t be completed. (UnityAdsTests.MockedError error 1.)") @@ -534,4 +584,16 @@ class SDKInitializerSequentialFlowIntegrationTests: SDKInitializerLegacyIntegrat }) } + + func test_returns_error_if_game_id_is_not_number() throws { + let expectedConfig = try configMockFactory.defaultUnityAdsConfig(experiments: defaultExperiments) + let testConfig = TestConfig(responses: [], + initializeConfig: SDKInitializerConfig(gameID: "notnumber", isTestModeEnabled: true), + sdkConfig: expectedConfig, + validateStartTimeStamp: false) + try executeTest(with: testConfig, + resultValidation: { + XCTAssertFailure($0, expectedError: InvalidGameId().localizedDescription) + }) + } } diff --git a/Tests/UnityAdsTests/Swift/Initialization/Legacy/InitializationTaskSequenceLegacyTests.swift b/Tests/UnityAdsTests/Swift/Initialization/Legacy/InitializationTaskSequenceLegacyTests.swift index 6596bf4f..80b9dafe 100644 --- a/Tests/UnityAdsTests/Swift/Initialization/Legacy/InitializationTaskSequenceLegacyTests.swift +++ b/Tests/UnityAdsTests/Swift/Initialization/Legacy/InitializationTaskSequenceLegacyTests.swift @@ -1,16 +1,6 @@ import XCTest @testable import UnityAds -private struct ExperimentsReaderMock: ExperimentsReader, SessionTokenReader { - let expectedExp: [String: Any] - let sessionToken = "" - - var experiments: ConfigExperiments? { - try? .init(dictionary: expectedExp) - - } -} - final class InitializationTaskSequenceLegacyTests: XCTestCase { private func sut(with exp: [String: Any]) -> IndexingIterator<[InitTaskCategory]> { diff --git a/Tests/UnityAdsTests/Swift/Initialization/Tasks/InitModulesTaskTests.swift b/Tests/UnityAdsTests/Swift/Initialization/Tasks/InitModulesTaskTests.swift new file mode 100644 index 00000000..5d6ee1b1 --- /dev/null +++ b/Tests/UnityAdsTests/Swift/Initialization/Tasks/InitModulesTaskTests.swift @@ -0,0 +1,76 @@ +import XCTest +@testable import UnityAds + +final class InitModulesTaskTests: XCTestCase { + + private var deviceInfoReaderMock = DeviceInfoReaderMock() + private var sut: InitModulesTask { + .init(legacyTask: LegacyTaskMock(), + deviceInfoReader: deviceInfoReaderMock) + } + + func test_init_calls_static_device_info() { + XCTAssertEqual(deviceInfoReaderMock.staticInfoCalledTimes, 0) + sut.start { _ in + XCTAssertEqual(self.deviceInfoReaderMock.staticInfoCalledTimes, 1) + } + } +} + +final class DeviceInfoReaderMock: DeviceInfoReader, DeviceInfoBodyStrategy { + func initializeStaticInfo() { + staticInfoCalledTimes += 1 + } + + var expected: [String: Any] = [:] + + func getDeviceInfoBody(of type: DeviceInfoType) -> [String: Any] { + return expected + } + + var staticInfoCalledTimes = 0 + + var countryCode: String = "" + + var osName: String = "osName" + + var deviceInfo: DeviceInfo { + DeviceInfo(staticInfo: staticInfo, + dynamic: dynamicInfo, + countryIso: countryCode) + } + + var staticInfo: StaticDeviceInfo { + return StaticDeviceInfo(bundle: Bundle.main.staticInfo, + screen: UIScreen.main.staticInfo, + device: UIDevice.current.staticInfo, + userAgent: "") + } + var dynamicInfo: DynamicDeviceInfo { + DynamicDeviceInfo(deviceInfo: UIDevice.current.dynamicInfo, + screenInfo: UIScreen.main.dynamicInfo, + telephonyInfo: TelephonyInfoDynamicInfo(networkStatusString: "", networkType: 0, operatorName: "", operatorCode: ""), + audioInfo: AVAudioSession.sharedInstance().dynamicInfo, + timeInfo: AppTimeInfo(appStartTime: 0, + appUptime: 0, + timeZoneOffset: 0, + timeZone: "", + systemBootTime: 0, + currentTimestamp: 0), + localeInfo: LocaleStaticInfo(language: "", preferredLocale: ""), + sessionInfo: .empty, + appStateInfo: GameStateInfo(startTime: 0, isTestModeEnabled: false, isActive: true), + connectionType: "") + } +} + +extension SessionInfo { + static var empty: Self { + .init(sessionID: "", + gameSessionID: 0, + analyticsSessionID: "", + analyticsUserID: "", + idfi: "", + userNonBehavioralFlag: false) + } +} diff --git a/Tests/UnityAdsTests/Swift/Initialization/Tasks/Mocks/LegacyTaskMock.swift b/Tests/UnityAdsTests/Swift/Initialization/Tasks/Mocks/LegacyTaskMock.swift new file mode 100644 index 00000000..d5adf93a --- /dev/null +++ b/Tests/UnityAdsTests/Swift/Initialization/Tasks/Mocks/LegacyTaskMock.swift @@ -0,0 +1,13 @@ +import Foundation +@testable import UnityAds + +final class LegacyTaskMock: PerformanceMeasurableTask { + func start(completion: @escaping ResultClosure) { + completion(VoidSuccess) + } + + var resultMetrics: ResultMetrics.Type { Constants.Metrics.Task.Reset.self } + + var startEventName: String? + +} diff --git a/Tests/UnityAdsTests/Swift/Initialization/Tasks/PreviousSessionCleanupTaskTests.swift b/Tests/UnityAdsTests/Swift/Initialization/Tasks/PreviousSessionCleanupTaskTests.swift index d5153278..9e738807 100644 --- a/Tests/UnityAdsTests/Swift/Initialization/Tasks/PreviousSessionCleanupTaskTests.swift +++ b/Tests/UnityAdsTests/Swift/Initialization/Tasks/PreviousSessionCleanupTaskTests.swift @@ -4,10 +4,14 @@ import XCTest final class PreviousSessionCleanupTaskTests: XCTestCase { private var loggerSettingsReader: LoggerSettingsReader = SDKSettingsStorage() + private var storageMock = KeyValueStorageMock() + private var cleanupKeys = ["test", "test2"] private var sut: PreviousSessionCleanupTask { .init(loggerSettingsReader: loggerSettingsReader, fileManager: fileManager, - legacyTask: LegacyTaskMock()) + legacyTask: TaskMock(), + storage: storageMock, + cleanupKeys: cleanupKeys) } private var fileManager = FileManager.default @@ -16,12 +20,14 @@ final class PreviousSessionCleanupTaskTests: XCTestCase { } override func setUpWithError() throws { loggerSettingsReader = SDKSettingsStorage() + storageMock = KeyValueStorageMock() try? fileManager.deleteFile(at: loggerSettingsReader.logsFileURL) } func test_task_deletes_dump_file() throws { + verifyNoTestDataSaved() + saveTestDataForKeys() XCTAssertEqual(dumpFileExists, false) - try fileManager.saveStringToFile("test", toFile: loggerSettingsReader.logsFileURL) XCTAssertEqual(dumpFileExists, true) let exp = defaultExpectation @@ -32,16 +38,21 @@ final class PreviousSessionCleanupTaskTests: XCTestCase { wait(for: [exp], timeout: 1) XCTAssertEqual(dumpFileExists, false) + verifyNoTestDataSaved() + XCTAssertEqual(storageMock.deleteCount, cleanupKeys.count) } -} -private class LegacyTaskMock: PerformanceMeasurableTask { - func start(completion: @escaping ResultClosure) { - completion(VoidSuccess) + func verifyNoTestDataSaved() { + cleanupKeys.forEach { + let data: String? = storageMock.getValue(for: $0) + XCTAssertNil(data) + } } - var resultMetrics: ResultMetrics.Type { Constants.Metrics.Task.Reset.self } - - var startEventName: String? - + func saveTestDataForKeys() { + cleanupKeys.forEach { + storageMock.saveValue(value: "test", forKey: $0) + XCTAssertNotNil(storageMock.getValue(for: $0)) + } + } } diff --git a/Tests/UnityAdsTests/Swift/Initialization/Tasks/StartInitTaskTests.swift b/Tests/UnityAdsTests/Swift/Initialization/Tasks/StartInitTaskTests.swift new file mode 100644 index 00000000..d801a49f --- /dev/null +++ b/Tests/UnityAdsTests/Swift/Initialization/Tasks/StartInitTaskTests.swift @@ -0,0 +1,71 @@ +import XCTest +@testable import UnityAds +// swiftlint:disable discouraged_optional_boolean + +// time reader into integration to test multithread. +final class AppStartTimeSaverMock: AppStartTimeSaver { + var startTime: TimeInterval = 0 + func save(startTime: TimeInterval) { + self.startTime = startTime + } +} + +final class LoggerMock: Logger { + var loggedRecords = [LogRecord]() + + func logRecord(_ record: LogRecord) { + loggedRecords.append(record) + } +} + +final class SessionInfoReaderMock: SessionInfoReader { + var auid: String = "auid" + var sessionID: String = "sessionID" + var gameSessionID: Int64 = 1 + var analyticsSessionID: String = "analyticsSessionID" + var analyticsUserID: String = "analyticsUserID" + var idfi: String = "idfi" + var userNonBehavioralFlag: Bool? + + var sessionInfo: SessionInfo { + .init(sessionID: sessionID, + gameSessionID: gameSessionID, + analyticsSessionID: analyticsSessionID, + analyticsUserID: analyticsUserID, + idfi: idfi, + userNonBehavioralFlag: userNonBehavioralFlag) + } +} + +final class StartInitTaskTests: XCTestCase { + var taskFactoryMock = InitTaskFactoryMock() + var timeReaderMock = TimeReaderMock() + var appStartTimeSaverMock = AppStartTimeSaverMock() + var loggerMock = LoggerMock() + var settingsMock = SDKGameSettingsProviderMock() + var sessionInfoReaderMock = SessionInfoReaderMock() + + var sut: StartInitTask { + StartInitTask(factory: taskFactoryMock, + sequence: ["doesnt mater"], + timeReader: timeReaderMock, + appStartTimeSaver: appStartTimeSaverMock, + logger: loggerMock, + settingProvider: settingsMock, + sessionInfoReader: sessionInfoReaderMock) + } + + override func setUpWithError() throws { + taskFactoryMock = InitTaskFactoryMock() + timeReaderMock = TimeReaderMock() + appStartTimeSaverMock = AppStartTimeSaverMock() + } + + func test_calls_reader_saver_and_task() { + sut.start(completion: { _ in }) + XCTAssertEqual(taskFactoryMock.taskMock.startCalled, 1) + XCTAssertEqual(timeReaderMock.currentTimeStampCalled, 1) + XCTAssertEqual(appStartTimeSaverMock.startTime, timeReaderMock.expectedInterval) + XCTAssertEqual(loggerMock.loggedRecords.count, 1, "Should have log init message") + } +} diff --git a/Tests/UnityAdsTests/Swift/TestTools/IntegrationTests/SDKInitializerLegacyIntegrationTestsBase.swift b/Tests/UnityAdsTests/Swift/TestTools/IntegrationTests/SDKInitializerLegacyIntegrationTestsBase.swift index d48633be..45bec71e 100644 --- a/Tests/UnityAdsTests/Swift/TestTools/IntegrationTests/SDKInitializerLegacyIntegrationTestsBase.swift +++ b/Tests/UnityAdsTests/Swift/TestTools/IntegrationTests/SDKInitializerLegacyIntegrationTestsBase.swift @@ -4,7 +4,7 @@ import XCTest @testable import UnityAds class SDKInitializerLegacyIntegrationTestsBase: XCMultiThreadTestCase { - let defaultTimeout: TimeInterval = 1 + let defaultTimeout: TimeInterval = 30 let concurrentQueue = DispatchQueue(label: "SDKInitializerLegacyIntegrationTestsBase.queue", qos: .background, attributes: .concurrent) @@ -31,11 +31,15 @@ class SDKInitializerLegacyIntegrationTestsBase: XCMultiThreadTestCase { } func resetTester() { + _tester = .init(useExampleConfig: useExampleConfig) + _tester?.resetStubs() + } override func tearDown() { - USRVApiSdk.setServiceProviderForTesting(UADSServiceProvider()) + UADSServiceProviderContainer.sharedInstance().serviceProvider = .init() + resetTester() } func saveConfigToFile(_ config: UnityAdsConfig) throws { @@ -78,13 +82,16 @@ extension SDKInitializerLegacyIntegrationTestsBase { expectation.expectedFulfillmentCount = config.multithreadCount + additionalFulfillmentCount let validator = tester.metricsValidator - tester.metricProtocolStub.requestObserver = { [weak validator]_ in + let metricsObserver: Closure = {[weak validator]_ in guard let validator = validator else { fatalError() } if validator.receivedCount >= types.count { expectation.fulfill() } + } + tester.metricProtocolStub.$requestObserver.setNewValue(metricsObserver) + setNetworkResponses(config.responses) multiThreadTest(stressCount: config.multithreadCount, @@ -102,13 +109,21 @@ extension SDKInitializerLegacyIntegrationTestsBase { webViewRetried: config.webviewRetried, file: file, line: line) - XCTAssertEqual(tester.networkRequests.count, config.expectedNumberOfRequests, file: file, line: line) -// XCTAssertEqual(self.tester.serviceProvider.sdkStateStorage.config, -// config.sdkConfig, -// file: file, -// line: line) - final?() + XCTAssertEqual(tester.networkRequests.count, + config.expectedNumberOfRequests, + file: file, + line: line) + if config.validateStartTimeStamp { + XCTAssertEqual(tester.timeStampReaderMock.expectedInterval, + tester.serviceProvider.sdkStateStorage.appStartTime, + file: file, + line: line) + } + final?() + tester.metricProtocolStub.$requestObserver.mutate({ + $0 = nil + }) } var defaultExperiments: [String: Bool] { @@ -126,7 +141,7 @@ extension SDKInitializerLegacyIntegrationTestsBase { struct TestConfig { let responses: [URLProtocolResponseStub] - var initializeConfig: SDKInitializerConfig = .init(gameID: "GameID") + var initializeConfig: SDKInitializerConfig = .init(gameID: "12345", isTestModeEnabled: false) let sdkConfig: UnityAdsConfig var expectedNumberOfRequests: Int = 0 var multithreadCount: Int = 1 @@ -134,6 +149,7 @@ extension SDKInitializerLegacyIntegrationTestsBase { var configRetried = 0 var webviewRetried = 0 var expectDiagnostic: Bool = true + var validateStartTimeStamp = true } func verifyWebExposedGetTrrData(_ config: UnityAdsConfig) { @@ -154,6 +170,14 @@ extension SDKInitializerLegacyIntegrationTestsBase { XCTFail("Didn't receive config data with WebViewExposed_getTrrData") } } + + func extractErrorFromState(_ state: SDKInitializerBase.State) -> Error? { + guard case let .failed(error) = state else { + return nil + } + + return error + } } extension LegacySDKConfig: Equatable { diff --git a/Tests/UnityAdsTests/Swift/TestTools/IntegrationTests/SDKNetworkTestsHelper.swift b/Tests/UnityAdsTests/Swift/TestTools/IntegrationTests/SDKNetworkTestsHelper.swift index d9080a61..c15f08f9 100644 --- a/Tests/UnityAdsTests/Swift/TestTools/IntegrationTests/SDKNetworkTestsHelper.swift +++ b/Tests/UnityAdsTests/Swift/TestTools/IntegrationTests/SDKNetworkTestsHelper.swift @@ -71,6 +71,7 @@ final class SDKNetworkTestsHelper { metricProtocolStub.requests } + private(set) var timeStampReaderMock = TimeReaderMock() let useExampleConfig: Bool init(useExampleConfig: Bool) { @@ -86,7 +87,8 @@ final class SDKNetworkTestsHelper { settings.metricsResourceTypes = [] // include all types settings.allowDumpToFile = false settings.currentLevel = .fatal - serviceProvider = .init(skdSettingsStorage: settings) + serviceProvider = .init(skdSettingsStorage: settings, + timeReader: timeStampReaderMock) serviceProvider.legacyStateFactory = initStateFactoryMock initStateFactoryMock.original = uadsServiceProvider.stateFactory @@ -96,9 +98,9 @@ final class SDKNetworkTestsHelper { resetStubs() resetCache() serviceProvider.sdkStateStorage.config = .default - serviceProvider.skdSettingsStorage.currentInitConfig = .init(gameID: "") + serviceProvider.skdSettingsStorage.$currentInitConfig.mutate({ $0 = .init(gameID: "", isTestModeEnabled: false) }) serviceProvider.sdkStateStorage.currentState = .notInitialized - USRVApiSdk.setServiceProviderForTesting(uadsServiceProvider) + UADSServiceProviderContainer.sharedInstance().serviceProvider = uadsServiceProvider } func resetStubs() { @@ -190,7 +192,7 @@ final class SDKNetworkTestsHelper { file: StaticString = #filePath, line: UInt = #line) throws { guard !metrics.isEmpty else { return } - var tags: [String: String] = ["c_retry": "\(configRetried)", + let tags: [String: String] = ["c_retry": "\(configRetried)", "wv_retry": "\(webViewRetried)"] let withRetryTags = metrics.filter { type in diff --git a/Tests/UnityAdsTests/Swift/TestTools/MetricValidator/MetricTypes/SDKMetricType.swift b/Tests/UnityAdsTests/Swift/TestTools/MetricValidator/MetricTypes/SDKMetricType.swift index 10cace79..ce488b7e 100644 --- a/Tests/UnityAdsTests/Swift/TestTools/MetricValidator/MetricTypes/SDKMetricType.swift +++ b/Tests/UnityAdsTests/Swift/TestTools/MetricValidator/MetricTypes/SDKMetricType.swift @@ -120,9 +120,11 @@ extension SDKMetricType { var resultMetrics: ResultMetrics.Type { switch self { case .compression: return Constants.Metrics.Compression.self + case .infoCollection: return Constants.Metrics.Collection.self } } case compression + case infoCollection } diff --git a/Tests/UnityAdsTests/Swift/TestTools/MetricValidator/MetricTypes/SDKMetricTypeLegacy.swift b/Tests/UnityAdsTests/Swift/TestTools/MetricValidator/MetricTypes/SDKMetricTypeLegacy.swift index 12c264c7..1e5560a6 100644 --- a/Tests/UnityAdsTests/Swift/TestTools/MetricValidator/MetricTypes/SDKMetricTypeLegacy.swift +++ b/Tests/UnityAdsTests/Swift/TestTools/MetricValidator/MetricTypes/SDKMetricTypeLegacy.swift @@ -31,7 +31,7 @@ extension SDKMetricType.Legacy { case configRequestSuccess case privacyRequestSuccess case configRequestFailure - case intoCollection + case infoCollection case infoCompression } @@ -99,7 +99,7 @@ extension SDKMetricType.Legacy.Latency: LegacyMetricConvertible { return UADSTsiMetric.newTokenResolutionRequestLatency(nil, tags: [:]) case .configRequestFailure: return UADSTsiMetric.newTokenResolutionRequestFailureLatency([:]) - case .intoCollection: + case .infoCollection: return UADSTsiMetric.newDeviceInfoCollectionLatency(0) case .infoCompression: return UADSTsiMetric.newDeviceInfoCompressionLatency(0) diff --git a/Tests/UnityAdsTests/Swift/TestTools/Mocks/ExperimentsReaderMock.swift b/Tests/UnityAdsTests/Swift/TestTools/Mocks/ExperimentsReaderMock.swift new file mode 100644 index 00000000..4a5f0282 --- /dev/null +++ b/Tests/UnityAdsTests/Swift/TestTools/Mocks/ExperimentsReaderMock.swift @@ -0,0 +1,12 @@ +import Foundation +@testable import UnityAds + +struct ExperimentsReaderMock: ExperimentsReader, SessionTokenReader { + let expectedExp: [String: Any] + let sessionToken = "" + + var experiments: ConfigExperiments? { + try? .init(dictionary: expectedExp) + + } +} diff --git a/Tests/UnityAdsTests/Swift/TestTools/Mocks/Factories/InitTaskFactoryMock.swift b/Tests/UnityAdsTests/Swift/TestTools/Mocks/Factories/InitTaskFactoryMock.swift new file mode 100644 index 00000000..7f846888 --- /dev/null +++ b/Tests/UnityAdsTests/Swift/TestTools/Mocks/Factories/InitTaskFactoryMock.swift @@ -0,0 +1,12 @@ +import Foundation +@testable import UnityAds + +final class InitTaskFactoryMock: TaskFactory { + var taskMock = TaskMock() + func task(of type: String) -> Task { + return taskMock + } + + typealias Element = String + +} diff --git a/Tests/UnityAdsTests/Swift/TestTools/Mocks/Metrcis/ExpectedMetrics.swift b/Tests/UnityAdsTests/Swift/TestTools/Mocks/Metrcis/ExpectedMetrics.swift index 248dd3f2..2668d108 100644 --- a/Tests/UnityAdsTests/Swift/TestTools/Mocks/Metrcis/ExpectedMetrics.swift +++ b/Tests/UnityAdsTests/Swift/TestTools/Mocks/Metrcis/ExpectedMetrics.swift @@ -6,9 +6,9 @@ struct ExpectedMetrics { extension ExpectedMetrics { struct LegacyFlow { static var HappyPath: [SDKMetricType] { - var sdkMetrics: [SDKMetricType] = [ + let sdkMetrics: [SDKMetricType] = [ .legacy(.initStarted), - .legacy(.latency(.intoCollection)), + .legacy(.latency(.infoCollection)), .legacy(.latency(.infoCompression)), .legacy(.missed(.token)), .legacy(.missed(.stateID)), @@ -34,7 +34,7 @@ extension ExpectedMetrics { static var HappyPath: [SDKMetricType] { var sdkMetrics: [SDKMetricType] = [ .legacy(.initStarted), - .legacy(.latency(.intoCollection)), + .legacy(.latency(.infoCollection)), .legacy(.latency(.infoCompression)), .legacy(.missed(.token)), .legacy(.missed(.stateID)), @@ -64,13 +64,13 @@ extension ExpectedMetrics { static var HappyPath: [SDKMetricType] { var sdkMetrics: [SDKMetricType] = [ .legacy(.initStarted), - .legacy(.latency(.intoCollection)), .legacy(.missed(.token)), .legacy(.missed(.stateID)) ] let sdkPerformanceMetrics: [SDKMetricType] = [ .systemPerformance(.success(.compression)), + .systemPerformance(.success(.infoCollection)), .requestPerformance(.success(.privacy)), .requestPerformance(.success(.config)), .taskPerformance(.success(.loadLocalConfig)), @@ -96,13 +96,13 @@ extension ExpectedMetrics { static var HappyPath: [SDKMetricType] { var sdkMetrics: [SDKMetricType] = [ .legacy(.initStarted), - .legacy(.latency(.intoCollection)), .legacy(.missed(.token)), .legacy(.missed(.stateID)) ] let sdkPerformanceMetrics: [SDKMetricType] = [ .systemPerformance(.success(.compression)), + .systemPerformance(.success(.infoCollection)), .requestPerformance(.success(.privacy)), .requestPerformance(.success(.config)), .taskPerformance(.success(.loadLocalConfig)), diff --git a/Tests/UnityAdsTests/Swift/TestTools/Mocks/Network/URLProtocolMetricsNetworkStub.swift b/Tests/UnityAdsTests/Swift/TestTools/Mocks/Network/URLProtocolMetricsNetworkStub.swift index 2e2a0945..790e6cac 100644 --- a/Tests/UnityAdsTests/Swift/TestTools/Mocks/Network/URLProtocolMetricsNetworkStub.swift +++ b/Tests/UnityAdsTests/Swift/TestTools/Mocks/Network/URLProtocolMetricsNetworkStub.swift @@ -10,7 +10,7 @@ final class URLProtocolMetricsNetworkStub: URLProtocolStubBase { override class func clear() { super.clear() - requestObserver = nil + _requestObserver.mutate({ $0 = nil }) } override class func appendRequest(_ urlRequest: URLRequest) { @@ -38,6 +38,6 @@ final class URLProtocolMetricsNetworkStub: URLProtocolStubBase { } override func beforeResponse() { - Self.requestObserver?(request) + Self._requestObserver.load()?(request) } } diff --git a/Tests/UnityAdsTests/Swift/TestTools/Mocks/Storage/KeyValueStorageMock.swift b/Tests/UnityAdsTests/Swift/TestTools/Mocks/Storage/KeyValueStorageMock.swift new file mode 100644 index 00000000..006d19ae --- /dev/null +++ b/Tests/UnityAdsTests/Swift/TestTools/Mocks/Storage/KeyValueStorageMock.swift @@ -0,0 +1,29 @@ +import Foundation +@testable import UnityAds + +final class KeyValueStorageMock: KeyValueStorage, StorageContentReader { + var allContent: [String: Any] { + storage + } + + var storage: [String: Any] = [:] + private(set) var saveCount = 0 + private(set) var getCount = 0 + private(set) var deleteCount = 0 + + func saveValue(value: T, forKey key: String) { + saveCount += 1 + storage[key] = value + } + + func getValue(for key: String) -> T? { + getCount += 1 + return storage[key] as? T + } + + func delete(forKey key: String) { + deleteCount += 1 + storage[key] = nil + } + +} diff --git a/Tests/UnityAdsTests/Swift/TestTools/Mocks/Tasks/TaskMock.swift b/Tests/UnityAdsTests/Swift/TestTools/Mocks/Tasks/TaskMock.swift new file mode 100644 index 00000000..6f47c549 --- /dev/null +++ b/Tests/UnityAdsTests/Swift/TestTools/Mocks/Tasks/TaskMock.swift @@ -0,0 +1,15 @@ +import Foundation +@testable import UnityAds + +final class TaskMock: PerformanceMeasurableTask { + private(set) var startCalled = 0 + func start(completion: @escaping ResultClosure) { + startCalled += 1 + completion(VoidSuccess) + } + + var resultMetrics: ResultMetrics.Type { Constants.Metrics.Task.Reset.self } + + var startEventName: String? + +} diff --git a/Tests/UnityAdsTests/Swift/TestTools/Mocks/TimeReaderMock.swift b/Tests/UnityAdsTests/Swift/TestTools/Mocks/TimeReaderMock.swift new file mode 100644 index 00000000..968fd788 --- /dev/null +++ b/Tests/UnityAdsTests/Swift/TestTools/Mocks/TimeReaderMock.swift @@ -0,0 +1,26 @@ +import Foundation +@testable import UnityAds + +final class TimeReaderMock: TimeReader, BootTimeReader, TimeZoneReader { + var timeZoneOffset: Int = 10 + + var expectedTimeZone = "TimeZone" + + func formattedTimeZone(daylightSavingTime: Bool) -> String { + expectedTimeZone + } + + var elapsedRealTime: UInt64 = 1 + + var upTime: TimeInterval = 2 + + var bootTime: TimeInterval = 3 + + var expectedInterval: TimeInterval = 4 + var currentTimeStampCalled = 0 + func currentTimestamp(in: TimeReaderInterval) -> TimeInterval { + currentTimeStampCalled += 1 + return expectedInterval + } + +} diff --git a/Tests/UnityAdsTests/Swift/TestTools/Network/NetworkTestCaseBase.swift b/Tests/UnityAdsTests/Swift/TestTools/Network/NetworkTestCaseBase.swift index f7d32a48..0fe08cd2 100644 --- a/Tests/UnityAdsTests/Swift/TestTools/Network/NetworkTestCaseBase.swift +++ b/Tests/UnityAdsTests/Swift/TestTools/Network/NetworkTestCaseBase.swift @@ -59,10 +59,11 @@ class NetworkTestCaseBase: XCTestCase { func verifyMetricsRequest(observer: @escaping Closure) -> XCTestExpectation { let expectation = expectation(description: "\(self)-Metrics") - networkTester.metricProtocolStub.requestObserver = { request in + let requestObserver: Closure = { request in observer(request) expectation.fulfill() } + networkTester.metricProtocolStub.$requestObserver.setNewValue(requestObserver) return expectation } diff --git a/Tests/UnityAdsTests/Swift/Token/HeaderBiddingTokenReaderTestsCase.swift b/Tests/UnityAdsTests/Swift/Token/HeaderBiddingTokenReaderTestsCase.swift new file mode 100644 index 00000000..7741d061 --- /dev/null +++ b/Tests/UnityAdsTests/Swift/Token/HeaderBiddingTokenReaderTestsCase.swift @@ -0,0 +1,47 @@ +import XCTest +@testable import UnityAds + +class HeaderBiddingTokenReaderTestsCase: XCTestCase { + + var deviceInfoBodyReaderMock = DeviceInfoReaderMock() + var uniqueGeneratorMock = UniqueGeneratorMock() + var experimentsDict: [String: String] = [:] + + var sut: HeaderBiddingTokenReader { + let experimentsMock = ExperimentsReaderMock(expectedExp: experimentsDict) + return HeaderBiddingTokenReaderBase( + .init(deviceInfoReader: deviceInfoBodyReaderMock, + compressor: Base64GzipCompressor(dataCompressor: GZipCompressor()), + customPrefix: "1:", + uniqueIdGenerator: uniqueGeneratorMock, + experiments: experimentsMock) + ) + } + + func test_returns_token_without_tid() throws { + deviceInfoBodyReaderMock.expected = ["key": "value"] + experimentsDict = [:] + try runTestWithExpectedToken("1:H4sIAAAAAAAAE6tWyk6tVLJSKkvMKU1VqgUAv5wYPw8AAAA=") + } + + func test_returns_token_with_tid() throws { + deviceInfoBodyReaderMock.expected = [:] + uniqueGeneratorMock.uniqueID = "1" + experimentsDict = ["scar_bm": "eag"] + try runTestWithExpectedToken("1:H4sIAAAAAAAAE6tWKslMUbJSMlSqBQCgUV/nCwAAAA==") + } + + func runTestWithExpectedToken(_ expected: String) throws { + let exp = defaultExpectation + try sut.getToken { token in + XCTAssertEqual(token.value, expected) + exp.fulfill() + } + wait(for: [exp], timeout: 1.0) + } + +} + +final class UniqueGeneratorMock: UniqueGenerator { + var uniqueID: String = "" +} diff --git a/Tests/UnityAdsTests/Swift/UnityServicesIdentifiersTests/Mocks/MockIdStore.swift b/Tests/UnityAdsTests/Swift/UnityServicesIdentifiersTests/Mocks/MockIdStore.swift deleted file mode 100644 index 6276820e..00000000 --- a/Tests/UnityAdsTests/Swift/UnityServicesIdentifiersTests/Mocks/MockIdStore.swift +++ /dev/null @@ -1,23 +0,0 @@ -import Foundation - -@testable import UnityAds - -class MockIdStore: UADSIdStore { - var getValueCallHistory: [[Any]] = [] - var commitValueCallHistory: [[Any]] = [] - let value: String? - - init(value: String?) { - self.value = value - } - - func getValue() -> String? { - getValueCallHistory.append([]) - return value - } - - func commitValue(_ value: String) { - commitValueCallHistory.append([value]) - } - -} diff --git a/Tests/UnityAdsTests/Swift/UnityServicesIdentifiersTests/UADSInstallationIdExtension.h b/Tests/UnityAdsTests/Swift/UnityServicesIdentifiersTests/UADSInstallationIdExtension.h deleted file mode 100644 index 939184ff..00000000 --- a/Tests/UnityAdsTests/Swift/UnityServicesIdentifiersTests/UADSInstallationIdExtension.h +++ /dev/null @@ -1,14 +0,0 @@ -#import "UADSIdStore.h" -#import "UADSInstallationId.h" - -NS_ASSUME_NONNULL_BEGIN - -@interface UADSInstallationId (Tests) - -- (instancetype)initWithInstallationIdStore:(id)installationIdStore - analyticsIdStore:(id)analyticsIdStore - unityAdsIdStore:(id)unityAdsIdStore; - -@end - -NS_ASSUME_NONNULL_END diff --git a/Tests/UnityAdsTests/Swift/UnityServicesIdentifiersTests/UADSInstallationIdTests.swift b/Tests/UnityAdsTests/Swift/UnityServicesIdentifiersTests/UADSInstallationIdTests.swift deleted file mode 100644 index 4876f150..00000000 --- a/Tests/UnityAdsTests/Swift/UnityServicesIdentifiersTests/UADSInstallationIdTests.swift +++ /dev/null @@ -1,195 +0,0 @@ -import Foundation -import XCTest - -@testable import UnityAds - -class UADSInstallationIdTests: XCTestCase { - - override func setUp() { - self.tearDownUserDefaults() - do { - try self.tearDownPlayerPrefs() - } catch { - // Do Nothing - } - } - - override func tearDown() { - self.tearDownUserDefaults() - do { - try self.tearDownPlayerPrefs() - } catch { - // Do Nothing - } - } - - func setupPlayerPrefs() { - let playerPrefsStore = UADSUnityPlayerPrefsStore(key: "UnityInstallationId") - playerPrefsStore.commitValue("PlayerPrefsTestInstallationId") - } - - func setupAnalyticsId() { - let analyticsPrefsStore = UADSUnityPlayerPrefsStore(key: "unity.cloud_userid") - analyticsPrefsStore.commitValue("AnalyticsPlayerPrefsTestInstallationId") - } - - func setupUnityAdsId() { - let unityAdsStore = UADSUserDefaultsStore(key: "unityads-idfi") - unityAdsStore.commitValue("UnityAdsUserDefaultsTestInstallationId") - } - - func tearDownPlayerPrefs() throws { - let bundleIdentifier = Bundle.main.bundleIdentifier ?? "" - let filePath = NSString(string: "~/Library/Preferences/\(bundleIdentifier).plist") - .expandingTildeInPath - let url = URL(fileURLWithPath: filePath) - try FileManager.default.removeItem(at: url) - } - - func tearDownUserDefaults() { - UserDefaults.standard.removeObject(forKey: "unityads-idfi") - } - - func testShared() { - let shared = UADSInstallationId.shared() - - XCTAssertNotNil(shared) - } - - func testPlayerPrefsIntegration() { - self.setupPlayerPrefs() - let installationId = UADSInstallationId() - - let id = installationId.installationId() - XCTAssertEqual(id, "PlayerPrefsTestInstallationId") - XCTAssertEqual(installationId.installationId(), id) - } - - func testAnalyticsPlayerPrefsIntegration() { - self.setupAnalyticsId() - let installationId = UADSInstallationId() - - let id = installationId.installationId() - XCTAssertEqual(id, "AnalyticsPlayerPrefsTestInstallationId") - XCTAssertEqual(installationId.installationId(), id) - } - - func testUnityAdsUserDefaultsIntegration() { - self.setupUnityAdsId() - let installationId = UADSInstallationId() - - let id = installationId.installationId() - XCTAssertEqual(id, "UnityAdsUserDefaultsTestInstallationId") - XCTAssertEqual(installationId.installationId(), id) - } - - func testNoId() { - let installationIdStore = MockIdStore(value: nil) - let analyticsIdStore = MockIdStore(value: nil) - let unityAdsIdStore = MockIdStore(value: nil) - let installationId = UADSInstallationId( - installationIdStore: installationIdStore, - analyticsIdStore: analyticsIdStore, - unityAdsIdStore: unityAdsIdStore) - - let id = installationId.installationId() - XCTAssertNotNil(id) - let secondId = installationId.installationId() - XCTAssertEqual(secondId, id) - - XCTAssertEqual(installationIdStore.getValueCallHistory.count, 1) - XCTAssertEqual(analyticsIdStore.getValueCallHistory.count, 1) - XCTAssertEqual(unityAdsIdStore.getValueCallHistory.count, 1) - XCTAssertEqual(installationIdStore.commitValueCallHistory.count, 1) - XCTAssertEqual(analyticsIdStore.commitValueCallHistory.count, 1) - XCTAssertEqual(unityAdsIdStore.commitValueCallHistory.count, 1) - } - - func testUnityAdsId() { - let installationIdStore = MockIdStore(value: nil) - let analyticsIdStore = MockIdStore(value: nil) - let unityAdsIdStore = MockIdStore(value: "unityAdsTestId") - let installationId = UADSInstallationId( - installationIdStore: installationIdStore, - analyticsIdStore: analyticsIdStore, - unityAdsIdStore: unityAdsIdStore) - - let id = installationId.installationId() - XCTAssertEqual(id, "unityAdsTestId") - let secondId = installationId.installationId() - XCTAssertEqual(secondId, "unityAdsTestId") - - XCTAssertEqual(installationIdStore.getValueCallHistory.count, 1) - XCTAssertEqual(analyticsIdStore.getValueCallHistory.count, 1) - XCTAssertEqual(unityAdsIdStore.getValueCallHistory.count, 1) - XCTAssertEqual(installationIdStore.commitValueCallHistory.count, 1) - XCTAssertEqual(analyticsIdStore.commitValueCallHistory.count, 1) - XCTAssertEqual(unityAdsIdStore.commitValueCallHistory.count, 1) - } - - func testAnalyticsId() { - let installationIdStore = MockIdStore(value: nil) - let analyticsIdStore = MockIdStore(value: "analyticsTestId") - let unityAdsIdStore = MockIdStore(value: "unityAdsTestId") - let installationId = UADSInstallationId( - installationIdStore: installationIdStore, - analyticsIdStore: analyticsIdStore, - unityAdsIdStore: unityAdsIdStore) - - let id = installationId.installationId() - XCTAssertEqual(id, "analyticsTestId") - let secondId = installationId.installationId() - XCTAssertEqual(secondId, "analyticsTestId") - - XCTAssertEqual(installationIdStore.getValueCallHistory.count, 1) - XCTAssertEqual(analyticsIdStore.getValueCallHistory.count, 1) - XCTAssertEqual(unityAdsIdStore.getValueCallHistory.count, 0) - XCTAssertEqual(installationIdStore.commitValueCallHistory.count, 1) - XCTAssertEqual(analyticsIdStore.commitValueCallHistory.count, 1) - XCTAssertEqual(unityAdsIdStore.commitValueCallHistory.count, 1) - } - - func testInstallationId() { - let installationIdStore = MockIdStore(value: "installationTestId") - let analyticsIdStore = MockIdStore(value: "analyticsTestId") - let unityAdsIdStore = MockIdStore(value: "unityAdsTestId") - let installationId = UADSInstallationId( - installationIdStore: installationIdStore, - analyticsIdStore: analyticsIdStore, - unityAdsIdStore: unityAdsIdStore) - - let id = installationId.installationId() - XCTAssertEqual(id, "installationTestId") - let secondId = installationId.installationId() - XCTAssertEqual(secondId, "installationTestId") - - XCTAssertEqual(installationIdStore.getValueCallHistory.count, 1) - XCTAssertEqual(analyticsIdStore.getValueCallHistory.count, 0) - XCTAssertEqual(unityAdsIdStore.getValueCallHistory.count, 0) - XCTAssertEqual(installationIdStore.commitValueCallHistory.count, 1) - XCTAssertEqual(analyticsIdStore.commitValueCallHistory.count, 1) - XCTAssertEqual(unityAdsIdStore.commitValueCallHistory.count, 1) - } - - func testMultithreading() { - var installationIds = [String]() - var expectations = [XCTestExpectation]() - for i in 0..<1_000 { - let expectation = self.expectation(description: "\(i) attempt") - expectations.append(expectation) - DispatchQueue.global(qos: .utility).async { - let installationId = UADSInstallationId.shared().installationId() - DispatchQueue.main.async { - installationIds.append(installationId) - expectation.fulfill() - } - } - } - - self.waitForExpectations(timeout: 5, handler: nil) - - XCTAssertEqual(installationIds.count, 1_000) - XCTAssertTrue(installationIds.allSatisfy({ $0 == installationIds.first })) - } - -} diff --git a/Tests/UnityAdsTests/Swift/UnityServicesIdentifiersTests/UADSPlistTests.swift b/Tests/UnityAdsTests/Swift/UnityServicesIdentifiersTests/UADSPlistTests.swift deleted file mode 100644 index 08334ca6..00000000 --- a/Tests/UnityAdsTests/Swift/UnityServicesIdentifiersTests/UADSPlistTests.swift +++ /dev/null @@ -1,176 +0,0 @@ -import Foundation -import XCTest - -@testable import UnityAds - -// swiftlint:disable force_unwrapping force_cast -class UADSPlistTests: XCTestCase { - - override func setUp() { - do { - try self.tearDownPlayerPrefs() - } catch { - // Do Nothing - } - } - - override func tearDown() { - do { - try self.tearDownPlayerPrefs() - } catch { - // Do Nothing - } - } - - func plistUrl() -> URL { - let bundleIdentifier = Bundle.main.bundleIdentifier ?? "" - let filePath = NSString(string: "~/Library/Preferences/\(bundleIdentifier).plist") - .expandingTildeInPath - let url = URL(fileURLWithPath: filePath) - return url - } - - func tearDownPlayerPrefs() throws { - let bundleIdentifier = Bundle.main.bundleIdentifier ?? "" - let filePath = NSString(string: "~/Library/Preferences/\(bundleIdentifier).plist") - .expandingTildeInPath - let url = URL(fileURLWithPath: filePath) - try FileManager.default.removeItem(at: url) - } - - @available(iOS 11, *) - func testReadWriteIosEleven() { - let url = self.plistUrl() - let firstReadDict = UADSPlist.dictionary(withContentsOfURLIosEleven: url) - XCTAssertNil(firstReadDict) - - var firstWriteDict: [AnyHashable: Any] = [:] - firstWriteDict["testKey"] = "testValue" - UADSPlist.writeIosEleven(firstWriteDict, toFileUrl: url) - var secondReadDict = UADSPlist.dictionary(withContentsOfURLIosEleven: url) - XCTAssertNotNil(secondReadDict) - XCTAssertEqual(secondReadDict?["testKey"] as? String, "testValue") - - secondReadDict?["testKey"] = "updatedTestValue" - UADSPlist.writeIosEleven(secondReadDict!, toFileUrl: url) - let thirdReadDict = UADSPlist.dictionary(withContentsOfURLIosEleven: url) - XCTAssertNotNil(thirdReadDict) - XCTAssertEqual(thirdReadDict?["testKey"] as? String, "updatedTestValue") - } - - func testReadWriteIosTen() { - let url = self.plistUrl() - let firstReadDict = UADSPlist.dictionary(withContentsOfURLIosTen: url) - XCTAssertNil(firstReadDict) - - var firstWriteDict: [AnyHashable: Any] = [:] - firstWriteDict["testKey"] = "testValue" - UADSPlist.writeIosTen(firstWriteDict, toFileUrl: url) - var secondReadDict = UADSPlist.dictionary(withContentsOfURLIosTen: url) - XCTAssertNotNil(secondReadDict) - XCTAssertEqual(secondReadDict?["testKey"] as? String, "testValue") - - secondReadDict?["testKey"] = "updatedTestValue" - UADSPlist.writeIosTen(secondReadDict!, toFileUrl: url) - let thirdReadDict = UADSPlist.dictionary(withContentsOfURLIosTen: url) - XCTAssertNotNil(thirdReadDict) - XCTAssertEqual(thirdReadDict?["testKey"] as? String, "updatedTestValue") - } - - func testReadWrite() { - let url = self.plistUrl() - let firstReadDict = UADSPlist.dictionary(withContentsOf: url) - XCTAssertNil(firstReadDict) - - var firstWriteDict: [AnyHashable: Any] = [:] - firstWriteDict["testKey"] = "testValue" - UADSPlist.write(firstWriteDict, toFileUrl: url) - var secondReadDict = UADSPlist.dictionary(withContentsOf: url) - XCTAssertNotNil(secondReadDict) - XCTAssertEqual(secondReadDict?["testKey"] as? String, "testValue") - - secondReadDict?["testKey"] = "updatedTestValue" - UADSPlist.write(secondReadDict!, toFileUrl: url) - let thirdReadDict = UADSPlist.dictionary(withContentsOf: url) - XCTAssertNotNil(thirdReadDict) - XCTAssertEqual(thirdReadDict?["testKey"] as? String, "updatedTestValue") - } - - func testWriteFileIosTenThreadSafe() { - let url = self.plistUrl() - let startTime = DispatchTime.now() - - for i in 0...100 { - var firstWriteDict: [AnyHashable: Any] = [:] - let expectation = self.expectation(description: "\(i) completed!") - firstWriteDict["testKey"] = "\(i)" - DispatchQueue.global(qos: .userInitiated).asyncAfter(deadline: startTime + 0.2) { - let success = UADSPlist.writeIosTen(firstWriteDict, toFileUrl: url) - XCTAssertTrue(success) - expectation.fulfill() - } - } - self.waitForExpectations(timeout: 1, handler: nil) - } - - @available(iOS 11, *) - func testWriteFileIosElevenThreadSafe() { - let url = self.plistUrl() - let startTime = DispatchTime.now() - - for i in 0...100 { - var firstWriteDict: [AnyHashable: Any] = [:] - let expectation = self.expectation(description: "\(i) completed!") - firstWriteDict["testKey"] = "\(i)" - DispatchQueue.global(qos: .userInitiated).asyncAfter(deadline: startTime + 0.2) { - let success = UADSPlist.writeIosEleven(firstWriteDict, toFileUrl: url) - XCTAssertTrue(success) - expectation.fulfill() - } - } - self.waitForExpectations(timeout: 1, handler: nil) - } - - func testReadFileIosTenThreadSafe() { - let url = self.plistUrl() - let startTime = DispatchTime.now() - var firstWriteDict: [AnyHashable: Any] = [:] - firstWriteDict["testKey"] = "testValue" - UADSPlist.writeIosTen(firstWriteDict, toFileUrl: url) - - for i in 0...100 { - var firstWriteDict: [AnyHashable: Any] = [:] - let expectation = self.expectation(description: "\(i) completed!") - firstWriteDict["testKey"] = "\(i)" - DispatchQueue.global(qos: .userInitiated).asyncAfter(deadline: startTime + 0.2) { - let dict: [String: String] = - UADSPlist.dictionary(withContentsOfURLIosTen: url) as! [String: String] - XCTAssertEqual(dict["testKey"], "testValue") - expectation.fulfill() - } - } - self.waitForExpectations(timeout: 1, handler: nil) - } - - @available(iOS 11, *) - func testReadFileIosElevenThreadSafe() { - let url = self.plistUrl() - var firstWriteDict: [AnyHashable: Any] = [:] - firstWriteDict["testKey"] = "testValue" - UADSPlist.writeIosEleven(firstWriteDict, toFileUrl: url) - let startTime = DispatchTime.now() - - for i in 0...100 { - var firstWriteDict: [AnyHashable: Any] = [:] - let expectation = self.expectation(description: "\(i) completed!") - firstWriteDict["testKey"] = "\(i)" - DispatchQueue.global(qos: .userInitiated).asyncAfter(deadline: startTime + 0.2) { - let dict: [String: String] = - UADSPlist.dictionary(withContentsOfURLIosEleven: url) as! [String: String] - XCTAssertEqual(dict["testKey"], "testValue") - expectation.fulfill() - } - } - self.waitForExpectations(timeout: 1, handler: nil) - } -} diff --git a/Tests/UnityAdsTests/Swift/UnityServicesIdentifiersTests/UADSSessionIdTests.swift b/Tests/UnityAdsTests/Swift/UnityServicesIdentifiersTests/UADSSessionIdTests.swift deleted file mode 100644 index eadf50d5..00000000 --- a/Tests/UnityAdsTests/Swift/UnityServicesIdentifiersTests/UADSSessionIdTests.swift +++ /dev/null @@ -1,54 +0,0 @@ -import Foundation -import XCTest - -@testable import UnityAds - -class UADSSessionIdTests: XCTestCase { - - func testShared() { - let shared = UADSSessionId.shared() - let shared2 = UADSSessionId.shared() - - XCTAssertNotNil(shared) - XCTAssertEqual(shared, shared2) - } - - func testSessionId() { - let shared = UADSSessionId.shared() - let shared2 = UADSSessionId.shared() - - XCTAssertNotNil(shared.sessionId()) - XCTAssertEqual(shared.sessionId(), shared.sessionId()) - XCTAssertEqual(shared.sessionId(), shared2.sessionId()) - } - - // sessionId should get generated uniquely per instance of UADSSessionId - func testDifferentInstancesOfSession() { - let instance1 = UADSSessionId() - let instance2 = UADSSessionId() - - XCTAssertNotEqual(instance1.sessionId(), instance2.sessionId()) - } - - func testMultithreading() { - var sessionIds = [String]() - var expectations = [XCTestExpectation]() - for i in 0..<1_000 { - let expectation = self.expectation(description: "\(i) attempt") - expectations.append(expectation) - DispatchQueue.global(qos: .utility).async { - let sessionId = UADSSessionId.shared().sessionId() - DispatchQueue.main.async { - sessionIds.append(sessionId) - expectation.fulfill() - } - } - } - - self.waitForExpectations(timeout: 5, handler: nil) - - XCTAssertEqual(sessionIds.count, 1_000) - XCTAssertTrue(sessionIds.allSatisfy({ $0 == sessionIds.first })) - } - -} diff --git a/Tests/UnityAdsTests/Swift/UnityServicesIdentifiersTests/UADSUnityPlayerPrefsStoreTests.swift b/Tests/UnityAdsTests/Swift/UnityServicesIdentifiersTests/UADSUnityPlayerPrefsStoreTests.swift deleted file mode 100644 index b359295c..00000000 --- a/Tests/UnityAdsTests/Swift/UnityServicesIdentifiersTests/UADSUnityPlayerPrefsStoreTests.swift +++ /dev/null @@ -1,85 +0,0 @@ -import Foundation -import XCTest - -@testable import UnityAds -// swiftlint:disable compiler_protocol_init -class UADSUnityPlayerPrefsStoreTests: XCTestCase { - - override func setUp() { - do { - try self.tearDownPlayerPrefs() - } catch { - // Do Nothing - } - } - - override func tearDown() { - do { - try self.tearDownPlayerPrefs() - } catch { - // Do Nothing - } - } - - func setupPlayerPrefs() { - let playerPrefsStore = UADSUnityPlayerPrefsStore(key: "UnityInstallationId") - playerPrefsStore.commitValue("PlayerPrefsTestInstallationId") - } - - func setupEmptyPlayerPrefs() throws { - let plistDictionary = NSDictionary() - try self.writePlist(plistDictionary: plistDictionary) - } - - func setupIntegerPlayerPrefs() throws { - let plistDictionary = NSMutableDictionary() - plistDictionary.setObject( - NSNumber(integerLiteral: 2), forKey: NSString(string: "UnityInstallationId")) - try self.writePlist(plistDictionary: plistDictionary) - } - - func writePlist(plistDictionary: NSDictionary) throws { - let bundleIdentifier = Bundle.main.bundleIdentifier ?? "" - let filePath = NSString(string: "~/Library/Preferences/\(bundleIdentifier).plist") - .expandingTildeInPath - let url = URL(fileURLWithPath: filePath) - if #available(iOS 11.0, *) { - try plistDictionary.write(to: url) - } else { - // Fallback on earlier versions - plistDictionary.write(to: url, atomically: true) - } - } - - func tearDownPlayerPrefs() throws { - let bundleIdentifier = Bundle.main.bundleIdentifier ?? "" - let filePath = NSString(string: "~/Library/Preferences/\(bundleIdentifier).plist") - .expandingTildeInPath - let url = URL(fileURLWithPath: filePath) - try FileManager.default.removeItem(at: url) - } - - func testNoPlist() { - let playerPrefsStore = UADSUnityPlayerPrefsStore(key: "UnityInstallationId") - XCTAssertEqual(playerPrefsStore.getValue(), nil) - playerPrefsStore.commitValue("noPlistInstallationId") - XCTAssertEqual(playerPrefsStore.getValue(), "noPlistInstallationId") - } - - func testEmptyPlist() throws { - try self.setupEmptyPlayerPrefs() - let playerPrefsStore = UADSUnityPlayerPrefsStore(key: "UnityInstallationId") - XCTAssertEqual(playerPrefsStore.getValue(), nil) - playerPrefsStore.commitValue("emptyPlistInstallationId") - XCTAssertEqual(playerPrefsStore.getValue(), "emptyPlistInstallationId") - } - - func testIntegerPlist() throws { - try self.setupIntegerPlayerPrefs() - let playerPrefsStore = UADSUnityPlayerPrefsStore(key: "UnityInstallationId") - XCTAssertEqual(playerPrefsStore.getValue(), nil) - playerPrefsStore.commitValue("integerPlistInstallationId") - XCTAssertEqual(playerPrefsStore.getValue(), "integerPlistInstallationId") - } - -} diff --git a/Tests/UnityAdsTests/Swift/UnityServicesIdentifiersTests/UADSUserDefaultsStoreTests.swift b/Tests/UnityAdsTests/Swift/UnityServicesIdentifiersTests/UADSUserDefaultsStoreTests.swift deleted file mode 100644 index 31c9f92d..00000000 --- a/Tests/UnityAdsTests/Swift/UnityServicesIdentifiersTests/UADSUserDefaultsStoreTests.swift +++ /dev/null @@ -1,39 +0,0 @@ -import Foundation -import XCTest - -@testable import UnityAds - -class USIUserDefaultsStoreTests: XCTestCase { - - let userDefaultsTestKey = "unityads-idfi" - - override func tearDown() { - self.tearDownUserDefaults() - } - - func setupUserDefaults() { - UserDefaults.standard.set("UnityAdsUserDefaultsTestInstallationId", forKey: userDefaultsTestKey) - } - - func tearDownUserDefaults() { - UserDefaults.standard.removeObject(forKey: userDefaultsTestKey) - } - - func testUnset() { - let store = UADSUserDefaultsStore(key: userDefaultsTestKey) - XCTAssertNil(store.getValue()) - - store.commitValue("UnityAdsUserDefaultsTestInstallationId") - XCTAssertEqual(store.getValue(), "UnityAdsUserDefaultsTestInstallationId") - } - - func testPreset() { - self.setupUserDefaults() - let store = UADSUserDefaultsStore(key: userDefaultsTestKey) - XCTAssertEqual(store.getValue(), "UnityAdsUserDefaultsTestInstallationId") - - store.commitValue("Second") - XCTAssertEqual(store.getValue(), "Second") - } - -} diff --git a/Tests/UnityAdsTests/Tools/Timer/UADSTimerTests.m b/Tests/UnityAdsTests/Tools/Timer/UADSTimerTests.m index c9cf385c..e121db01 100644 --- a/Tests/UnityAdsTests/Tools/Timer/UADSTimerTests.m +++ b/Tests/UnityAdsTests/Tools/Timer/UADSTimerTests.m @@ -160,7 +160,7 @@ - (void)test_resumes_after_pause { block:^(NSInteger index) { NSTimeInterval currentTime = [NSDate currentTimeInterval]; NSTimeInterval diff = index == pauseIndex ? secondWait + ti : ti; - XCTAssertEqualWithAccuracy(currentTime - startTime, diff, 0.05); + XCTAssertEqualWithAccuracy(currentTime - startTime, diff, 0.1); startTime = currentTime; [exp fulfill]; diff --git a/Tests/UnityAdsTests/UADSTools/DynamicLibLoader/DynamicLibLoaderTests.m b/Tests/UnityAdsTests/UADSTools/DynamicLibLoader/DynamicLibLoaderTests.m index fb1128e5..09ae46a6 100644 --- a/Tests/UnityAdsTests/UADSTools/DynamicLibLoader/DynamicLibLoaderTests.m +++ b/Tests/UnityAdsTests/UADSTools/DynamicLibLoader/DynamicLibLoaderTests.m @@ -39,10 +39,6 @@ @interface DynamicLibLoaderTests : XCTestCase @implementation DynamicLibLoaderTests -- (void)test_returns_not_loaded_state { - XCTAssertEqual(QuartzCoreLoaderMock.frameworkState, kUADSDynamicLibLoaderStateNotLoaded); -} - - (void)test_loads_framework_and_change_state { XCTAssertEqual([QuartzCoreLoaderMock loadFrameworkIfNotLoaded], kUADSDynamicLibLoaderStateLoaded); XCTAssertEqual([QuartzCoreLoaderMock loadFrameworkIfNotLoaded], kUADSDynamicLibLoaderStateLoaded); diff --git a/Tests/UnityAdsTests/UADTestsTools/GMATestsHelper/GMATestsHelper.m b/Tests/UnityAdsTests/UADTestsTools/GMATestsHelper/GMATestsHelper.m index 0a4c58ce..2f1d19ad 100644 --- a/Tests/UnityAdsTests/UADTestsTools/GMATestsHelper/GMATestsHelper.m +++ b/Tests/UnityAdsTests/UADTestsTools/GMATestsHelper/GMATestsHelper.m @@ -2,7 +2,7 @@ #import "UADSTools.h" #import "USRVWebViewCallbackMock.h" #import "GMAIntegrationTestsConstants.h" - +#import "UnityAds+Testability.h" #import "NSArray+Map.h" @implementation GMATestsHelper @@ -19,8 +19,7 @@ - (void)install { } - (void)clear { - _webViewMock = nil; - [USRVWebViewApp setCurrentApp: _webViewMock]; + [UnityAds resetForTest]; } - (NSString *)apiClassName { diff --git a/Tests/UnityAdsTests/UADTestsTools/Mocks/USRVWebViewAppMock.m b/Tests/UnityAdsTests/UADTestsTools/Mocks/USRVWebViewAppMock.m index 3f859a9e..f13b1029 100644 --- a/Tests/UnityAdsTests/UADTestsTools/Mocks/USRVWebViewAppMock.m +++ b/Tests/UnityAdsTests/UADTestsTools/Mocks/USRVWebViewAppMock.m @@ -43,7 +43,6 @@ - (BOOL)sendEvent: (NSString *)eventId category: (NSString *)category param1: (i - (BOOL)sendEvent: (NSString *)eventId category: (NSString *)category params: (NSArray *)params { [_expectation fulfill]; - _expectation = nil; _categoryNames = [_categoryNames arrayByAddingObject: category]; _eventNames = [_eventNames arrayByAddingObject: eventId]; diff --git a/Tests/UnityAdsTests/UnityServices/Ads/Load/UADSLoadModule/Mocks/UnityAdsLoadDelegateMock.m b/Tests/UnityAdsTests/UnityServices/Ads/Load/UADSLoadModule/Mocks/UnityAdsLoadDelegateMock.m index 111783ca..b0fbf614 100644 --- a/Tests/UnityAdsTests/UnityServices/Ads/Load/UADSLoadModule/Mocks/UnityAdsLoadDelegateMock.m +++ b/Tests/UnityAdsTests/UnityServices/Ads/Load/UADSLoadModule/Mocks/UnityAdsLoadDelegateMock.m @@ -26,9 +26,7 @@ - (void)unityAdsAdLoaded: (nonnull NSString *)placementId { } - (void)fulfill { - if ((_failedPlacements.count + _succeedPlacements.count) == 1) { - [self.expectation fulfill]; - } + [self.expectation fulfill]; } @end diff --git a/Tests/UnityAdsTests/UnityServices/Ads/Load/UADSLoadModule/UADSLoadModuleIntegrationTests.m b/Tests/UnityAdsTests/UnityServices/Ads/Load/UADSLoadModule/UADSLoadModuleIntegrationTests.m index 98e7d73d..5ef57649 100644 --- a/Tests/UnityAdsTests/UnityServices/Ads/Load/UADSLoadModule/UADSLoadModuleIntegrationTests.m +++ b/Tests/UnityAdsTests/UnityServices/Ads/Load/UADSLoadModule/UADSLoadModuleIntegrationTests.m @@ -185,7 +185,6 @@ - (void)emulateSendLoadedForTheLastListener { NSArray *passedArguments = _webAppMock.returnedParams.lastObject; NSDictionary *params = passedArguments.firstObject; NSString *listenerID = params[kUADSListenerIDKey]; - [self.moduleToTest sendAdLoadedForPlacementID: kUADSLoadModuleTestsPlacementID andListenerID: listenerID]; } diff --git a/Tests/UnityAdsTests/WebViewMethodInvokeHandlerTests.m b/Tests/UnityAdsTests/WebViewMethodInvokeHandlerTests.m index a9507b7a..61f63acc 100644 --- a/Tests/UnityAdsTests/WebViewMethodInvokeHandlerTests.m +++ b/Tests/UnityAdsTests/WebViewMethodInvokeHandlerTests.m @@ -1,7 +1,7 @@ #import #import #import "UnityAdsTests-Bridging-Header.h" - +#import "UnityAds+Testability.h" @interface WebViewBridgeTestApi : NSObject @end @@ -105,6 +105,7 @@ @implementation UrlProtocolTests - (void)setUp { [super setUp]; + [UnityAds resetForTest]; MethodInvokeMockConfiguration *config = [[MethodInvokeMockConfiguration alloc] initWithConfigUrl: @"http://localhost/"]; UrlProtocolMockWebView *mockWebView = [[UrlProtocolMockWebView alloc] init]; XCTestExpectation *expectation = [self expectationWithDescription: @"setup"]; @@ -137,6 +138,7 @@ - (void)tearDown { apiCallbackCount = 0; [USRVWebViewApp setCurrentApp: NULL]; + [UnityAds resetForTest]; } - (void)testHandleInvocationShouldFailParametersNull { diff --git a/UnityAds.podspec b/UnityAds.podspec index 2ac916b7..68a82aed 100644 --- a/UnityAds.podspec +++ b/UnityAds.podspec @@ -1,12 +1,12 @@ Pod::Spec.new do |s| s.name = 'UnityAds' - s.version = '4.6.1' + s.version = '4.7.0' s.license = { :type => 'Unity License', :file => 'LICENSE' } s.author = { 'UnityAds' => 'itunes@unity3d.com' } s.homepage = 'https://unity3d.com/services/ads' s.summary = 'Monetize your entire player base and reach new audiences with video ads.' s.platform = :ios - s.source = { :http => 'https://github.com/Unity-Technologies/unity-ads-ios/releases/download/4.6.1/UnityAds.zip' } + s.source = { :http => 'https://github.com/Unity-Technologies/unity-ads-ios/releases/download/4.7.0/UnityAds.zip' } s.ios.deployment_target = '9.0' s.ios.vendored_frameworks = 'UnityAds.xcframework' s.swift_version = '5.0'