diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml new file mode 100644 index 000000000..36534aa4e --- /dev/null +++ b/.github/workflows/build.yaml @@ -0,0 +1,206 @@ +on: + create: + tags: + - v* +name: Build framework +jobs: + static: + name: Build static SDK + runs-on: macOS-latest + steps: + - uses: actions/checkout@v2 + - name: Build + run: | + mkdir -p frameworks/static + xcodebuild -target AdjustStatic -configuration Release clean build + + mkdir AdjustSdkStatic + mv frameworks/static/* AdjustSdkStatic + zip -ry AdjustSdkStatic.framework.zip AdjustSdkStatic/* + - name: Upload files + uses: actions/upload-artifact@v2 + with: + name: static_framework + path: AdjustSdkStatic.framework.zip + tvOS: + name: Build Static tvOS SDK + runs-on: macOS-latest + steps: + - uses: actions/checkout@v2 + - name: Universal tvOS SDK + run: | + mkdir -p frameworks/static_tvos + xcodebuild -configuration Release -target AdjustSdkTv -arch x86_64 -sdk appletvsimulator clean build + xcodebuild -configuration Release -target AdjustSdkTv -arch arm64 -sdk appletvos build + cp -Rv build/Release-appletvos/AdjustSdkTv.framework frameworks/static_tvos + lipo -create -output frameworks/static_tvos/AdjustSdkTv.framework/AdjustSdkTv build/Release-appletvos/AdjustSdkTv.framework/AdjustSdkTv build/Release-appletvsimulator/AdjustSdkTv.framework/AdjustSdkTv + + mkdir AdjustSdkTvStatic + mv frameworks/static_tvos/* AdjustSdkTvStatic + zip -ry AdjustSdkTvStatic.framework.zip AdjustSdkTvStatic/* + - name: Upload files + uses: actions/upload-artifact@v2 + with: + name: universal_tvos + path: AdjustSdkTvStatic.framework.zip + + dynamic_ios_tvos: + name: Build dynamic iOS and tvOS targets with Carthage + runs-on: macOS-latest + steps: + - uses: actions/checkout@v2 + - name: Install Carthage + run: | + brew install carthage + - name: Build dynamic framework + run: | + mv Adjust.xcodeproj/xcshareddata/xcschemes/AdjustSdkIm.xcscheme \ + Adjust.xcodeproj/xcshareddata/xcschemes/AdjustSdkWebBridge.xcscheme . + carthage build --no-skip-current + + mkdir AdjustSdkDynamic + mv Carthage/Build/iOS/* AdjustSdkDynamic + zip -ry AdjustSdkDynamic.framework.zip AdjustSdkDynamic/* + + mkdir AdjustSdkTvDynamic + mv Carthage/Build/tvOS/* AdjustSdkTvDynamic + zip -ry AdjustSdkTvDynamic.framework.zip AdjustSdkTvDynamic/* + - name: Upload iOS + uses: actions/upload-artifact@v2 + with: + name: dynamic_ios + path: AdjustSdkDynamic.framework.zip + - name: Upload tvOS + uses: actions/upload-artifact@v2 + with: + name: dynamic_tvos + path: AdjustSdkTvDynamic.framework.zip + + dynamic_imessage: + name: Build dynamic iMessage target with Carthage + runs-on: macOS-latest + steps: + - uses: actions/checkout@v2 + - name: Install Carthage + run: | + brew install carthage + - name: Build dynamic framework + run: | + mv Adjust.xcodeproj/xcshareddata/xcschemes/*.xcscheme . + mv AdjustSdkIm.xcscheme Adjust.xcodeproj/xcshareddata/xcschemes + + carthage build --no-skip-current + + mkdir AdjustSdkImDynamic + mv Carthage/Build/iOS/* AdjustSdkImDynamic + zip -ry AdjustSdkIm.framework.zip AdjustSdkImDynamic/* + - name: Upload framework + uses: actions/upload-artifact@v2 + with: + name: dynamic_imessage + path: AdjustSdkIm.framework.zip + + dynamic_webbridge: + name: Build dynamic WebBridge target with Carthage + runs-on: macOS-latest + steps: + - uses: actions/checkout@v2 + - name: Install Carthage + run: | + brew install carthage + - name: Build dynamic framework + run: | + mv Adjust.xcodeproj/xcshareddata/xcschemes/*.xcscheme . + mv AdjustSdkWebBridge.xcscheme Adjust.xcodeproj/xcshareddata/xcschemes + + carthage build --no-skip-current + mkdir AdjustSdkWebBridgeDynamic + mv Carthage/Build/iOS/* AdjustSdkWebBridgeDynamic + zip -ry AdjustSdkWebBridge.framework.zip AdjustSdkWebBridgeDynamic/* + - name: Upload framework + uses: actions/upload-artifact@v2 + with: + name: dynamic_webbridge + path: AdjustSdkWebBridge.framework.zip + + release: + name: Create new release and upload assets + runs-on: ubuntu-latest + needs: [static, tvOS, dynamic_ios_tvos, dynamic_imessage, dynamic_webbridge] + steps: + - name: Create Release + id: create_release + uses: actions/create-release@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + tag_name: ${{ github.ref }} + release_name: Version ${{ github.ref }} + draft: true + prerelease: false + + - name: Download all frameworks + uses: actions/download-artifact@v2 + with: + path: frameworks + + - name: Upload static framework + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} + asset_path: frameworks/static_framework/AdjustSdkStatic.framework.zip + asset_name: AdjustSdkStatic.framework.zip + asset_content_type: application/zip + + - name: Upload tvOS framework + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} + asset_path: frameworks/universal_tvos/AdjustSdkTvStatic.framework.zip + asset_name: AdjustSdkTvStatic.framework.zip + asset_content_type: application/zip + + - name: Upload dynamic iOS framework + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} + asset_path: frameworks/dynamic_ios/AdjustSdkDynamic.framework.zip + asset_name: AdjustSdkDynamic.framework.zip + asset_content_type: application/zip + + - name: Upload dynamic tvOS framework + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} + asset_path: frameworks/dynamic_tvos/AdjustSdkTvDynamic.framework.zip + asset_name: AdjustSdkTvDynamic.framework.zip + asset_content_type: application/zip + + - name: Upload dynamic iMessage framework + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} + asset_path: frameworks/dynamic_imessage/AdjustSdkIm.framework.zip + asset_name: AdjustSdkIm.framework.zip + asset_content_type: application/zip + + - name: Upload dynamic WebBridge framework + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} + asset_path: frameworks/dynamic_webbridge/AdjustSdkWebBridge.framework.zip + asset_name: AdjustSdkWebBridge.framework.zip + asset_content_type: application/zip + diff --git a/Adjust.podspec b/Adjust.podspec index af71cca67..bc15647e2 100644 --- a/Adjust.podspec +++ b/Adjust.podspec @@ -1,11 +1,11 @@ Pod::Spec.new do |s| s.name = "Adjust" - s.version = "4.21.0" + s.version = "4.23.0" s.summary = "This is the iOS SDK of adjust. You can read more about it at http://adjust.com." s.homepage = "https://github.com/adjust/ios_sdk" s.license = { :type => 'MIT', :file => 'MIT-LICENSE' } s.author = { "Christian Wellenbrock" => "welle@adjust.com" } - s.source = { :git => "https://github.com/adjust/ios_sdk.git", :tag => "v4.21.0" } + s.source = { :git => "https://github.com/adjust/ios_sdk.git", :tag => "v4.23.0" } s.ios.deployment_target = '6.0' s.tvos.deployment_target = '9.0' s.framework = 'SystemConfiguration' diff --git a/Adjust.xcodeproj/project.pbxproj b/Adjust.xcodeproj/project.pbxproj index 4ebae30f3..56facc42b 100644 --- a/Adjust.xcodeproj/project.pbxproj +++ b/Adjust.xcodeproj/project.pbxproj @@ -23,6 +23,18 @@ /* Begin PBXBuildFile section */ 2067002A1F18BDC700B4FDE1 /* CoreTelephony.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9601C19C1A31DD7F00A9AE21 /* CoreTelephony.framework */; settings = {ATTRIBUTES = (Weak, ); }; }; + 6FBEE8F324E2C26F00FEF3F1 /* ADJUrlStrategy.h in Headers */ = {isa = PBXBuildFile; fileRef = 6FBEE8F124E2C26F00FEF3F1 /* ADJUrlStrategy.h */; }; + 6FBEE8F524E2C26F00FEF3F1 /* ADJUrlStrategy.m in Sources */ = {isa = PBXBuildFile; fileRef = 6FBEE8F224E2C26F00FEF3F1 /* ADJUrlStrategy.m */; }; + 6FBEE92624E422EB00FEF3F1 /* ADJUrlStrategy.m in Sources */ = {isa = PBXBuildFile; fileRef = 6FBEE92424E422EB00FEF3F1 /* ADJUrlStrategy.m */; }; + 6FBEE92724E422EB00FEF3F1 /* ADJUrlStrategy.m in Sources */ = {isa = PBXBuildFile; fileRef = 6FBEE92424E422EB00FEF3F1 /* ADJUrlStrategy.m */; }; + 6FBEE92824E422EB00FEF3F1 /* ADJUrlStrategy.h in Headers */ = {isa = PBXBuildFile; fileRef = 6FBEE92524E422EB00FEF3F1 /* ADJUrlStrategy.h */; }; + 6FBEE92924E422EB00FEF3F1 /* ADJUrlStrategy.h in Headers */ = {isa = PBXBuildFile; fileRef = 6FBEE92524E422EB00FEF3F1 /* ADJUrlStrategy.h */; }; + 6FBEE92C24E4230800FEF3F1 /* ADJUrlStrategy.h in Headers */ = {isa = PBXBuildFile; fileRef = 6FBEE92A24E4230700FEF3F1 /* ADJUrlStrategy.h */; }; + 6FBEE92D24E4230800FEF3F1 /* ADJUrlStrategy.m in Sources */ = {isa = PBXBuildFile; fileRef = 6FBEE92B24E4230700FEF3F1 /* ADJUrlStrategy.m */; }; + 6FBEE93024E4231400FEF3F1 /* ADJUrlStrategy.h in Headers */ = {isa = PBXBuildFile; fileRef = 6FBEE92E24E4231300FEF3F1 /* ADJUrlStrategy.h */; }; + 6FBEE93124E4231400FEF3F1 /* ADJUrlStrategy.m in Sources */ = {isa = PBXBuildFile; fileRef = 6FBEE92F24E4231300FEF3F1 /* ADJUrlStrategy.m */; }; + 6FBEE93424E4232800FEF3F1 /* ADJUrlStrategy.h in Headers */ = {isa = PBXBuildFile; fileRef = 6FBEE93224E4232800FEF3F1 /* ADJUrlStrategy.h */; }; + 6FBEE93524E4232800FEF3F1 /* ADJUrlStrategy.m in Sources */ = {isa = PBXBuildFile; fileRef = 6FBEE93324E4232800FEF3F1 /* ADJUrlStrategy.m */; }; 6FCC85001F278CF300D6A0ED /* ADJReachability.m in Sources */ = {isa = PBXBuildFile; fileRef = 6FCC84F71F278CF300D6A0ED /* ADJReachability.m */; }; 6FCC85011F278CF300D6A0ED /* ADJReachability.h in Headers */ = {isa = PBXBuildFile; fileRef = 6FCC84F81F278CF300D6A0ED /* ADJReachability.h */; }; 6FCC85041F27945E00D6A0ED /* ADJReachability.h in Headers */ = {isa = PBXBuildFile; fileRef = 6FCC85021F27944600D6A0ED /* ADJReachability.h */; }; @@ -216,6 +228,16 @@ 9D0E2EB9210B575600133B4F /* WKWebViewJavascriptBridge.h in Headers */ = {isa = PBXBuildFile; fileRef = 9D0E2E68210B575600133B4F /* WKWebViewJavascriptBridge.h */; settings = {ATTRIBUTES = (Public, ); }; }; 9D0E2EBA210B575600133B4F /* AdjustBridge.h in Headers */ = {isa = PBXBuildFile; fileRef = 9D0E2E69210B575600133B4F /* AdjustBridge.h */; settings = {ATTRIBUTES = (Public, ); }; }; 9D0E2EBB210B575600133B4F /* AdjustBridgeRegister.m in Sources */ = {isa = PBXBuildFile; fileRef = 9D0E2E6A210B575600133B4F /* AdjustBridgeRegister.m */; }; + 9D2F23E22447CE5C00B7CA90 /* ADJSubscription.h in Headers */ = {isa = PBXBuildFile; fileRef = 9D2F23E02447CE5C00B7CA90 /* ADJSubscription.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 9D2F23E32447CE5C00B7CA90 /* ADJSubscription.m in Sources */ = {isa = PBXBuildFile; fileRef = 9D2F23E12447CE5C00B7CA90 /* ADJSubscription.m */; }; + 9D2F23F82447DCE800B7CA90 /* ADJSubscription.m in Sources */ = {isa = PBXBuildFile; fileRef = 9D2F23F62447DCE800B7CA90 /* ADJSubscription.m */; }; + 9D2F23F92447DCE800B7CA90 /* ADJSubscription.h in Headers */ = {isa = PBXBuildFile; fileRef = 9D2F23F72447DCE800B7CA90 /* ADJSubscription.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 9D2F23FC2447DD2500B7CA90 /* ADJSubscription.h in Headers */ = {isa = PBXBuildFile; fileRef = 9D2F23FA2447DD2500B7CA90 /* ADJSubscription.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 9D2F23FD2447DD2500B7CA90 /* ADJSubscription.m in Sources */ = {isa = PBXBuildFile; fileRef = 9D2F23FB2447DD2500B7CA90 /* ADJSubscription.m */; }; + 9D2F24002447DD3700B7CA90 /* ADJSubscription.h in Headers */ = {isa = PBXBuildFile; fileRef = 9D2F23FE2447DD3600B7CA90 /* ADJSubscription.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 9D2F24012447DD3700B7CA90 /* ADJSubscription.m in Sources */ = {isa = PBXBuildFile; fileRef = 9D2F23FF2447DD3700B7CA90 /* ADJSubscription.m */; }; + 9D2F24042447DD6000B7CA90 /* ADJSubscription.m in Sources */ = {isa = PBXBuildFile; fileRef = 9D2F24022447DD6000B7CA90 /* ADJSubscription.m */; }; + 9D2F24052447DD6000B7CA90 /* ADJSubscription.h in Headers */ = {isa = PBXBuildFile; fileRef = 9D2F24032447DD6000B7CA90 /* ADJSubscription.h */; settings = {ATTRIBUTES = (Public, ); }; }; 9D363AC31BDA50FA00B47FE9 /* ADJLogger.h in Headers */ = {isa = PBXBuildFile; fileRef = 96E5E37318BBB48A008E7B30 /* ADJLogger.h */; settings = {ATTRIBUTES = (Public, ); }; }; 9D7431EA1EB9F9B700969F14 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 9D7431E91EB9F9B700969F14 /* main.m */; }; 9D7431ED1EB9F9B700969F14 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 9D7431EC1EB9F9B700969F14 /* AppDelegate.m */; }; @@ -591,6 +613,16 @@ 6F0842182007766700568A31 /* AdjustTestLibrary.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = AdjustTestLibrary.xcodeproj; path = AdjustTestLibrary/AdjustTestLibrary.xcodeproj; sourceTree = ""; }; 6F084240200776A000568A31 /* AdjustTestApp.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = AdjustTestApp.xcodeproj; path = AdjustTestApp/AdjustTestApp.xcodeproj; sourceTree = ""; }; 6F7AF63F211878BC00F730B2 /* AdjustWebBridgeTestApp.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = AdjustWebBridgeTestApp.xcodeproj; path = AdjustWebBridgeTestApp/AdjustWebBridgeTestApp.xcodeproj; sourceTree = ""; }; + 6FBEE8F124E2C26F00FEF3F1 /* ADJUrlStrategy.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ADJUrlStrategy.h; sourceTree = ""; }; + 6FBEE8F224E2C26F00FEF3F1 /* ADJUrlStrategy.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ADJUrlStrategy.m; sourceTree = ""; }; + 6FBEE92424E422EB00FEF3F1 /* ADJUrlStrategy.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ADJUrlStrategy.m; sourceTree = ""; }; + 6FBEE92524E422EB00FEF3F1 /* ADJUrlStrategy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ADJUrlStrategy.h; sourceTree = ""; }; + 6FBEE92A24E4230700FEF3F1 /* ADJUrlStrategy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ADJUrlStrategy.h; sourceTree = ""; }; + 6FBEE92B24E4230700FEF3F1 /* ADJUrlStrategy.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ADJUrlStrategy.m; sourceTree = ""; }; + 6FBEE92E24E4231300FEF3F1 /* ADJUrlStrategy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ADJUrlStrategy.h; sourceTree = ""; }; + 6FBEE92F24E4231300FEF3F1 /* ADJUrlStrategy.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ADJUrlStrategy.m; sourceTree = ""; }; + 6FBEE93224E4232800FEF3F1 /* ADJUrlStrategy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ADJUrlStrategy.h; sourceTree = ""; }; + 6FBEE93324E4232800FEF3F1 /* ADJUrlStrategy.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ADJUrlStrategy.m; sourceTree = ""; }; 6FCC84F71F278CF300D6A0ED /* ADJReachability.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ADJReachability.m; sourceTree = ""; }; 6FCC84F81F278CF300D6A0ED /* ADJReachability.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ADJReachability.h; sourceTree = ""; }; 6FCC85021F27944600D6A0ED /* ADJReachability.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ADJReachability.h; sourceTree = ""; }; @@ -806,6 +838,16 @@ 9D0E2E68210B575600133B4F /* WKWebViewJavascriptBridge.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WKWebViewJavascriptBridge.h; sourceTree = ""; }; 9D0E2E69210B575600133B4F /* AdjustBridge.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AdjustBridge.h; sourceTree = ""; }; 9D0E2E6A210B575600133B4F /* AdjustBridgeRegister.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AdjustBridgeRegister.m; sourceTree = ""; }; + 9D2F23E02447CE5C00B7CA90 /* ADJSubscription.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ADJSubscription.h; sourceTree = ""; }; + 9D2F23E12447CE5C00B7CA90 /* ADJSubscription.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ADJSubscription.m; sourceTree = ""; }; + 9D2F23F62447DCE800B7CA90 /* ADJSubscription.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ADJSubscription.m; sourceTree = ""; }; + 9D2F23F72447DCE800B7CA90 /* ADJSubscription.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ADJSubscription.h; sourceTree = ""; }; + 9D2F23FA2447DD2500B7CA90 /* ADJSubscription.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ADJSubscription.h; sourceTree = ""; }; + 9D2F23FB2447DD2500B7CA90 /* ADJSubscription.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ADJSubscription.m; sourceTree = ""; }; + 9D2F23FE2447DD3600B7CA90 /* ADJSubscription.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ADJSubscription.h; sourceTree = ""; }; + 9D2F23FF2447DD3700B7CA90 /* ADJSubscription.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ADJSubscription.m; sourceTree = ""; }; + 9D2F24022447DD6000B7CA90 /* ADJSubscription.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ADJSubscription.m; sourceTree = ""; }; + 9D2F24032447DD6000B7CA90 /* ADJSubscription.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ADJSubscription.h; sourceTree = ""; }; 9D449DB31E6ED23400E7E80B /* AdjustExample-iWatch.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = "AdjustExample-iWatch.xcodeproj"; path = "examples/AdjustExample-iWatch/AdjustExample-iWatch.xcodeproj"; sourceTree = ""; }; 9D449DBF1E6ED23900E7E80B /* AdjustExample-Swift.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = "AdjustExample-Swift.xcodeproj"; path = "examples/AdjustExample-Swift/AdjustExample-Swift.xcodeproj"; sourceTree = ""; }; 9D449DC51E6ED24000E7E80B /* AdjustExample-tvOS.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = "AdjustExample-tvOS.xcodeproj"; path = "examples/AdjustExample-tvOS/AdjustExample-tvOS.xcodeproj"; sourceTree = ""; }; @@ -1334,6 +1376,10 @@ 6FCC84F71F278CF300D6A0ED /* ADJReachability.m */, 9DD0E9AC1F44690B00B2A759 /* ADJUserDefaults.h */, 9DD0E9AD1F44690B00B2A759 /* ADJUserDefaults.m */, + 9D2F23E02447CE5C00B7CA90 /* ADJSubscription.h */, + 9D2F23E12447CE5C00B7CA90 /* ADJSubscription.m */, + 6FBEE8F124E2C26F00FEF3F1 /* ADJUrlStrategy.h */, + 6FBEE8F224E2C26F00FEF3F1 /* ADJUrlStrategy.m */, ); path = Adjust; sourceTree = ""; @@ -1434,6 +1480,10 @@ 9D0E2E58210B575600133B4F /* ADJTimerCycle.h */, 9D0E2E59210B575600133B4F /* ADJActivityHandler.m */, 9D0E2E5A210B575600133B4F /* ADJReachability.m */, + 9D2F24032447DD6000B7CA90 /* ADJSubscription.h */, + 9D2F24022447DD6000B7CA90 /* ADJSubscription.m */, + 6FBEE93224E4232800FEF3F1 /* ADJUrlStrategy.h */, + 6FBEE93324E4232800FEF3F1 /* ADJUrlStrategy.m */, ); path = Adjust; sourceTree = SOURCE_ROOT; @@ -1638,6 +1688,10 @@ 9DEAF0F2210072BC005CAEDB /* ADJTimerCycle.h */, 9DEAF0F3210072BC005CAEDB /* ADJActivityHandler.m */, 9DEAF0F4210072BC005CAEDB /* ADJReachability.m */, + 9D2F23FA2447DD2500B7CA90 /* ADJSubscription.h */, + 9D2F23FB2447DD2500B7CA90 /* ADJSubscription.m */, + 6FBEE92A24E4230700FEF3F1 /* ADJUrlStrategy.h */, + 6FBEE92B24E4230700FEF3F1 /* ADJUrlStrategy.m */, ); path = Adjust; sourceTree = SOURCE_ROOT; @@ -1717,6 +1771,10 @@ 96B671131D788F4A0090A023 /* ADJSessionParameters.m */, 6FCC85021F27944600D6A0ED /* ADJReachability.h */, 6FCC85031F27944600D6A0ED /* ADJReachability.m */, + 9D2F23F72447DCE800B7CA90 /* ADJSubscription.h */, + 9D2F23F62447DCE800B7CA90 /* ADJSubscription.m */, + 6FBEE92524E422EB00FEF3F1 /* ADJUrlStrategy.h */, + 6FBEE92424E422EB00FEF3F1 /* ADJUrlStrategy.m */, ); path = Adjust; sourceTree = SOURCE_ROOT; @@ -1816,6 +1874,10 @@ 96B671171D788F7A0090A023 /* ADJSessionParameters.m */, 6FCC85071F27948700D6A0ED /* ADJReachability.h */, 6FCC85061F27948700D6A0ED /* ADJReachability.m */, + 9D2F23FE2447DD3600B7CA90 /* ADJSubscription.h */, + 9D2F23FF2447DD3700B7CA90 /* ADJSubscription.m */, + 6FBEE92E24E4231300FEF3F1 /* ADJUrlStrategy.h */, + 6FBEE92F24E4231300FEF3F1 /* ADJUrlStrategy.m */, ); path = Adjust; sourceTree = SOURCE_ROOT; @@ -1843,9 +1905,12 @@ 96BCFBCD1AC99231005A65C5 /* Adjust.h in Headers */, 96BCFBCE1AC99235005A65C5 /* ADJEvent.h in Headers */, 96BCFBD01AC9923F005A65C5 /* ADJConfig.h in Headers */, + 6FBEE92824E422EB00FEF3F1 /* ADJUrlStrategy.h in Headers */, 9D363AC31BDA50FA00B47FE9 /* ADJLogger.h in Headers */, 96BCFBD11AC99246005A65C5 /* ADJAttribution.h in Headers */, + 9D2F23E22447CE5C00B7CA90 /* ADJSubscription.h in Headers */, 9601CAE81C74BAAE00670879 /* ADJEventFailure.h in Headers */, + 6FBEE8F324E2C26F00FEF3F1 /* ADJUrlStrategy.h in Headers */, 9601CAE41C74B70600670879 /* ADJEventSuccess.h in Headers */, 6FCC85011F278CF300D6A0ED /* ADJReachability.h in Headers */, 96BCFBD41AC99338005A65C5 /* NSData+ADJAdditions.h in Headers */, @@ -1890,6 +1955,7 @@ 9D0E2E6B210B575600133B4F /* ADJConfig.h in Headers */, 9D0E2E8F210B575600133B4F /* ADJEvent.h in Headers */, 9D0E2E73210B575600133B4F /* ADJAttribution.h in Headers */, + 9D2F24052447DD6000B7CA90 /* ADJSubscription.h in Headers */, 9D0E2EA2210B575600133B4F /* ADJEventFailure.h in Headers */, 9D0E2EA1210B575600133B4F /* ADJEventSuccess.h in Headers */, 9D0E2E9E210B575600133B4F /* ADJSessionFailure.h in Headers */, @@ -1905,6 +1971,7 @@ 9D0E2E98210B575600133B4F /* NSString+ADJAdditions.h in Headers */, 9D0E2EA7210B575600133B4F /* ADJBackoffStrategy.h in Headers */, 9D0E2E8C210B575600133B4F /* ADJDeviceInfo.h in Headers */, + 6FBEE93424E4232800FEF3F1 /* ADJUrlStrategy.h in Headers */, 9D0E2E90210B575600133B4F /* ADJSdkClickHandler.h in Headers */, 9D0E2E81210B575600133B4F /* ADJUtil.h in Headers */, 9D0E2E78210B575600133B4F /* ADJPackageHandler.h in Headers */, @@ -1929,8 +1996,10 @@ 9DE354D62100726300D211C9 /* AdjustSdkIm.h in Headers */, 9DEAF11C210072BC005CAEDB /* ADJKeychain.h in Headers */, 9DEAF0F9210072BC005CAEDB /* Adjust.h in Headers */, + 6FBEE92C24E4230800FEF3F1 /* ADJUrlStrategy.h in Headers */, 9DEAF0F5210072BC005CAEDB /* ADJConfig.h in Headers */, 9DEAF119210072BC005CAEDB /* ADJEvent.h in Headers */, + 9D2F23FC2447DD2500B7CA90 /* ADJSubscription.h in Headers */, 9DEAF0FD210072BC005CAEDB /* ADJAttribution.h in Headers */, 9DEAF12E210072BC005CAEDB /* ADJSessionSuccess.h in Headers */, 9DEAF128210072BC005CAEDB /* ADJSessionFailure.h in Headers */, @@ -1970,9 +2039,11 @@ 9DFA37B71C0F21D600782607 /* AdjustSdk.h in Headers */, 9DF9C9431D6F3CA5008E362F /* Adjust.h in Headers */, 9DF9C9231D6F3CA5008E362F /* ADJEvent.h in Headers */, + 6FBEE92924E422EB00FEF3F1 /* ADJUrlStrategy.h in Headers */, 9DF9C91F1D6F3CA5008E362F /* ADJConfig.h in Headers */, 9DF9C92B1D6F3CA5008E362F /* ADJLogger.h in Headers */, 9DF9C9191D6F3CA5008E362F /* ADJAttribution.h in Headers */, + 9D2F23F92447DCE800B7CA90 /* ADJSubscription.h in Headers */, 9DF9C9251D6F3CA5008E362F /* ADJEventFailure.h in Headers */, 9DF9C9271D6F3CA5008E362F /* ADJEventSuccess.h in Headers */, 9DF9C9371D6F3CA5008E362F /* ADJSessionFailure.h in Headers */, @@ -2011,9 +2082,11 @@ 9DFB06131D747070006D48FC /* AdjustSdkTv.h in Headers */, 9DFB06941D7470C0006D48FC /* Adjust.h in Headers */, 9DFB06741D7470C0006D48FC /* ADJEvent.h in Headers */, + 6FBEE93024E4231400FEF3F1 /* ADJUrlStrategy.h in Headers */, 9DFB06701D7470C0006D48FC /* ADJConfig.h in Headers */, 9DFB067C1D7470C0006D48FC /* ADJLogger.h in Headers */, 9DFB066A1D7470C0006D48FC /* ADJAttribution.h in Headers */, + 9D2F24002447DD3700B7CA90 /* ADJSubscription.h in Headers */, 9DFB06761D7470C0006D48FC /* ADJEventFailure.h in Headers */, 9DFB06781D7470C0006D48FC /* ADJEventSuccess.h in Headers */, 9DFB06881D7470C0006D48FC /* ADJSessionFailure.h in Headers */, @@ -2197,7 +2270,7 @@ 9679920518BBAE2800394606 /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 1130; + LastUpgradeCheck = 1150; ORGANIZATIONNAME = "adjust GmbH"; TargetAttributes = { 9615158E1CD2CB2C0022D336 = { @@ -2528,13 +2601,16 @@ 96E5E39418BBB48A008E7B30 /* ADJPackageBuilder.m in Sources */, 6FCC85001F278CF300D6A0ED /* ADJReachability.m in Sources */, 96E5E39618BBB48A008E7B30 /* ADJRequestHandler.m in Sources */, + 9D2F23E32447CE5C00B7CA90 /* ADJSubscription.m in Sources */, 96E5E39918BBB48A008E7B30 /* ADJUtil.m in Sources */, + 6FBEE92624E422EB00FEF3F1 /* ADJUrlStrategy.m in Sources */, 9609BC6A19EEA55800E02303 /* ADJEvent.m in Sources */, 965307F61A000DA400107FF9 /* ADJDeviceInfo.m in Sources */, 969952CF1A012F5300928462 /* ADJAttributionHandler.m in Sources */, 969952D21A01309200928462 /* ADJAttribution.m in Sources */, 960A8BB91A029A8000F2BB95 /* ADJConfig.m in Sources */, 96854A5A1B1F2779002B2874 /* ADJTimerOnce.m in Sources */, + 6FBEE8F524E2C26F00FEF3F1 /* ADJUrlStrategy.m in Sources */, 96854A601B1F278C002B2874 /* ADJTimerCycle.m in Sources */, 96FCC53B1C186426007BBFE1 /* ADJResponseData.m in Sources */, 968173841C3C2D07002AE1DE /* ADJSessionSuccess.m in Sources */, @@ -2614,11 +2690,13 @@ 9D0E2E6D210B575600133B4F /* ADJTimerOnce.m in Sources */, 9D0E2E77210B575600133B4F /* ADJEvent.m in Sources */, 9D0E2E8D210B575600133B4F /* ADJConfig.m in Sources */, + 9D2F24042447DD6000B7CA90 /* ADJSubscription.m in Sources */, 9D0E2E6E210B575600133B4F /* ADJAttributionHandler.m in Sources */, 9D0E2E87210B575600133B4F /* ADJBackoffStrategy.m in Sources */, 9D0E2EBB210B575600133B4F /* AdjustBridgeRegister.m in Sources */, 9D0E2E84210B575600133B4F /* ADJTimerCycle.m in Sources */, 9D0E2E6C210B575600133B4F /* ADJDeviceInfo.m in Sources */, + 6FBEE93524E4232800FEF3F1 /* ADJUrlStrategy.m in Sources */, 9D0E2EA5210B575600133B4F /* ADJPackageBuilder.m in Sources */, 9D0E2EAD210B575600133B4F /* ADJReachability.m in Sources */, 9D0E2E99210B575600133B4F /* ADJAttribution.m in Sources */, @@ -2657,6 +2735,7 @@ 9DEAF10A210072BC005CAEDB /* ADJSessionFailure.m in Sources */, 9DEAF121210072BC005CAEDB /* UIDevice+ADJAdditions.m in Sources */, 9DEAF105210072BC005CAEDB /* ADJSessionSuccess.m in Sources */, + 9D2F23FD2447DD2500B7CA90 /* ADJSubscription.m in Sources */, 9DEAF124210072BC005CAEDB /* ADJSystemProfile.m in Sources */, 9DEAF0FB210072BC005CAEDB /* ADJRequestHandler.m in Sources */, 9DEAF11B210072BC005CAEDB /* ADJActivityKind.m in Sources */, @@ -2664,6 +2743,7 @@ 9DEAF118210072BC005CAEDB /* ADJPackageHandler.m in Sources */, 9DEAF110210072BC005CAEDB /* ADJLogger.m in Sources */, 9DEAF0F7210072BC005CAEDB /* ADJTimerOnce.m in Sources */, + 6FBEE92D24E4230800FEF3F1 /* ADJUrlStrategy.m in Sources */, 9DEAF101210072BC005CAEDB /* ADJEvent.m in Sources */, 9DEAF117210072BC005CAEDB /* ADJConfig.m in Sources */, 9DEAF0F8210072BC005CAEDB /* ADJAttributionHandler.m in Sources */, @@ -2697,6 +2777,7 @@ 9DF9C92E1D6F3CA5008E362F /* ADJPackageBuilder.m in Sources */, 9DF9C9301D6F3CA5008E362F /* ADJPackageHandler.m in Sources */, 6FCC85051F27946100D6A0ED /* ADJReachability.m in Sources */, + 9D2F23F82447DCE800B7CA90 /* ADJSubscription.m in Sources */, 9DF9C9321D6F3CA5008E362F /* ADJRequestHandler.m in Sources */, 9DF9C9461D6F3CA5008E362F /* ADJUtil.m in Sources */, 9DF9C9241D6F3CA5008E362F /* ADJEvent.m in Sources */, @@ -2704,6 +2785,7 @@ 9DF9C91C1D6F3CA5008E362F /* ADJAttributionHandler.m in Sources */, 9DF9C91A1D6F3CA5008E362F /* ADJAttribution.m in Sources */, 9DF9C9201D6F3CA5008E362F /* ADJConfig.m in Sources */, + 6FBEE92724E422EB00FEF3F1 /* ADJUrlStrategy.m in Sources */, 9DF9C9401D6F3CA5008E362F /* ADJTimerOnce.m in Sources */, 9DF9C93E1D6F3CA5008E362F /* ADJTimerCycle.m in Sources */, 9DF9C9341D6F3CA5008E362F /* ADJResponseData.m in Sources */, @@ -2737,6 +2819,7 @@ 9DFB067F1D7470C0006D48FC /* ADJPackageBuilder.m in Sources */, 9DFB06811D7470C0006D48FC /* ADJPackageHandler.m in Sources */, 6FCC85091F27949000D6A0ED /* ADJReachability.m in Sources */, + 9D2F24012447DD3700B7CA90 /* ADJSubscription.m in Sources */, 9DFB06831D7470C0006D48FC /* ADJRequestHandler.m in Sources */, 9DFB06971D7470C0006D48FC /* ADJUtil.m in Sources */, 9DFB06751D7470C0006D48FC /* ADJEvent.m in Sources */, @@ -2744,6 +2827,7 @@ 9DFB066D1D7470C0006D48FC /* ADJAttributionHandler.m in Sources */, 9DFB066B1D7470C0006D48FC /* ADJAttribution.m in Sources */, 9DFB06711D7470C0006D48FC /* ADJConfig.m in Sources */, + 6FBEE93124E4231400FEF3F1 /* ADJUrlStrategy.m in Sources */, 9DFB06911D7470C0006D48FC /* ADJTimerOnce.m in Sources */, 9DFB068F1D7470C0006D48FC /* ADJTimerCycle.m in Sources */, 9DFB06851D7470C0006D48FC /* ADJResponseData.m in Sources */, diff --git a/Adjust.xcodeproj/xcshareddata/xcschemes/AdjustSdk.xcscheme b/Adjust.xcodeproj/xcshareddata/xcschemes/AdjustSdk.xcscheme index 40aed6fbe..fafe60d22 100644 --- a/Adjust.xcodeproj/xcshareddata/xcschemes/AdjustSdk.xcscheme +++ b/Adjust.xcodeproj/xcshareddata/xcschemes/AdjustSdk.xcscheme @@ -1,6 +1,6 @@ @property (nonatomic, copy) ADJAttribution *attribution; +@property (nonatomic, strong) ADJTrackingStatusManager *trackingStatusManager; + - (NSString *)adid; - (id)initWithConfig:(ADJConfig *)adjustConfig @@ -82,8 +85,7 @@ - (BOOL)updateAttributionI:(id)selfI attribution:(ADJAttribution *)attribution; - (void)setAttributionDetails:(NSDictionary *)attributionDetails - error:(NSError *)error - retriesLeft:(int)retriesLeft; + error:(NSError *)error; - (void)setOfflineMode:(BOOL)offline; - (void)sendFirstPackages; @@ -98,8 +100,8 @@ - (void)resetSessionPartnerParameters; - (void)trackAdRevenue:(NSString *)soruce payload:(NSData *)payload; - (void)disableThirdPartySharing; -- (NSString *)getBasePath; -- (NSString *)getGdprPath; +- (void)trackSubscription:(ADJSubscription *)subscription; +- (void)updateAttStatusFromUserCallback:(int)newAttStatusFromUser; - (ADJDeviceInfo *)deviceInfo; - (ADJActivityState *)activityState; @@ -112,8 +114,8 @@ @interface ADJActivityHandler : NSObject -+ (id)handlerWithConfig:(ADJConfig *)adjustConfig - savedPreLaunch:(ADJSavedPreLaunch *)savedPreLaunch; +- (id)initWithConfig:(ADJConfig *)adjustConfig + savedPreLaunch:(ADJSavedPreLaunch *)savedPreLaunch; - (void)addSessionCallbackParameterI:(ADJActivityHandler *)selfI key:(NSString *)key @@ -130,3 +132,19 @@ - (void)resetSessionPartnerParametersI:(ADJActivityHandler *)selfI; @end + +@interface ADJTrackingStatusManager : NSObject + +- (instancetype)initWithActivityHandler:(ADJActivityHandler *)activityHandler; + +- (void)checkForNewAttStatus; +- (void)updateAttStatusFromUserCallback:(int)newAttStatusFromUser; + +- (BOOL)canGetAttStatus; + +@property (nonatomic, readonly, assign) BOOL trackingEnabled; +@property (nonatomic, readonly, assign) int attStatus; + +@end + +extern NSString * const ADJiAdPackageKey; diff --git a/Adjust/ADJActivityHandler.m b/Adjust/ADJActivityHandler.m index 7c46373d6..2cfa7cc95 100644 --- a/Adjust/ADJActivityHandler.m +++ b/Adjust/ADJActivityHandler.m @@ -20,6 +20,9 @@ #import "NSString+ADJAdditions.h" #import "ADJSdkClickHandler.h" #import "ADJUserDefaults.h" +#import "ADJUrlStrategy.h" + +NSString * const ADJiAdPackageKey = @"iad3"; typedef void (^activityHandlerBlockI)(ADJActivityHandler * activityHandler); @@ -38,10 +41,7 @@ static NSTimeInterval kBackgroundTimerInterval; static double kSessionInterval; static double kSubSessionInterval; - -// number of tries -static const int kTryIadV3 = 2; -static const uint64_t kDelayRetryIad = 2 * NSEC_PER_SEC; // 1 second +static const int kiAdRetriesCount = 3; @implementation ADJInternalState @@ -83,12 +83,13 @@ - (id)init { @interface ADJActivityHandler() @property (nonatomic, strong) dispatch_queue_t internalQueue; -@property (nonatomic, strong) id packageHandler; -@property (nonatomic, strong) id attributionHandler; -@property (nonatomic, strong) id sdkClickHandler; +@property (nonatomic, strong) ADJPackageHandler *packageHandler; +@property (nonatomic, strong) ADJAttributionHandler *attributionHandler; +@property (nonatomic, strong) ADJSdkClickHandler *sdkClickHandler; @property (nonatomic, strong) ADJActivityState *activityState; @property (nonatomic, strong) ADJTimerCycle *foregroundTimer; @property (nonatomic, strong) ADJTimerOnce *backgroundTimer; +@property (nonatomic, assign) NSInteger iAdRetriesLeft; @property (nonatomic, strong) ADJInternalState *internalState; @property (nonatomic, strong) ADJDeviceInfo *deviceInfo; @property (nonatomic, strong) ADJTimerOnce *delayStartTimer; @@ -101,29 +102,32 @@ @interface ADJActivityHandler() @property (nonatomic, copy) NSData* deviceTokenData; @property (nonatomic, copy) NSString* basePath; @property (nonatomic, copy) NSString* gdprPath; +@property (nonatomic, copy) NSString* subscriptionPath; @end // copy from ADClientError typedef NS_ENUM(NSInteger, AdjADClientError) { AdjADClientErrorUnknown = 0, - AdjADClientErrorLimitAdTracking = 1, + AdjADClientErrorTrackingRestrictedOrDenied = 1, + AdjADClientErrorMissingData = 2, + AdjADClientErrorCorruptResponse = 3, + AdjADClientErrorRequestClientError = 4, + AdjADClientErrorRequestServerError = 5, + AdjADClientErrorRequestNetworkError = 6, + AdjADClientErrorUnsupportedPlatform = 7, + AdjCustomErrorTimeout = 100, }; #pragma mark - @implementation ADJActivityHandler @synthesize attribution = _attribution; - -+ (id)handlerWithConfig:(ADJConfig *)adjustConfig - savedPreLaunch:(ADJSavedPreLaunch *)savedPreLaunch -{ - return [[ADJActivityHandler alloc] initWithConfig:adjustConfig - savedPreLaunch:savedPreLaunch]; -} +@synthesize trackingStatusManager = _trackingStatusManager; - (id)initWithConfig:(ADJConfig *)adjustConfig - savedPreLaunch:(ADJSavedPreLaunch *)savedPreLaunch { + savedPreLaunch:(ADJSavedPreLaunch *)savedPreLaunch +{ self = [super init]; if (self == nil) return nil; @@ -154,11 +158,17 @@ - (id)initWithConfig:(ADJConfig *)adjustConfig [self.logger lockLogLevel]; // inject app token be available in activity state - [ADJActivityState saveAppToken:adjustConfig.appToken]; + [ADJUtil launchSynchronisedWithObject:[ADJActivityState class] + block:^{ + [ADJActivityState saveAppToken:adjustConfig.appToken]; + }]; // read files to have sync values available [self readAttribution]; [self readActivityState]; + + // register SKAdNetwork attribution + [self registerForSKAdNetworkAttribution]; self.internalState = [[ADJInternalState alloc] init]; @@ -195,19 +205,16 @@ - (id)initWithConfig:(ADJConfig *)adjustConfig // does not have the session response by default self.internalState.sessionResponseProcessed = NO; - if (savedPreLaunch.basePath != nil) { - self.basePath = savedPreLaunch.basePath; - } - if (savedPreLaunch.gdprPath != nil) { - self.gdprPath = savedPreLaunch.gdprPath; - } + self.iAdRetriesLeft = kiAdRetriesCount; + + self.trackingStatusManager = [[ADJTrackingStatusManager alloc] initWithActivityHandler:self]; self.internalQueue = dispatch_queue_create(kInternalQueueName, DISPATCH_QUEUE_SERIAL); [ADJUtil launchInQueue:self.internalQueue selfInject:self block:^(ADJActivityHandler * selfI) { [selfI initI:selfI - preLaunchActionsArray:savedPreLaunch.preLaunchActionsArray]; + preLaunchActions:savedPreLaunch]; }]; /* Not needed, done already in initI:preLaunchActionsArray: method. @@ -269,6 +276,8 @@ - (void)trackEvent:(ADJEvent *)event { } - (void)finishedTracking:(ADJResponseData *)responseData { + [self checkConversionValue:responseData]; + // redirect session responses to attribution handler to check for attribution information if ([responseData isKindOfClass:[ADJSessionResponseData class]]) { [self.attributionHandler checkSessionResponse:(ADJSessionResponseData*)responseData]; @@ -394,23 +403,53 @@ - (void)setTrackingStateOptedOut { - (void)setAttributionDetails:(NSDictionary *)attributionDetails error:(NSError *)error - retriesLeft:(int)retriesLeft { if (![ADJUtil isNull:error]) { [self.logger warn:@"Unable to read iAd details"]; - if (retriesLeft < 0) { - [self.logger warn:@"Limit number of retry for iAd v3 surpassed"]; + if (self.iAdRetriesLeft < 0) { + [self.logger warn:@"Number of retries to get iAd information surpassed"]; return; } - if (error.code == AdjADClientErrorUnknown) { - dispatch_time_t retryTime = dispatch_time(DISPATCH_TIME_NOW, kDelayRetryIad); - dispatch_after(retryTime, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ - [[UIDevice currentDevice] adjSetIad:self triesV3Left:retriesLeft]; - }); + switch (error.code) { + // if first request was unsuccessful and ended up with one of the following error codes: + // apply following retry logic: + // - 1st retry after 5 seconds + // - 2nd retry after 2 seconds + // - 3rd retry after 2 seconds + case AdjADClientErrorUnknown: + case AdjADClientErrorMissingData: + case AdjADClientErrorCorruptResponse: + case AdjADClientErrorRequestClientError: + case AdjADClientErrorRequestServerError: + case AdjADClientErrorRequestNetworkError: + case AdjCustomErrorTimeout: { + + [self saveiAdErrorCode:error.code]; + + int64_t iAdRetryDelay = 0; + switch (self.iAdRetriesLeft) { + case 2: + iAdRetryDelay = 5 * NSEC_PER_SEC; + break; + default: + iAdRetryDelay = 2 * NSEC_PER_SEC; + break; + } + self.iAdRetriesLeft = self.iAdRetriesLeft - 1; + dispatch_time_t retryTime = dispatch_time(DISPATCH_TIME_NOW, iAdRetryDelay); + dispatch_after(retryTime, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + [self checkForiAdI:self]; + }); + return; + } + case AdjADClientErrorTrackingRestrictedOrDenied: + case AdjADClientErrorUnsupportedPlatform: + return; + default: + return; } - return; } // check if it's a valid attribution details @@ -451,6 +490,31 @@ - (void)setAttributionDetails:(NSDictionary *)attributionDetails }]; } +- (void)saveiAdErrorCode:(NSInteger)code { + NSString *codeKey; + switch (code) { + case AdjADClientErrorUnknown: + codeKey = @"AdjADClientErrorUnknown"; + break; + case AdjADClientErrorMissingData: + codeKey = @"AdjADClientErrorMissingData"; + break; + case AdjADClientErrorCorruptResponse: + codeKey = @"AdjADClientErrorCorruptResponse"; + break; + case AdjCustomErrorTimeout: + codeKey = @"AdjCustomErrorTimeout"; + break; + default: + codeKey = @""; + break; + } + + if (![codeKey isEqualToString:@""]) { + [ADJUserDefaults saveiAdErrorKey:codeKey]; + } +} + - (void)sendIad3ClickPackage:(ADJActivityHandler *)selfI attributionDetails:(NSDictionary *)attributionDetails { @@ -465,19 +529,23 @@ - (void)sendIad3ClickPackage:(ADJActivityHandler *)selfI double now = [NSDate.date timeIntervalSince1970]; if (selfI.activityState != nil) { - double lastInterval = now - selfI.activityState.lastActivity; - selfI.activityState.lastInterval = lastInterval; + [ADJUtil launchSynchronisedWithObject:[ADJActivityState class] + block:^{ + double lastInterval = now - selfI.activityState.lastActivity; + selfI.activityState.lastInterval = lastInterval; + }]; } ADJPackageBuilder *clickBuilder = [[ADJPackageBuilder alloc] initWithDeviceInfo:selfI.deviceInfo activityState:selfI.activityState config:selfI.adjustConfig sessionParameters:self.sessionParameters + trackingStatusManager:self.trackingStatusManager createdAt:now]; clickBuilder.attributionDetails = attributionDetails; - ADJActivityPackage *clickPackage = [clickBuilder buildClickPackage:@"iad3"]; + ADJActivityPackage *clickPackage = [clickBuilder buildClickPackage:ADJiAdPackageKey]; [selfI.sdkClickHandler sendSdkClick:clickPackage]; } @@ -485,7 +553,10 @@ - (void)saveAttributionDetailsI:(ADJActivityHandler *)selfI attributionDetails:(NSDictionary *)attributionDetails { // save new iAd details - selfI.activityState.attributionDetails = attributionDetails; + [ADJUtil launchSynchronisedWithObject:[ADJActivityState class] + block:^{ + selfI.activityState.attributionDetails = attributionDetails; + }]; [selfI writeAttributionI:selfI]; } @@ -580,6 +651,14 @@ - (void)trackAdRevenue:(NSString *)source payload:(NSData *)payload { }]; } +- (void)trackSubscription:(ADJSubscription *)subscription { + [ADJUtil launchInQueue:self.internalQueue + selfInject:self + block:^(ADJActivityHandler * selfI) { + [selfI trackSubscriptionI:selfI subscription:subscription]; + }]; +} + - (void)disableThirdPartySharing { [ADJUtil launchInQueue:self.internalQueue selfInject:self @@ -588,6 +667,42 @@ - (void)disableThirdPartySharing { }]; } +- (void)writeActivityState { + [ADJUtil launchInQueue:self.internalQueue + selfInject:self + block:^(ADJActivityHandler * selfI) { + [selfI writeActivityStateI:selfI]; + }]; +} + +- (void)trackAttStatusUpdate { + [ADJUtil launchInQueue:self.internalQueue + selfInject:self + block:^(ADJActivityHandler * selfI) { + [selfI trackAttStatusUpdateI:selfI]; + }]; +} +- (void)trackAttStatusUpdateI:(ADJActivityHandler *)selfI { + double now = [NSDate.date timeIntervalSince1970]; + + ADJPackageBuilder *infoBuilder = [[ADJPackageBuilder alloc] + initWithDeviceInfo:selfI.deviceInfo + activityState:selfI.activityState + config:selfI.adjustConfig + sessionParameters:selfI.sessionParameters + trackingStatusManager:self.trackingStatusManager + createdAt:now]; + + ADJActivityPackage *infoPackage = [infoBuilder buildInfoPackage:@"att"]; + [selfI.packageHandler addPackage:infoPackage]; + + if (selfI.adjustConfig.eventBufferingEnabled) { + [selfI.logger info:@"Buffered event %@", infoPackage.suffix]; + } else { + [selfI.packageHandler sendFirstPackage]; + } +} + - (NSString *)getBasePath { return _basePath; } @@ -596,6 +711,10 @@ - (NSString *)getGdprPath { return _gdprPath; } +- (NSString *)getSubscriptionPath { + return _subscriptionPath; +} + - (void)teardown { [ADJAdjustFactory.logger verbose:@"ADJActivityHandler teardown"]; @@ -666,7 +785,7 @@ + (void)deleteSessionPartnerParameter { #pragma mark - internal - (void)initI:(ADJActivityHandler *)selfI -preLaunchActionsArray:(NSArray*)preLaunchActionsArray +preLaunchActions:(ADJSavedPreLaunch*)preLaunchActions { // get session values kSessionInterval = ADJAdjustFactory.sessionInterval; @@ -739,28 +858,55 @@ - (void)initI:(ADJActivityHandler *)selfI [ADJUtil updateUrlSessionConfiguration:selfI.adjustConfig]; - selfI.packageHandler = [ADJAdjustFactory packageHandlerForActivityHandler:selfI - startsSending:[selfI toSendI:selfI - sdkClickHandlerOnly:NO]]; + ADJUrlStrategy *packageHandlerUrlStrategy = + [[ADJUrlStrategy alloc] + initWithUrlStrategyInfo:selfI.adjustConfig.urlStrategy + extraPath:preLaunchActions.extraPath]; + + selfI.packageHandler = [[ADJPackageHandler alloc] + initWithActivityHandler:selfI + startsSending: + [selfI toSendI:selfI sdkClickHandlerOnly:NO] + userAgent:selfI.adjustConfig.userAgent + urlStrategy:packageHandlerUrlStrategy]; // update session parameters in package queue if ([selfI itHasToUpdatePackagesI:selfI]) { [selfI updatePackagesI:selfI]; } - selfI.attributionHandler = [ADJAdjustFactory attributionHandlerForActivityHandler:selfI - startsSending:[selfI toSendI:selfI - sdkClickHandlerOnly:NO]]; - selfI.sdkClickHandler = [ADJAdjustFactory sdkClickHandlerForActivityHandler:selfI - startsSending:[selfI toSendI:selfI - sdkClickHandlerOnly:YES]]; + ADJUrlStrategy *attributionHandlerUrlStrategy = + [[ADJUrlStrategy alloc] + initWithUrlStrategyInfo:selfI.adjustConfig.urlStrategy + extraPath:preLaunchActions.extraPath]; + + selfI.attributionHandler = [[ADJAttributionHandler alloc] + initWithActivityHandler:selfI + startsSending: + [selfI toSendI:selfI sdkClickHandlerOnly:NO] + userAgent:selfI.adjustConfig.userAgent + urlStrategy:attributionHandlerUrlStrategy]; + + ADJUrlStrategy *sdkClickHandlerUrlStrategy = + [[ADJUrlStrategy alloc] + initWithUrlStrategyInfo:selfI.adjustConfig.urlStrategy + extraPath:preLaunchActions.extraPath]; - if (self.adjustConfig.allowiAdInfoReading == YES) { - [[UIDevice currentDevice] adjSetIad:selfI triesV3Left:kTryIadV3]; + selfI.sdkClickHandler = [[ADJSdkClickHandler alloc] + initWithActivityHandler:selfI + startsSending:[selfI toSendI:selfI sdkClickHandlerOnly:YES] + userAgent:selfI.adjustConfig.userAgent + urlStrategy:sdkClickHandlerUrlStrategy]; + + if (selfI.adjustConfig.allowiAdInfoReading == YES) { + [selfI checkForiAdI:selfI]; } - [selfI preLaunchActionsI:selfI preLaunchActionsArray:preLaunchActionsArray]; + [selfI.trackingStatusManager checkForNewAttStatus]; + + [selfI preLaunchActionsI:selfI + preLaunchActionsArray:preLaunchActions.preLaunchActionsArray]; [ADJUtil launchInMainThreadWithInactive:^(BOOL isInactive) { [ADJUtil launchInQueue:self.internalQueue selfInject:self block:^(ADJActivityHandler * selfI) { @@ -802,7 +948,10 @@ - (void)processSessionI:(ADJActivityHandler *)selfI { NSData *deviceToken = [ADJUserDefaults getPushTokenData]; NSString *deviceTokenString = [ADJUtil convertDeviceToken:deviceToken]; NSString *pushToken = [ADJUserDefaults getPushTokenString]; - selfI.activityState.deviceToken = deviceTokenString != nil ? deviceTokenString : pushToken; + [ADJUtil launchSynchronisedWithObject:[ADJActivityState class] + block:^{ + selfI.activityState.deviceToken = deviceTokenString != nil ? deviceTokenString : pushToken; + }]; // track the first session package only if it's enabled if ([selfI.internalState isEnabled]) { @@ -814,14 +963,20 @@ - (void)processSessionI:(ADJActivityHandler *)selfI { if ([ADJUserDefaults getDisableThirdPartySharing]) { [selfI disableThirdPartySharingI:selfI]; } - selfI.activityState.sessionCount = 1; // this is the first session + [ADJUtil launchSynchronisedWithObject:[ADJActivityState class] + block:^{ + selfI.activityState.sessionCount = 1; // this is the first session + }]; [selfI transferSessionPackageI:selfI now:now]; } } - [selfI.activityState resetSessionAttributes:now]; - selfI.activityState.enabled = [selfI.internalState isEnabled]; - selfI.activityState.updatePackages = [selfI.internalState itHasToUpdatePackages]; + [ADJUtil launchSynchronisedWithObject:[ADJActivityState class] + block:^{ + [selfI.activityState resetSessionAttributes:now]; + selfI.activityState.enabled = [selfI.internalState isEnabled]; + selfI.activityState.updatePackages = [selfI.internalState itHasToUpdatePackages]; + }]; [selfI writeActivityStateI:selfI]; [ADJUserDefaults removePushToken]; @@ -833,7 +988,10 @@ - (void)processSessionI:(ADJActivityHandler *)selfI { double lastInterval = now - selfI.activityState.lastActivity; if (lastInterval < 0) { [selfI.logger error:@"Time travel!"]; - selfI.activityState.lastActivity = now; + [ADJUtil launchSynchronisedWithObject:[ADJActivityState class] + block:^{ + selfI.activityState.lastActivity = now; + }]; [selfI writeActivityStateI:selfI]; return; } @@ -846,9 +1004,12 @@ - (void)processSessionI:(ADJActivityHandler *)selfI { // new subsession if (lastInterval > kSubSessionInterval) { - selfI.activityState.subsessionCount++; - selfI.activityState.sessionLength += lastInterval; - selfI.activityState.lastActivity = now; + [ADJUtil launchSynchronisedWithObject:[ADJActivityState class] + block:^{ + selfI.activityState.subsessionCount++; + selfI.activityState.sessionLength += lastInterval; + selfI.activityState.lastActivity = now; + }]; [selfI.logger verbose:@"Started subsession %d of session %d", selfI.activityState.subsessionCount, selfI.activityState.sessionCount]; @@ -865,10 +1026,16 @@ - (void)trackNewSessionI:(double)now withActivityHandler:(ADJActivityHandler *)s } double lastInterval = now - selfI.activityState.lastActivity; - selfI.activityState.sessionCount++; - selfI.activityState.lastInterval = lastInterval; + [ADJUtil launchSynchronisedWithObject:[ADJActivityState class] + block:^{ + selfI.activityState.sessionCount++; + selfI.activityState.lastInterval = lastInterval; + }]; [selfI transferSessionPackageI:selfI now:now]; - [selfI.activityState resetSessionAttributes:now]; + [ADJUtil launchSynchronisedWithObject:[ADJActivityState class] + block:^{ + [selfI.activityState resetSessionAttributes:now]; + }]; [selfI writeActivityStateI:selfI]; } @@ -879,6 +1046,7 @@ - (void)transferSessionPackageI:(ADJActivityHandler *)selfI activityState:selfI.activityState config:selfI.adjustConfig sessionParameters:selfI.sessionParameters + trackingStatusManager:self.trackingStatusManager createdAt:now]; ADJActivityPackage *sessionPackage = [sessionBuilder buildSessionPackage:[selfI.internalState isInDelayedStart]]; [selfI.packageHandler addPackage:sessionPackage]; @@ -941,7 +1109,10 @@ - (void)eventI:(ADJActivityHandler *)selfI double now = [NSDate.date timeIntervalSince1970]; - selfI.activityState.eventCount++; + [ADJUtil launchSynchronisedWithObject:[ADJActivityState class] + block:^{ + selfI.activityState.eventCount++; + }]; [selfI updateActivityStateI:selfI now:now]; // create and populate event package @@ -950,6 +1121,7 @@ - (void)eventI:(ADJActivityHandler *)selfI activityState:selfI.activityState config:selfI.adjustConfig sessionParameters:selfI.sessionParameters + trackingStatusManager:self.trackingStatusManager createdAt:now]; ADJActivityPackage *eventPackage = [eventBuilder buildEventPackage:event isInDelay:[selfI.internalState isInDelayedStart]]; @@ -985,14 +1157,54 @@ - (void)adRevenueI:(ADJActivityHandler *)selfI double now = [NSDate.date timeIntervalSince1970]; // Create and submit ad revenue package. - ADJPackageBuilder *adRevenueBuilder = [[ADJPackageBuilder alloc] initWithDeviceInfo:selfI.deviceInfo - activityState:selfI.activityState - config:selfI.adjustConfig - sessionParameters:selfI.sessionParameters - createdAt:now]; + ADJPackageBuilder *adRevenueBuilder = [[ADJPackageBuilder alloc] + initWithDeviceInfo:selfI.deviceInfo + activityState:selfI.activityState + config:selfI.adjustConfig + sessionParameters:selfI.sessionParameters + trackingStatusManager:self.trackingStatusManager + createdAt:now]; + ADJActivityPackage *adRevenuePackage = [adRevenueBuilder buildAdRevenuePackage:source payload:payload]; [selfI.packageHandler addPackage:adRevenuePackage]; - [selfI.packageHandler sendFirstPackage]; + if (selfI.adjustConfig.eventBufferingEnabled) { + [selfI.logger info:@"Buffered event %@", adRevenuePackage.suffix]; + } else { + [selfI.packageHandler sendFirstPackage]; + } +} + +- (void)trackSubscriptionI:(ADJActivityHandler *)selfI + subscription:(ADJSubscription *)subscription { + if (!selfI.activityState) { + return; + } + if (![selfI isEnabledI:selfI]) { + return; + } + if (selfI.activityState.isGdprForgotten) { + return; + } + + double now = [NSDate.date timeIntervalSince1970]; + + // Create and submit ad revenue package. + ADJPackageBuilder *subscriptionBuilder = [[ADJPackageBuilder alloc] + initWithDeviceInfo:selfI.deviceInfo + activityState:selfI.activityState + config:selfI.adjustConfig + sessionParameters:selfI.sessionParameters + trackingStatusManager:self.trackingStatusManager + createdAt:now]; + + ADJActivityPackage *subscriptionPackage = [subscriptionBuilder buildSubscriptionPackage:subscription + isInDelay:[selfI.internalState isInDelayedStart]]; + [selfI.packageHandler addPackage:subscriptionPackage]; + if (selfI.adjustConfig.eventBufferingEnabled) { + [selfI.logger info:@"Buffered event %@", subscriptionPackage.suffix]; + } else { + [selfI.packageHandler sendFirstPackage]; + } } - (void)disableThirdPartySharingI:(ADJActivityHandler *)selfI { @@ -1013,18 +1225,22 @@ - (void)disableThirdPartySharingI:(ADJActivityHandler *)selfI { return; } - selfI.activityState.isThirdPartySharingDisabled = YES; + [ADJUtil launchSynchronisedWithObject:[ADJActivityState class] + block:^{ + selfI.activityState.isThirdPartySharingDisabled = YES; + }]; [selfI writeActivityStateI:selfI]; double now = [NSDate.date timeIntervalSince1970]; // build package ADJPackageBuilder *dtpsBuilder = [[ADJPackageBuilder alloc] - initWithDeviceInfo:selfI.deviceInfo - activityState:selfI.activityState - config:selfI.adjustConfig - sessionParameters:selfI.sessionParameters - createdAt:now]; + initWithDeviceInfo:selfI.deviceInfo + activityState:selfI.activityState + config:selfI.adjustConfig + sessionParameters:selfI.sessionParameters + trackingStatusManager:self.trackingStatusManager + createdAt:now]; ADJActivityPackage *dtpsPackage = [dtpsBuilder buildDisableThirdPartySharingPackage]; @@ -1128,6 +1344,8 @@ - (void)launchSdkClickResponseTasksI:(ADJActivityHandler *)selfI - (void)launchAttributionResponseTasksI:(ADJActivityHandler *)selfI attributionResponseData:(ADJAttributionResponseData *)attributionResponseData { + [selfI checkConversionValue:attributionResponseData]; + [selfI updateAdidI:selfI adid:attributionResponseData.adid]; BOOL toLaunchAttributionDelegate = [selfI updateAttributionI:selfI @@ -1179,7 +1397,10 @@ - (void)updateAdidI:(ADJActivityHandler *)selfI return; } - selfI.activityState.adid = adid; + [ADJUtil launchSynchronisedWithObject:[ADJActivityState class] + block:^{ + selfI.activityState.adid = adid; + }]; [selfI writeActivityStateI:selfI]; } @@ -1238,7 +1459,10 @@ - (void)setEnabledI:(ADJActivityHandler *)selfI enabled:(BOOL)enabled { } // Save new enabled state in activity state. - selfI.activityState.enabled = enabled; + [ADJUtil launchSynchronisedWithObject:[ADJActivityState class] + block:^{ + selfI.activityState.enabled = enabled; + }]; [selfI writeActivityStateI:selfI]; // Check if upon enabling install has been tracked. @@ -1260,8 +1484,8 @@ - (void)setEnabledI:(ADJActivityHandler *)selfI enabled:(BOOL)enabled { } else if ([ADJUserDefaults getDisableThirdPartySharing]) { [selfI disableThirdPartySharing]; } - if (self.adjustConfig.allowiAdInfoReading == YES) { - [[UIDevice currentDevice] adjSetIad:selfI triesV3Left:kTryIadV3]; + if (selfI.adjustConfig.allowiAdInfoReading == YES) { + [selfI checkForiAdI:selfI]; } } @@ -1272,6 +1496,10 @@ - (void)setEnabledI:(ADJActivityHandler *)selfI enabled:(BOOL)enabled { unPausingMessage:@"Resuming handlers due to SDK being enabled"]; } +- (void)checkForiAdI:(ADJActivityHandler *)selfI { + [[UIDevice currentDevice] adjCheckForiAd:selfI queue:selfI.internalQueue]; +} + - (void)setOfflineModeI:(ADJActivityHandler *)selfI offline:(BOOL)offline { // compare with the internal state @@ -1374,14 +1602,20 @@ - (void)appWillOpenUrlI:(ADJActivityHandler *)selfI } double now = [NSDate.date timeIntervalSince1970]; - double lastInterval = now - selfI.activityState.lastActivity; - selfI.activityState.lastInterval = lastInterval; - ADJPackageBuilder *clickBuilder = [[ADJPackageBuilder alloc] initWithDeviceInfo:selfI.deviceInfo - activityState:selfI.activityState - config:selfI.adjustConfig - sessionParameters:selfI.sessionParameters - createdAt:now]; - clickBuilder.deeplinkParameters = adjustDeepLinks; + [ADJUtil launchSynchronisedWithObject:[ADJActivityState class] + block:^{ + double lastInterval = now - selfI.activityState.lastActivity; + selfI.activityState.lastInterval = lastInterval; + }]; + ADJPackageBuilder *clickBuilder = [[ADJPackageBuilder alloc] + initWithDeviceInfo:selfI.deviceInfo + activityState:selfI.activityState + config:selfI.adjustConfig + sessionParameters:selfI.sessionParameters + trackingStatusManager:self.trackingStatusManager + createdAt:now]; + + clickBuilder.deeplinkParameters = [adjustDeepLinks copy]; clickBuilder.attribution = deeplinkAttribution; clickBuilder.clickTime = clickTime; clickBuilder.deeplink = [url absoluteString]; @@ -1469,16 +1703,21 @@ - (void)setDeviceTokenI:(ADJActivityHandler *)selfI } // save new push token - selfI.activityState.deviceToken = deviceTokenString; + [ADJUtil launchSynchronisedWithObject:[ADJActivityState class] + block:^{ + selfI.activityState.deviceToken = deviceTokenString; + }]; [selfI writeActivityStateI:selfI]; // send info package double now = [NSDate.date timeIntervalSince1970]; - ADJPackageBuilder *infoBuilder = [[ADJPackageBuilder alloc] initWithDeviceInfo:selfI.deviceInfo - activityState:selfI.activityState - config:selfI.adjustConfig - sessionParameters:selfI.sessionParameters - createdAt:now]; + ADJPackageBuilder *infoBuilder = [[ADJPackageBuilder alloc] + initWithDeviceInfo:selfI.deviceInfo + activityState:selfI.activityState + config:selfI.adjustConfig + sessionParameters:selfI.sessionParameters + trackingStatusManager:self.trackingStatusManager + createdAt:now]; ADJActivityPackage *infoPackage = [infoBuilder buildInfoPackage:@"push"]; @@ -1513,16 +1752,22 @@ - (void)setPushTokenI:(ADJActivityHandler *)selfI } // save new push token - selfI.activityState.deviceToken = pushToken; + [ADJUtil launchSynchronisedWithObject:[ADJActivityState class] + block:^{ + selfI.activityState.deviceToken = pushToken; + }]; [selfI writeActivityStateI:selfI]; // send info package double now = [NSDate.date timeIntervalSince1970]; - ADJPackageBuilder *infoBuilder = [[ADJPackageBuilder alloc] initWithDeviceInfo:selfI.deviceInfo - activityState:selfI.activityState - config:selfI.adjustConfig - sessionParameters:selfI.sessionParameters - createdAt:now]; + ADJPackageBuilder *infoBuilder = [[ADJPackageBuilder alloc] + initWithDeviceInfo:selfI.deviceInfo + activityState:selfI.activityState + config:selfI.adjustConfig + sessionParameters:selfI.sessionParameters + trackingStatusManager:self.trackingStatusManager + createdAt:now]; + ADJActivityPackage *infoPackage = [infoBuilder buildInfoPackage:@"push"]; [selfI.packageHandler addPackage:infoPackage]; @@ -1548,16 +1793,21 @@ - (void)setGdprForgetMeI:(ADJActivityHandler *)selfI { return; } - selfI.activityState.isGdprForgotten = YES; + [ADJUtil launchSynchronisedWithObject:[ADJActivityState class] + block:^{ + selfI.activityState.isGdprForgotten = YES; + }]; [selfI writeActivityStateI:selfI]; // Send GDPR package double now = [NSDate.date timeIntervalSince1970]; - ADJPackageBuilder *gdprBuilder = [[ADJPackageBuilder alloc] initWithDeviceInfo:selfI.deviceInfo - activityState:selfI.activityState - config:selfI.adjustConfig - sessionParameters:selfI.sessionParameters - createdAt:now]; + ADJPackageBuilder *gdprBuilder = [[ADJPackageBuilder alloc] + initWithDeviceInfo:selfI.deviceInfo + activityState:selfI.activityState + config:selfI.adjustConfig + sessionParameters:selfI.sessionParameters + trackingStatusManager:self.trackingStatusManager + createdAt:now]; ADJActivityPackage *gdprPackage = [gdprBuilder buildGdprPackage]; [selfI.packageHandler addPackage:gdprPackage]; @@ -1574,7 +1824,10 @@ - (void)setGdprForgetMeI:(ADJActivityHandler *)selfI { - (void)setTrackingStateOptedOutI:(ADJActivityHandler *)selfI { // In case of web opt out, once response from backend arrives isGdprForgotten field in this moment defaults to NO. // Set it to YES regardless of state, since at this moment it should be YES. - selfI.activityState.isGdprForgotten = YES; + [ADJUtil launchSynchronisedWithObject:[ADJActivityState class] + block:^{ + selfI.activityState.isGdprForgotten = YES; + }]; [selfI writeActivityStateI:selfI]; [selfI setEnabled:NO]; @@ -1617,14 +1870,20 @@ - (BOOL)updateActivityStateI:(ADJActivityHandler *)selfI // ignore late updates if (lastInterval > kSessionInterval) return NO; - selfI.activityState.lastActivity = now; + [ADJUtil launchSynchronisedWithObject:[ADJActivityState class] + block:^{ + selfI.activityState.lastActivity = now; + }]; if (lastInterval < 0) { [selfI.logger error:@"Time travel!"]; return YES; } else { - selfI.activityState.sessionLength += lastInterval; - selfI.activityState.timeSpent += lastInterval; + [ADJUtil launchSynchronisedWithObject:[ADJActivityState class] + block:^{ + selfI.activityState.sessionLength += lastInterval; + selfI.activityState.timeSpent += lastInterval; + }]; } return YES; @@ -1632,12 +1891,16 @@ - (BOOL)updateActivityStateI:(ADJActivityHandler *)selfI - (void)writeActivityStateI:(ADJActivityHandler *)selfI { - @synchronized ([ADJActivityState class]) { + [ADJUtil launchSynchronisedWithObject:[ADJActivityState class] + block:^{ if (selfI.activityState == nil) { return; } - [ADJUtil writeObject:selfI.activityState fileName:kActivityStateFilename objectName:@"Activity state"]; - } + [ADJUtil writeObject:selfI.activityState + fileName:kActivityStateFilename + objectName:@"Activity state" + syncObject:[ADJActivityState class]]; + }]; } - (void)teardownActivityStateS @@ -1655,7 +1918,10 @@ - (void)writeAttributionI:(ADJActivityHandler *)selfI { if (selfI.attribution == nil) { return; } - [ADJUtil writeObject:selfI.attribution fileName:kAttributionFilename objectName:@"Attribution"]; + [ADJUtil writeObject:selfI.attribution + fileName:kAttributionFilename + objectName:@"Attribution" + syncObject:[ADJAttribution class]]; } } @@ -1670,16 +1936,21 @@ - (void)teardownAttributionS } - (void)readActivityState { - [NSKeyedUnarchiver setClass:[ADJActivityState class] forClassName:@"AIActivityState"]; - self.activityState = [ADJUtil readObject:kActivityStateFilename - objectName:@"Activity state" - class:[ADJActivityState class]]; + [ADJUtil launchSynchronisedWithObject:[ADJActivityState class] + block:^{ + [NSKeyedUnarchiver setClass:[ADJActivityState class] forClassName:@"AIActivityState"]; + self.activityState = [ADJUtil readObject:kActivityStateFilename + objectName:@"Activity state" + class:[ADJActivityState class] + syncObject:[ADJActivityState class]]; + }]; } - (void)readAttribution { self.attribution = [ADJUtil readObject:kAttributionFilename objectName:@"Attribution" - class:[ADJAttribution class]]; + class:[ADJAttribution class] + syncObject:[ADJAttribution class]]; } - (void)writeSessionCallbackParametersI:(ADJActivityHandler *)selfI { @@ -1689,7 +1960,8 @@ - (void)writeSessionCallbackParametersI:(ADJActivityHandler *)selfI { } [ADJUtil writeObject:selfI.sessionParameters.callbackParameters fileName:kSessionCallbackParametersFilename - objectName:@"Session Callback parameters"]; + objectName:@"Session Callback parameters" + syncObject:[ADJSessionParameters class]]; } } @@ -1700,7 +1972,8 @@ - (void)writeSessionPartnerParametersI:(ADJActivityHandler *)selfI { } [ADJUtil writeObject:selfI.sessionParameters.partnerParameters fileName:kSessionPartnerParametersFilename - objectName:@"Session Partner parameters"]; + objectName:@"Session Partner parameters" + syncObject:[ADJSessionParameters class]]; } } @@ -1718,13 +1991,15 @@ - (void)teardownAllSessionParametersS { - (void)readSessionCallbackParametersI:(ADJActivityHandler *)selfI { selfI.sessionParameters.callbackParameters = [ADJUtil readObject:kSessionCallbackParametersFilename objectName:@"Session Callback parameters" - class:[NSDictionary class]]; + class:[NSDictionary class] + syncObject:[ADJSessionParameters class]]; } - (void)readSessionPartnerParametersI:(ADJActivityHandler *)selfI { selfI.sessionParameters.partnerParameters = [ADJUtil readObject:kSessionPartnerParametersFilename objectName:@"Session Partner parameters" - class:[NSDictionary class]]; + class:[NSDictionary class] + syncObject:[ADJSessionParameters class]]; } # pragma mark - handlers status @@ -1811,7 +2086,10 @@ - (BOOL)toSendI:(ADJActivityHandler *)selfI - (void)setAskingAttributionI:(ADJActivityHandler *)selfI askingAttribution:(BOOL)askingAttribution { - selfI.activityState.askingAttribution = askingAttribution; + [ADJUtil launchSynchronisedWithObject:[ADJActivityState class] + block:^{ + selfI.activityState.askingAttribution = askingAttribution; + }]; [selfI writeActivityStateI:selfI]; } @@ -1844,6 +2122,8 @@ - (void)foregroundTimerFiredI:(ADJActivityHandler *)selfI { if ([selfI updateActivityStateI:selfI now:now]) { [selfI writeActivityStateI:selfI]; } + + [selfI.trackingStatusManager checkForNewAttStatus]; } - (void)startBackgroundTimerI:(ADJActivityHandler *)selfI { @@ -1910,7 +2190,10 @@ - (void)delayStartI:(ADJActivityHandler *)selfI { selfI.internalState.updatePackages = YES; if (selfI.activityState != nil) { - selfI.activityState.updatePackages = YES; + [ADJUtil launchSynchronisedWithObject:[ADJActivityState class] + block:^{ + selfI.activityState.updatePackages = YES; + }]; [selfI writeActivityStateI:selfI]; } } @@ -1938,7 +2221,10 @@ - (void)updatePackagesI:(ADJActivityHandler *)selfI { // no longer needs to update packages selfI.internalState.updatePackages = NO; if (selfI.activityState != nil) { - selfI.activityState.updatePackages = NO; + [ADJUtil launchSynchronisedWithObject:[ADJActivityState class] + block:^{ + selfI.activityState.updatePackages = NO; + }]; [selfI writeActivityStateI:selfI]; } } @@ -2147,4 +2433,145 @@ - (BOOL)checkActivityStateI:(ADJActivityHandler *)selfI { } return YES; } + +- (void)registerForSKAdNetworkAttribution { + if (!self.adjustConfig.isSKAdNetworkHandlingActive) { + return; + } + id logger = [ADJAdjustFactory logger]; + + Class skAdNetwork = NSClassFromString(@"SKAdNetwork"); + if (skAdNetwork == nil) { + [logger warn:@"StoreKit framework not found in user's app (SKAdNetwork not found)"]; + return; + } + + SEL registerAttributionSelector = NSSelectorFromString(@"registerAppForAdNetworkAttribution"); + if ([skAdNetwork respondsToSelector:registerAttributionSelector]) { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Warc-performSelector-leaks" + [skAdNetwork performSelector:registerAttributionSelector]; +#pragma clang diagnostic pop + } +} + +- (void)checkConversionValue:(ADJResponseData *)responseData { + if (!self.adjustConfig.isSKAdNetworkHandlingActive) { + return; + } + if (responseData.jsonResponse == nil) { + return; + } + + NSNumber *conversionValue = [responseData.jsonResponse objectForKey:@"skadn_conv_value"]; + + if (!conversionValue) { + return; + } + + id logger = [ADJAdjustFactory logger]; + + Class skAdNetwork = NSClassFromString(@"SKAdNetwork"); + if (skAdNetwork == nil) { + [logger warn:@"StoreKit framework not found in user's app (SKAdNetwork not found)"]; + return; + } + + SEL updateConversionValueSelector = NSSelectorFromString(@"updateConversionValue:"); + if ([skAdNetwork respondsToSelector:updateConversionValueSelector]) { + NSInteger intValue = [conversionValue integerValue]; + + NSMethodSignature *conversionValueMethodSignature = [skAdNetwork methodSignatureForSelector:updateConversionValueSelector]; + NSInvocation *conversionInvocation = [NSInvocation invocationWithMethodSignature:conversionValueMethodSignature]; + [conversionInvocation setSelector:updateConversionValueSelector]; + [conversionInvocation setTarget:skAdNetwork]; + + [conversionInvocation setArgument:&intValue atIndex:2]; + [conversionInvocation invoke]; + } +} + +- (void)updateAttStatusFromUserCallback:(int)newAttStatusFromUser { + [self.trackingStatusManager updateAttStatusFromUserCallback:newAttStatusFromUser]; +} + +@end + +@interface ADJTrackingStatusManager () + +@property (nonatomic, readonly, weak) ADJActivityHandler *activityHandler; + +@end + +@implementation ADJTrackingStatusManager +// constructors +- (instancetype)initWithActivityHandler:(ADJActivityHandler *)activityHandler { + self = [super init]; + + _activityHandler = activityHandler; + + return self; +} +// public api +- (BOOL)canGetAttStatus { + return SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"14.0"); +} + +- (BOOL)trackingEnabled { + return UIDevice.currentDevice.adjTrackingEnabled; +} + +- (int)attStatus { + int readAttStatus = UIDevice.currentDevice.adjATTStatus; + + [self updateAttStatus:readAttStatus]; + + // does not need to track AttStatus update, since it will be send with package + + return readAttStatus; +} + +- (void)checkForNewAttStatus { + int readAttStatus = UIDevice.currentDevice.adjATTStatus; + + BOOL didUpdateAttStatus = [self updateAttStatus:readAttStatus]; + + if (!didUpdateAttStatus) { + return; + } + + [self.activityHandler trackAttStatusUpdate]; +} +- (void)updateAttStatusFromUserCallback:(int)newAttStatusFromUser { + BOOL didUpdateAttStatus = [self updateAttStatus:newAttStatusFromUser]; + + if (!didUpdateAttStatus) { + return; + } + + [self.activityHandler trackAttStatusUpdate]; +} + +// internal methods +- (BOOL)updateAttStatus:(int)readAttStatus { + if (readAttStatus < 0) { + return NO; + } + + if (self.activityHandler == nil || self.activityHandler.activityState == nil) { + return NO; + } + + if (readAttStatus == self.activityHandler.activityState.trackingManagerAuthorizationStatus) { + return NO; + } + + [ADJUtil launchSynchronisedWithObject:[ADJActivityState class] + block:^{ + self.activityHandler.activityState.trackingManagerAuthorizationStatus = readAttStatus; + }]; + [self.activityHandler writeActivityState]; + + return YES; +} @end diff --git a/Adjust/ADJActivityKind.h b/Adjust/ADJActivityKind.h index 6a13128c0..1f83c99d0 100644 --- a/Adjust/ADJActivityKind.h +++ b/Adjust/ADJActivityKind.h @@ -13,16 +13,17 @@ #endif typedef NS_ENUM(int, ADJActivityKind) { - ADJActivityKindUnknown = 0, - ADJActivityKindSession = 1, - ADJActivityKindEvent = 2, -// ADJActivityKindRevenue = 3, - ADJActivityKindClick = 4, - ADJActivityKindAttribution = 5, - ADJActivityKindInfo = 6, - ADJActivityKindGdpr = 7, - ADJActivityKindAdRevenue = 8, - ADJActivityKindDisableThirdPartySharing = 9 + ADJActivityKindUnknown = 0, + ADJActivityKindSession = 1, + ADJActivityKindEvent = 2, + // ADJActivityKindRevenue = 3, + ADJActivityKindClick = 4, + ADJActivityKindAttribution = 5, + ADJActivityKindInfo = 6, + ADJActivityKindGdpr = 7, + ADJActivityKindAdRevenue = 8, + ADJActivityKindDisableThirdPartySharing = 9, + ADJActivityKindSubscription = 10 }; @interface ADJActivityKindUtil : NSObject diff --git a/Adjust/ADJActivityKind.m b/Adjust/ADJActivityKind.m index 694ff623f..7c8cb862d 100644 --- a/Adjust/ADJActivityKind.m +++ b/Adjust/ADJActivityKind.m @@ -29,6 +29,8 @@ + (ADJActivityKind)activityKindFromString:(NSString *)activityKindString { return ADJActivityKindAdRevenue; } else if ([@"disable_third_party_sharing" isEqualToString:activityKindString]) { return ADJActivityKindDisableThirdPartySharing; + } else if ([@"subscription" isEqualToString:activityKindString]) { + return ADJActivityKindSubscription; } else { return ADJActivityKindUnknown; } @@ -52,6 +54,8 @@ + (NSString *)activityKindToString:(ADJActivityKind)activityKind { return @"ad_revenue"; case ADJActivityKindDisableThirdPartySharing: return @"disable_third_party_sharing"; + case ADJActivityKindSubscription: + return @"subscription"; default: return @"unknown"; } diff --git a/Adjust/ADJActivityPackage.h b/Adjust/ADJActivityPackage.h index 668d9e5a9..3db72b530 100644 --- a/Adjust/ADJActivityPackage.h +++ b/Adjust/ADJActivityPackage.h @@ -16,8 +16,6 @@ @property (nonatomic, copy) NSString *clientSdk; -@property (nonatomic, assign) NSInteger retries; - @property (nonatomic, strong) NSMutableDictionary *parameters; @property (nonatomic, strong) NSDictionary *partnerParameters; @@ -36,8 +34,4 @@ - (NSString *)failureMessage; -- (NSInteger)getRetries; - -- (NSInteger)increaseRetries; - @end diff --git a/Adjust/ADJActivityPackage.m b/Adjust/ADJActivityPackage.m index 6231e28ab..a92954361 100644 --- a/Adjust/ADJActivityPackage.m +++ b/Adjust/ADJActivityPackage.m @@ -15,7 +15,7 @@ @implementation ADJActivityPackage - (NSString *)extendedString { NSMutableString *builder = [NSMutableString string]; - NSArray *excludedKeys = @[@"secret_id", @"app_secret", @"event_callback_id"]; + NSArray *excludedKeys = @[@"secret_id", @"app_secret", @"signature", @"headers_id", @"native_version", @"event_callback_id"]; [builder appendFormat:@"Path: %@\n", self.path]; [builder appendFormat:@"ClientSdk: %@\n", self.clientSdk]; @@ -42,16 +42,6 @@ - (NSString *)extendedString { return builder; } -- (NSInteger)getRetries { - return self.retries; -} - -- (NSInteger)increaseRetries { - self.retries = self.retries + 1; - - return self.retries; -} - - (NSString *)description { return [NSString stringWithFormat:@"%@%@", [ADJActivityKindUtil activityKindToString:self.activityKind], self.suffix]; } diff --git a/Adjust/ADJActivityState.h b/Adjust/ADJActivityState.h index ac141039b..a6cb96fc6 100644 --- a/Adjust/ADJActivityState.h +++ b/Adjust/ADJActivityState.h @@ -23,6 +23,8 @@ @property (nonatomic, copy) NSString *adid; @property (nonatomic, strong) NSDictionary *attributionDetails; +@property (nonatomic, assign) int trackingManagerAuthorizationStatus; + // Global counters @property (nonatomic, assign) int eventCount; @property (nonatomic, assign) int sessionCount; diff --git a/Adjust/ADJActivityState.m b/Adjust/ADJActivityState.m index 3a3b9c14e..d8606cf9f 100644 --- a/Adjust/ADJActivityState.m +++ b/Adjust/ADJActivityState.m @@ -41,6 +41,7 @@ - (id)init { self.deviceToken = nil; self.transactionIds = [NSMutableArray arrayWithCapacity:kTransactionIdCount]; self.updatePackages = NO; + self.trackingManagerAuthorizationStatus = -1; return self; } @@ -106,11 +107,11 @@ - (void)assignUuid:(NSString *)uuid { } - (NSString *)description { - return [NSString stringWithFormat:@"ec:%d sc:%d ssc:%d ask:%d sl:%.1f ts:%.1f la:%.1f dt:%@ gdprf:%d dtps:%d", + return [NSString stringWithFormat:@"ec:%d sc:%d ssc:%d ask:%d sl:%.1f ts:%.1f la:%.1f dt:%@ gdprf:%d dtps:%d att:%d", self.eventCount, self.sessionCount, self.subsessionCount, self.askingAttribution, self.sessionLength, self.timeSpent, self.lastActivity, self.deviceToken, - self.isGdprForgotten, self.isThirdPartySharingDisabled]; + self.isGdprForgotten, self.isThirdPartySharingDisabled, self.trackingManagerAuthorizationStatus]; } #pragma mark - NSCoding protocol methods @@ -185,6 +186,13 @@ - (id)initWithCoder:(NSCoder *)decoder { self.attributionDetails = [decoder decodeObjectForKey:@"attributionDetails"]; } + if ([decoder containsValueForKey:@"trackingManagerAuthorizationStatus"]) { + self.trackingManagerAuthorizationStatus = + [decoder decodeIntForKey:@"trackingManagerAuthorizationStatus"]; + } else { + self.trackingManagerAuthorizationStatus = -1; + } + self.lastInterval = -1; return self; @@ -207,6 +215,8 @@ - (void)encodeWithCoder:(NSCoder *)encoder { [encoder encodeBool:self.updatePackages forKey:@"updatePackages"]; [encoder encodeObject:self.adid forKey:@"adid"]; [encoder encodeObject:self.attributionDetails forKey:@"attributionDetails"]; + [encoder encodeInt:self.trackingManagerAuthorizationStatus + forKey:@"trackingManagerAuthorizationStatus"]; } #pragma mark - NSCopying protocol methods @@ -230,6 +240,7 @@ - (id)copyWithZone:(NSZone *)zone { copy.isThirdPartySharingDisabled = self.isThirdPartySharingDisabled; copy.deviceToken = [self.deviceToken copyWithZone:zone]; copy.updatePackages = self.updatePackages; + copy.trackingManagerAuthorizationStatus = self.trackingManagerAuthorizationStatus; } return copy; diff --git a/Adjust/ADJAdditions/UIDevice+ADJAdditions.h b/Adjust/ADJAdditions/UIDevice+ADJAdditions.h index a506ac0eb..f47fbb56b 100644 --- a/Adjust/ADJAdditions/UIDevice+ADJAdditions.h +++ b/Adjust/ADJAdditions/UIDevice+ADJAdditions.h @@ -6,12 +6,14 @@ // Copyright © 2012-2018 Adjust GmbH. All rights reserved. // -#import #import +#import +#import "ADJDeviceInfo.h" #import "ADJActivityHandler.h" @interface UIDevice(ADJAdditions) +- (int)adjATTStatus; - (BOOL)adjTrackingEnabled; - (NSString *)adjIdForAdvertisers; - (NSString *)adjFbAnonymousId; @@ -19,6 +21,9 @@ - (NSString *)adjDeviceName; - (NSString *)adjCreateUuid; - (NSString *)adjVendorId; -- (void)adjSetIad:(ADJActivityHandler *)activityHandler - triesV3Left:(int)triesV3Left; +- (NSString *)adjDeviceId:(ADJDeviceInfo *)deviceInfo; +- (void)adjCheckForiAd:(ADJActivityHandler *)activityHandler queue:(dispatch_queue_t)queue; + +- (void)requestTrackingAuthorizationWithCompletionHandler:(void (^)(NSUInteger status))completion; + @end diff --git a/Adjust/ADJAdditions/UIDevice+ADJAdditions.m b/Adjust/ADJAdditions/UIDevice+ADJAdditions.m index ca185e7e4..6bf199197 100644 --- a/Adjust/ADJAdditions/UIDevice+ADJAdditions.m +++ b/Adjust/ADJAdditions/UIDevice+ADJAdditions.m @@ -19,29 +19,87 @@ #import #endif +#import "ADJUtil.h" +#import "ADJSystemProfile.h" #import "ADJAdjustFactory.h" @implementation UIDevice(ADJAdditions) +- (Class)adSupportManager { + NSString *className = [NSString adjJoin:@"A", @"S", @"identifier", @"manager", nil]; + Class class = NSClassFromString(className); + + return class; +} + +- (Class)appTrackingManager { + NSString *className = [NSString adjJoin:@"A", @"T", @"tracking", @"manager", nil]; + Class class = NSClassFromString(className); + + return class; +} + +- (int)adjATTStatus { + Class appTrackingClass = [self appTrackingManager]; + if (appTrackingClass != nil) { + NSString *keyAuthorization = [NSString adjJoin:@"tracking", @"authorization", @"status", nil]; + SEL selAuthorization = NSSelectorFromString(keyAuthorization); + if ([appTrackingClass respondsToSelector:selAuthorization]) { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunguarded-availability" +#pragma clang diagnostic ignored "-Warc-performSelector-leaks" + return (int)[appTrackingClass performSelector:selAuthorization]; +#pragma clang diagnostic pop + } + } + + return -1; +} + +- (void)requestTrackingAuthorizationWithCompletionHandler:(void (^)(NSUInteger status))completion +{ + Class appTrackingClass = [self appTrackingManager]; + if (appTrackingClass == nil) { + return; + } + NSString *requestAuthorization = [NSString adjJoin: + @"request", + @"tracking", + @"authorization", + @"with", + @"completion", + @"handler:", nil]; + SEL selRequestAuthorization = NSSelectorFromString(requestAuthorization); + if (![appTrackingClass respondsToSelector:selRequestAuthorization]) { + return; + } +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunguarded-availability" +#pragma clang diagnostic ignored "-Warc-performSelector-leaks" + [appTrackingClass performSelector:selRequestAuthorization withObject:completion]; +#pragma clang diagnostic pop +} + - (BOOL)adjTrackingEnabled { #if ADJUST_NO_IDFA return NO; #else - // return [[ASIdentifierManager sharedManager] isAdvertisingTrackingEnabled]; - NSString *className = [NSString adjJoin:@"A", @"S", @"identifier", @"manager", nil]; - Class class = NSClassFromString(className); - if (class == nil) { + +// return [[ASIdentifierManager sharedManager] isAdvertisingTrackingEnabled]; + Class adSupportClass = [self adSupportManager]; + if (adSupportClass == nil) { return NO; } -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Warc-performSelector-leaks" + NSString *keyManager = [NSString adjJoin:@"shared", @"manager", nil]; SEL selManager = NSSelectorFromString(keyManager); - if (![class respondsToSelector:selManager]) { + if (![adSupportClass respondsToSelector:selManager]) { return NO; } - id manager = [class performSelector:selManager]; - +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Warc-performSelector-leaks" + id manager = [adSupportClass performSelector:selManager]; + NSString *keyEnabled = [NSString adjJoin:@"is", @"advertising", @"tracking", @"enabled", nil]; SEL selEnabled = NSSelectorFromString(keyEnabled); if (![manager respondsToSelector:selEnabled]) { @@ -58,9 +116,8 @@ - (NSString *)adjIdForAdvertisers { return @""; #else // return [[[ASIdentifierManager sharedManager] advertisingIdentifier] UUIDString]; - NSString *className = [NSString adjJoin:@"A", @"S", @"identifier", @"manager", nil]; - Class class = NSClassFromString(className); - if (class == nil) { + Class adSupportClass = [self adSupportManager]; + if (adSupportClass == nil) { return @""; } #pragma clang diagnostic push @@ -68,10 +125,10 @@ - (NSString *)adjIdForAdvertisers { NSString *keyManager = [NSString adjJoin:@"shared", @"manager", nil]; SEL selManager = NSSelectorFromString(keyManager); - if (![class respondsToSelector:selManager]) { + if (![adSupportClass respondsToSelector:selManager]) { return @""; } - id manager = [class performSelector:selManager]; + id manager = [adSupportClass performSelector:selManager]; NSString *keyIdentifier = [NSString adjJoin:@"advertising", @"identifier", nil]; SEL selIdentifier = NSSelectorFromString(keyIdentifier); @@ -96,20 +153,33 @@ - (NSString *)adjFbAnonymousId { #if TARGET_OS_TV return @""; #else + // pre FB SDK v6.0.0 // return [FBSDKAppEventsUtility retrievePersistedAnonymousID]; - Class class = NSClassFromString(@"FBSDKAppEventsUtility"); - if (class == nil) { - return @""; - } + // post FB SDK v6.0.0 + // return [FBSDKBasicUtility retrievePersistedAnonymousID]; + Class class = nil; SEL selGetId = NSSelectorFromString(@"retrievePersistedAnonymousID"); - if (![class respondsToSelector:selGetId]) { - return @""; + class = NSClassFromString(@"FBSDKBasicUtility"); + if (class != nil) { + if ([class respondsToSelector:selGetId]) { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Warc-performSelector-leaks" + NSString *fbAnonymousId = (NSString *)[class performSelector:selGetId]; + return fbAnonymousId; +#pragma clang diagnostic pop + } } + class = NSClassFromString(@"FBSDKAppEventsUtility"); + if (class != nil) { + if ([class respondsToSelector:selGetId]) { #pragma clang diagnostic push #pragma clang diagnostic ignored "-Warc-performSelector-leaks" - NSString *fbAnonymousId = (NSString *)[class performSelector:selGetId]; + NSString *fbAnonymousId = (NSString *)[class performSelector:selGetId]; + return fbAnonymousId; #pragma clang diagnostic pop - return fbAnonymousId; + } + } + return @""; #endif } @@ -144,8 +214,113 @@ - (NSString *)adjVendorId { return @""; } -- (void)adjSetIad:(ADJActivityHandler *)activityHandler - triesV3Left:(int)triesV3Left { +- (NSString *)adjDeviceId:(ADJDeviceInfo *)deviceInfo { + int languageMaxLength = 16; + NSString *language = deviceInfo.languageCode; + NSString *binaryLanguage = [ADJUtil stringToBinaryString:language]; + NSString *binaryLanguageFormatted = [ADJUtil enforceParameterLength:binaryLanguage withMaxlength:languageMaxLength]; + + int hardwareNameMaxLength = 48; + NSString *hardwareName = deviceInfo.machineModel; + NSString *binaryHardwareName = [ADJUtil stringToBinaryString:hardwareName]; + NSString *binaryHardwareNameFormatted = [ADJUtil enforceParameterLength:binaryHardwareName withMaxlength:hardwareNameMaxLength]; + + NSArray *versionParts = [deviceInfo.systemVersion componentsSeparatedByString:@"."]; + int osVersionMajor = [[versionParts objectAtIndex:0] intValue]; + int osVersionMinor = [[versionParts objectAtIndex:1] intValue]; + int osVersionPatch = [versionParts count] == 3 ? [[versionParts objectAtIndex:2] intValue] : 0; + + int osVersionMajorMaxLength = 8; + NSString *binaryOsVersionMajor = [ADJUtil decimalToBinaryString:osVersionMajor]; + NSString *binaryOsVersionMajorFormatted = [ADJUtil enforceParameterLength:binaryOsVersionMajor withMaxlength:osVersionMajorMaxLength]; + + int osVersionMinorMaxLength = 8; + NSString *binaryOsVersionMinor = [ADJUtil decimalToBinaryString:osVersionMinor]; + NSString *binaryOsVersionMinorFormatted = [ADJUtil enforceParameterLength:binaryOsVersionMinor withMaxlength:osVersionMinorMaxLength]; + + int osVersionPatchMaxLength = 8; + NSString *binaryOsVersionPatch = [ADJUtil decimalToBinaryString:osVersionPatch]; + NSString *binaryOsVersionPatchFormatted = [ADJUtil enforceParameterLength:binaryOsVersionPatch withMaxlength:osVersionPatchMaxLength]; + + int mccMaxLength = 24; + NSString *mcc = [ADJUtil readMCC]; + NSString *binaryMcc = [ADJUtil stringToBinaryString:mcc]; + NSString *binaryMccFormatted = [ADJUtil enforceParameterLength:binaryMcc withMaxlength:mccMaxLength]; + + int mncMaxLength = 24; + NSString *mnc = [ADJUtil readMNC]; + NSString *binaryMnc = [ADJUtil stringToBinaryString:mnc]; + NSString *binaryMncFormatted = [ADJUtil enforceParameterLength:binaryMnc withMaxlength:mncMaxLength]; + + int chargingStatusMaxLength = 8; + NSUInteger chargingStatus = [ADJSystemProfile chargingStatus]; + NSString *binaryChargingStatus = [ADJUtil decimalToBinaryString:chargingStatus]; + NSString *binaryChargingStatusFormatted = [ADJUtil enforceParameterLength:binaryChargingStatus withMaxlength:chargingStatusMaxLength]; + + int batteryLevelMaxSize = 8; + NSUInteger batteryLevel = [ADJSystemProfile batteryLevel]; + NSString *binaryBatteryLevel = [ADJUtil decimalToBinaryString:batteryLevel]; + NSString *binaryBatteryLevelFormatted = [ADJUtil enforceParameterLength:binaryBatteryLevel withMaxlength:batteryLevelMaxSize]; + + int totalSpaceMaxSize = 24; + NSUInteger totalSpace = [ADJSystemProfile totalDiskSpace]; + NSString *binaryTotalSpace = [ADJUtil decimalToBinaryString:totalSpace]; + NSString *binaryTotalSpaceFormatted = [ADJUtil enforceParameterLength:binaryTotalSpace withMaxlength:totalSpaceMaxSize]; + + int freeSpaceMaxSize = 24; + NSUInteger freeSpace = [ADJSystemProfile freeDiskSpace]; + NSString *binaryFreeSpace = [ADJUtil decimalToBinaryString:freeSpace]; + NSString *binaryFreeSpaceFormatted = [ADJUtil enforceParameterLength:binaryFreeSpace withMaxlength:freeSpaceMaxSize]; + + int systemUptimeMaxSize = 24; + NSUInteger systemUptime = [ADJSystemProfile systemUptime]; + NSString *binarySystemUptime = [ADJUtil decimalToBinaryString:systemUptime]; + NSString *binarySystemUptimeFormatted = [ADJUtil enforceParameterLength:binarySystemUptime withMaxlength:systemUptimeMaxSize]; + + int lastBootTimeMaxSize = 32; + NSUInteger lastBootTime = [ADJSystemProfile lastBootTime]; + NSString *binaryLastBootTime = [ADJUtil decimalToBinaryString:lastBootTime]; + NSString *binaryLastBootTimeFormatted = [ADJUtil enforceParameterLength:binaryLastBootTime withMaxlength:lastBootTimeMaxSize]; + + NSString *concatenated = [NSString stringWithFormat:@"%@%@%@%@%@%@%@%@%@%@%@%@%@", + binaryLanguageFormatted, + binaryHardwareNameFormatted, + binaryOsVersionMajorFormatted, + binaryOsVersionMinorFormatted, + binaryOsVersionPatchFormatted, + binaryMccFormatted, + binaryMncFormatted, + binaryChargingStatusFormatted, + binaryBatteryLevelFormatted, + binaryTotalSpaceFormatted, + binaryFreeSpaceFormatted, + binarySystemUptimeFormatted, + binaryLastBootTimeFormatted]; + + // make sure concatenated string length is multiple of 4 + if (concatenated.length % 4 != 0) { + int numberOfBits = concatenated.length % 4; + while (numberOfBits != 4) { + concatenated = [@"0" stringByAppendingString:concatenated]; + numberOfBits += 1; + } + } + + NSString *mParameter = @""; + for (NSUInteger i = 0; i < concatenated.length; i += 4) { + // get fourplet substring + NSString *fourplet = [concatenated substringWithRange:NSMakeRange(i, 4)]; + // convert fourplet to decimal number + long decimalFourplet = strtol([fourplet UTF8String], NULL, 2); + // append hex value of fourplet to final parameter + mParameter = [mParameter stringByAppendingString:[NSString stringWithFormat:@"%lX", decimalFourplet]]; + } + + return mParameter; +} + +- (void)adjCheckForiAd:(ADJActivityHandler *)activityHandler queue:(dispatch_queue_t)queue { + // if no tries for iad v3 left, stop trying id logger = [ADJAdjustFactory logger]; #if ADJUST_NO_IAD || TARGET_OS_TV @@ -174,43 +349,64 @@ - (void)adjSetIad:(ADJActivityHandler *)activityHandler } [logger debug:@"iAd framework successfully found in user's app"]; - [logger debug:@"iAd with %d tries to read v3", triesV3Left]; - // if no tries for iad v3 left, stop trying - if (triesV3Left == 0) { - [logger warn:@"Reached limit number of retry for iAd v3"]; - return; - } + BOOL iAdInformationAvailable = [self setiAdWithDetails:activityHandler + adcClientSharedInstance:ADClientSharedClientInstance + queue:queue]; - BOOL isIadV3Avaliable = [self adjSetIadWithDetails:activityHandler - ADClientSharedClientInstance:ADClientSharedClientInstance - retriesLeft:(triesV3Left - 1)]; - - // if iad v3 not available - if (!isIadV3Avaliable) { - [logger warn:@"iAd v3 not available"]; + if (!iAdInformationAvailable) { + [logger warn:@"iAd information not available"]; return; } #pragma clang diagnostic pop #endif } -- (BOOL)adjSetIadWithDetails:(ADJActivityHandler *)activityHandler -ADClientSharedClientInstance:(id)ADClientSharedClientInstance - retriesLeft:(int)retriesLeft { - SEL iadDetailsSelector = NSSelectorFromString(@"requestAttributionDetailsWithBlock:"); - if (![ADClientSharedClientInstance respondsToSelector:iadDetailsSelector]) { +- (BOOL)setiAdWithDetails:(ADJActivityHandler *)activityHandler + adcClientSharedInstance:(id)ADClientSharedClientInstance + queue:(dispatch_queue_t)queue { + SEL iAdDetailsSelector = NSSelectorFromString(@"requestAttributionDetailsWithBlock:"); + if (![ADClientSharedClientInstance respondsToSelector:iAdDetailsSelector]) { return NO; } - + + __block Class lock = [ADJActivityHandler class]; + __block BOOL completed = NO; + #pragma clang diagnostic push #pragma clang diagnostic ignored "-Warc-performSelector-leaks" - [ADClientSharedClientInstance performSelector:iadDetailsSelector + [ADClientSharedClientInstance performSelector:iAdDetailsSelector withObject:^(NSDictionary *attributionDetails, NSError *error) { - [activityHandler setAttributionDetails:attributionDetails error:error retriesLeft:retriesLeft]; - }]; + + @synchronized (lock) { + if (completed) { + return; + } else { + completed = YES; + } + } + + [activityHandler setAttributionDetails:attributionDetails + error:error]; + }]; #pragma clang diagnostic pop - + + // 5 seconds of timeout + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5.0 * NSEC_PER_SEC)), queue, ^{ + @synchronized (lock) { + if (completed) { + return; + } else { + completed = YES; + } + } + + [activityHandler setAttributionDetails:nil + error:[NSError errorWithDomain:@"com.adjust.sdk.iAd" + code:100 + userInfo:@{@"Error reason": @"iAd request timed out"}]]; + }); + return YES; } diff --git a/Adjust/ADJAdjustFactory.h b/Adjust/ADJAdjustFactory.h index fab71f48f..cef20d7e3 100644 --- a/Adjust/ADJAdjustFactory.h +++ b/Adjust/ADJAdjustFactory.h @@ -7,53 +7,36 @@ // #import -#import "ADJActivityHandler.h" -#import "ADJPackageHandler.h" -#import "ADJRequestHandler.h" #import "ADJLogger.h" -#import "ADJAttributionHandler.h" #import "ADJActivityPackage.h" #import "ADJBackoffStrategy.h" #import "ADJSdkClickHandler.h" @interface ADJAdjustFactory : NSObject -+ (id)packageHandlerForActivityHandler:(id)activityHandler - startsSending:(BOOL)startsSending; -+ (id)requestHandlerForPackageHandler:(id)packageHandler - andActivityHandler:(id)activityHandler; -+ (id)activityHandlerWithConfig:(ADJConfig *)adjustConfig - savedPreLaunch:(ADJSavedPreLaunch *)savedPreLaunch; -+ (id)sdkClickHandlerForActivityHandler:(id)activityHandler - startsSending:(BOOL)startsSending; - + (id)logger; + (double)sessionInterval; + (double)subsessionInterval; ++ (double)requestTimeout; + (NSTimeInterval)timerInterval; + (NSTimeInterval)timerStart; + (ADJBackoffStrategy *)packageHandlerBackoffStrategy; + (ADJBackoffStrategy *)sdkClickHandlerBackoffStrategy; + (ADJBackoffStrategy *)installSessionBackoffStrategy; -+ (id)attributionHandlerForActivityHandler:(id)activityHandler - startsSending:(BOOL)startsSending; + (BOOL)testing; + (NSTimeInterval)maxDelayStart; + (NSString *)baseUrl; + (NSString *)gdprUrl; ++ (NSString *)subscriptionUrl; + (BOOL)iAdFrameworkEnabled; -+ (void)setPackageHandler:(id)packageHandler; -+ (void)setRequestHandler:(id)requestHandler; -+ (void)setActivityHandler:(id)activityHandler; -+ (void)setSdkClickHandler:(id)sdkClickHandler; + (void)setLogger:(id)logger; + (void)setSessionInterval:(double)sessionInterval; + (void)setSubsessionInterval:(double)subsessionInterval; ++ (void)setRequestTimeout:(double)requestTimeout; + (void)setTimerInterval:(NSTimeInterval)timerInterval; + (void)setTimerStart:(NSTimeInterval)timerStart; -+ (void)setAttributionHandler:(id)attributionHandler; + (void)setPackageHandlerBackoffStrategy:(ADJBackoffStrategy *)backoffStrategy; + (void)setSdkClickHandlerBackoffStrategy:(ADJBackoffStrategy *)backoffStrategy; + (void)setTesting:(BOOL)testing; @@ -61,6 +44,7 @@ + (void)setMaxDelayStart:(NSTimeInterval)maxDelayStart; + (void)setBaseUrl:(NSString *)baseUrl; + (void)setGdprUrl:(NSString *)gdprUrl; ++ (void)setSubscriptionUrl:(NSString *)subscriptionUrl; + (void)enableSigning; + (void)disableSigning; diff --git a/Adjust/ADJAdjustFactory.m b/Adjust/ADJAdjustFactory.m index 2c59c67bd..bb7b66c82 100644 --- a/Adjust/ADJAdjustFactory.m +++ b/Adjust/ADJAdjustFactory.m @@ -7,16 +7,14 @@ // #import "ADJAdjustFactory.h" +#import "ADJActivityHandler.h" +#import "ADJPackageHandler.h" -static id internalPackageHandler = nil; -static id internalRequestHandler = nil; -static id internalActivityHandler = nil; static id internalLogger = nil; -static id internalAttributionHandler = nil; -static id internalSdkClickHandler = nil; static double internalSessionInterval = -1; static double intervalSubsessionInterval = -1; +static double internalRequestTimeout = -1; static NSTimeInterval internalTimerInterval = -1; static NSTimeInterval intervalTimerStart = -1; static ADJBackoffStrategy * packageHandlerBackoffStrategy = nil; @@ -26,44 +24,12 @@ static NSTimeInterval internalMaxDelayStart = -1; static BOOL internaliAdFrameworkEnabled = YES; -static NSString * const kBaseUrl = @"https://app.adjust.com"; -static NSString * internalBaseUrl = @"https://app.adjust.com"; -static NSString * const kGdprUrl = @"https://gdpr.adjust.com"; -static NSString * internalGdprUrl = @"https://gdpr.adjust.com"; +static NSString * internalBaseUrl = nil; +static NSString * internalGdprUrl = nil; +static NSString * internalSubscriptionUrl = nil; @implementation ADJAdjustFactory -+ (id)packageHandlerForActivityHandler:(id)activityHandler - startsSending:(BOOL)startsSending { - if (internalPackageHandler == nil) { - return [ADJPackageHandler handlerWithActivityHandler:activityHandler startsSending:startsSending]; - } - - return [internalPackageHandler initWithActivityHandler:activityHandler startsSending:startsSending]; -} - -+ (id)requestHandlerForPackageHandler:(id)packageHandler - andActivityHandler:(id)activityHandler { - if (internalRequestHandler == nil) { - return [ADJRequestHandler handlerWithPackageHandler:packageHandler - andActivityHandler:activityHandler]; - } - return [internalRequestHandler initWithPackageHandler:packageHandler - andActivityHandler:activityHandler]; -} - -+ (id)activityHandlerWithConfig:(ADJConfig *)adjustConfig - savedPreLaunch:(ADJSavedPreLaunch *)savedPreLaunch -{ - if (internalActivityHandler == nil) { - return [ADJActivityHandler handlerWithConfig:adjustConfig - savedPreLaunch:savedPreLaunch - ]; - } - return [internalActivityHandler initWithConfig:adjustConfig - savedPreLaunch:savedPreLaunch]; -} - + (id)logger { if (internalLogger == nil) { // same instance of logger @@ -86,6 +52,13 @@ + (double)subsessionInterval { return intervalSubsessionInterval; } ++ (double)requestTimeout { + if (internalRequestTimeout == -1) { + return 60; // 60 second + } + return internalRequestTimeout; +} + + (NSTimeInterval)timerInterval { if (internalTimerInterval < 0) { return 60; // 1 minute @@ -121,28 +94,6 @@ + (ADJBackoffStrategy *)installSessionBackoffStrategy { return installSessionBackoffStrategy; } -+ (id)attributionHandlerForActivityHandler:(id)activityHandler - startsSending:(BOOL)startsSending -{ - if (internalAttributionHandler == nil) { - return [ADJAttributionHandler handlerWithActivityHandler:activityHandler - startsSending:startsSending]; - } - - return [internalAttributionHandler initWithActivityHandler:activityHandler - startsSending:startsSending]; -} - -+ (id)sdkClickHandlerForActivityHandler:(id)activityHandler - startsSending:(BOOL)startsSending -{ - if (internalSdkClickHandler == nil) { - return [ADJSdkClickHandler handlerWithActivityHandler:activityHandler startsSending:startsSending]; - } - - return [internalSdkClickHandler initWithActivityHandler:activityHandler startsSending:startsSending]; -} - + (BOOL)testing { return internalTesting; } @@ -166,16 +117,8 @@ + (NSString *)gdprUrl { return internalGdprUrl; } -+ (void)setPackageHandler:(id)packageHandler { - internalPackageHandler = packageHandler; -} - -+ (void)setRequestHandler:(id)requestHandler { - internalRequestHandler = requestHandler; -} - -+ (void)setActivityHandler:(id)activityHandler { - internalActivityHandler = activityHandler; ++ (NSString *)subscriptionUrl { + return internalSubscriptionUrl; } + (void)setLogger:(id)logger { @@ -190,6 +133,10 @@ + (void)setSubsessionInterval:(double)subsessionInterval { intervalSubsessionInterval = subsessionInterval; } ++ (void)setRequestTimeout:(double)requestTimeout { + internalRequestTimeout = requestTimeout; +} + + (void)setTimerInterval:(NSTimeInterval)timerInterval { internalTimerInterval = timerInterval; } @@ -198,14 +145,6 @@ + (void)setTimerStart:(NSTimeInterval)timerStart { intervalTimerStart = timerStart; } -+ (void)setAttributionHandler:(id)attributionHandler { - internalAttributionHandler = attributionHandler; -} - -+ (void)setSdkClickHandler:(id)sdkClickHandler { - internalSdkClickHandler = sdkClickHandler; -} - + (void)setPackageHandlerBackoffStrategy:(ADJBackoffStrategy *)backoffStrategy { packageHandlerBackoffStrategy = backoffStrategy; } @@ -234,6 +173,10 @@ + (void)setGdprUrl:(NSString *)gdprUrl { internalGdprUrl = gdprUrl; } ++ (void)setSubscriptionUrl:(NSString *)subscriptionUrl { + internalSubscriptionUrl = subscriptionUrl; +} + + (void)enableSigning { Class signerClass = NSClassFromString(@"ADJSigner"); if (signerClass == nil) { @@ -281,23 +224,20 @@ + (void)teardown:(BOOL)deleteState { [ADJActivityHandler deleteState]; [ADJPackageHandler deleteState]; } - internalPackageHandler = nil; - internalRequestHandler = nil; - internalActivityHandler = nil; internalLogger = nil; - internalAttributionHandler = nil; - internalSdkClickHandler = nil; - internalSessionInterval = -1; + internalSessionInterval = -1; intervalSubsessionInterval = -1; internalTimerInterval = -1; intervalTimerStart = -1; + internalRequestTimeout = -1; packageHandlerBackoffStrategy = nil; sdkClickHandlerBackoffStrategy = nil; internalTesting = NO; internalMaxDelayStart = -1; - internalBaseUrl = kBaseUrl; - internalGdprUrl = kGdprUrl; + internalBaseUrl = nil; + internalGdprUrl = nil; + internalSubscriptionUrl = nil; internaliAdFrameworkEnabled = YES; } @end diff --git a/Adjust/ADJAttributionHandler.h b/Adjust/ADJAttributionHandler.h index 783e6f079..4a27a26b1 100644 --- a/Adjust/ADJAttributionHandler.h +++ b/Adjust/ADJAttributionHandler.h @@ -9,11 +9,15 @@ #import #import "ADJActivityHandler.h" #import "ADJActivityPackage.h" +#import "ADJRequestHandler.h" +#import "ADJUrlStrategy.h" -@protocol ADJAttributionHandler +@interface ADJAttributionHandler : NSObject - (id)initWithActivityHandler:(id) activityHandler - startsSending:(BOOL)startsSending; + startsSending:(BOOL)startsSending + userAgent:(NSString *)userAgent + urlStrategy:(ADJUrlStrategy *)urlStrategy; - (void)checkSessionResponse:(ADJSessionResponseData *)sessionResponseData; @@ -30,10 +34,3 @@ - (void)teardown; @end - -@interface ADJAttributionHandler : NSObject - -+ (id)handlerWithActivityHandler:(id)activityHandler - startsSending:(BOOL)startsSending; - -@end diff --git a/Adjust/ADJAttributionHandler.m b/Adjust/ADJAttributionHandler.m index 22f2b77da..af8d4bcb2 100644 --- a/Adjust/ADJAttributionHandler.m +++ b/Adjust/ADJAttributionHandler.m @@ -13,6 +13,7 @@ #import "NSString+ADJAdditions.h" #import "ADJTimerOnce.h" #import "ADJPackageBuilder.h" +#import "ADJUtil.h" static const char * const kInternalQueueName = "com.adjust.AttributionQueue"; static NSString * const kAttributionTimerName = @"Attribution timer"; @@ -20,35 +21,33 @@ @interface ADJAttributionHandler() @property (nonatomic, strong) dispatch_queue_t internalQueue; +@property (nonatomic, strong) ADJRequestHandler *requestHandler; @property (nonatomic, weak) id activityHandler; @property (nonatomic, weak) id logger; @property (nonatomic, strong) ADJTimerOnce *attributionTimer; @property (atomic, assign) BOOL paused; -@property (nonatomic, copy) NSString *basePath; @property (nonatomic, copy) NSString *lastInitiatedBy; @end @implementation ADJAttributionHandler - -+ (id)handlerWithActivityHandler:(id)activityHandler - startsSending:(BOOL)startsSending; -{ - return [[ADJAttributionHandler alloc] initWithActivityHandler:activityHandler - startsSending:startsSending]; -} - - (id)initWithActivityHandler:(id) activityHandler - startsSending:(BOOL)startsSending; + startsSending:(BOOL)startsSending + userAgent:(NSString *)userAgent + urlStrategy:(ADJUrlStrategy *)urlStrategy { self = [super init]; if (self == nil) return nil; self.internalQueue = dispatch_queue_create(kInternalQueueName, DISPATCH_QUEUE_SERIAL); + self.requestHandler = [[ADJRequestHandler alloc] + initWithResponseCallback:self + urlStrategy:urlStrategy + userAgent:userAgent + requestTimeout:[ADJAdjustFactory requestTimeout]]; self.activityHandler = activityHandler; self.logger = ADJAdjustFactory.logger; self.paused = !startsSending; - self.basePath = [activityHandler getBasePath]; __weak __typeof__(self) weakSelf = self; self.attributionTimer = [ADJTimerOnce timerWithBlock:^{ __typeof__(self) strongSelf = weakSelf; @@ -113,14 +112,14 @@ - (void)resumeSending { - (void)checkSessionResponseI:(ADJAttributionHandler*)selfI sessionResponseData:(ADJSessionResponseData *)sessionResponseData { [selfI checkAttributionI:selfI responseData:sessionResponseData]; - + [selfI.activityHandler launchSessionResponseTasks:sessionResponseData]; } - (void)checkSdkClickResponseI:(ADJAttributionHandler*)selfI sdkClickResponseData:(ADJSdkClickResponseData *)sdkClickResponseData { [selfI checkAttributionI:selfI responseData:sdkClickResponseData]; - + [selfI.activityHandler launchSdkClickResponseTasks:sdkClickResponseData]; } @@ -129,7 +128,7 @@ - (void)checkAttributionResponseI:(ADJAttributionHandler*)selfI [selfI checkAttributionI:selfI responseData:attributionResponseData]; [selfI checkDeeplinkI:selfI attributionResponseData:attributionResponseData]; - + [selfI.activityHandler launchAttributionResponseTasks:attributionResponseData]; } @@ -190,25 +189,33 @@ - (void)requestAttributionI:(ADJAttributionHandler*)selfI { [selfI.logger verbose:@"%@", attributionPackage.extendedString]; - NSURL * baseUrl = [NSURL URLWithString:[ADJAdjustFactory baseUrl]]; - - [ADJUtil sendGetRequest:baseUrl - basePath:selfI.basePath - prefixErrorMessage:@"Failed to get attribution" - activityPackage:attributionPackage - responseDataHandler:^(ADJResponseData * responseData) - { - // Check if any package response contains information that user has opted out. - // If yes, disable SDK and flush any potentially stored packages that happened afterwards. - if (responseData.trackingState == ADJTrackingStateOptedOut) { - [selfI.activityHandler setTrackingStateOptedOut]; - return; - } - - if ([responseData isKindOfClass:[ADJAttributionResponseData class]]) { - [selfI checkAttributionResponse:(ADJAttributionResponseData*)responseData]; - } - }]; + NSDictionary *sendingParameters = @{ + @"sent_at": [ADJUtil formatSeconds1970:[NSDate.date timeIntervalSince1970]] + }; + + [selfI.requestHandler sendPackageByGET:attributionPackage + sendingParameters:sendingParameters]; +} + +- (void)responseCallback:(ADJResponseData *)responseData { + if (responseData.jsonResponse) { + [self.logger debug: + @"Got attribution JSON response with message: %@", responseData.message]; + } else { + [self.logger error: + @"Could not get attribution JSON response with message: %@", responseData.message]; + } + + // Check if any package response contains information that user has opted out. + // If yes, disable SDK and flush any potentially stored packages that happened afterwards. + if (responseData.trackingState == ADJTrackingStateOptedOut) { + [self.activityHandler setTrackingStateOptedOut]; + return; + } + + if ([responseData isKindOfClass:[ADJAttributionResponseData class]]) { + [self checkAttributionResponse:(ADJAttributionResponseData*)responseData]; + } } - (void)waitRequestAttributionWithDelayI:(ADJAttributionHandler*)selfI @@ -236,6 +243,7 @@ - (ADJActivityPackage *)buildAndGetAttributionPackageI:(ADJAttributionHandler*)s activityState:selfI.activityHandler.activityState config:selfI.activityHandler.adjustConfig sessionParameters:selfI.activityHandler.sessionParameters + trackingStatusManager:selfI.activityHandler.trackingStatusManager createdAt:now]; ADJActivityPackage *attributionPackage = [attributionBuilder buildAttributionPackage:selfI.lastInitiatedBy]; @@ -256,6 +264,7 @@ - (void)teardown { self.activityHandler = nil; self.logger = nil; self.attributionTimer = nil; + self.requestHandler = nil; } @end diff --git a/Adjust/ADJConfig.h b/Adjust/ADJConfig.h index 1bcccf9a2..4e8458add 100644 --- a/Adjust/ADJConfig.h +++ b/Adjust/ADJConfig.h @@ -187,6 +187,16 @@ info3:(NSUInteger)info3 info4:(NSUInteger)info4; + +@property (nonatomic, assign, readonly) BOOL isSKAdNetworkHandlingActive; + +- (void)deactivateSKAdNetworkHandling; + +/** + * @brief Adjust url strategy. + */ +@property (nonatomic, copy, readwrite, nullable) NSString *urlStrategy; + /** * @brief Get configuration object for the initialization of the Adjust SDK. * diff --git a/Adjust/ADJConfig.m b/Adjust/ADJConfig.m index 90abe25ba..315ed4260 100644 --- a/Adjust/ADJConfig.m +++ b/Adjust/ADJConfig.m @@ -66,6 +66,7 @@ - (id)initWithAppToken:(NSString *)appToken self.eventBufferingEnabled = NO; self.allowIdfaReading = YES; self.allowiAdInfoReading = YES; + _isSKAdNetworkHandlingActive = YES; return self; } @@ -81,6 +82,10 @@ - (void)setLogLevel:(ADJLogLevel)logLevel isProductionEnvironment:[ADJEnvironmentProduction isEqualToString:environment]]; } +- (void)deactivateSKAdNetworkHandling { + _isSKAdNetworkHandlingActive = NO; +} + - (void)setDelegate:(NSObject *)delegate { BOOL hasResponseDelegate = NO; BOOL implementsDeeplinkCallback = NO; @@ -202,6 +207,8 @@ -(id)copyWithZone:(NSZone *)zone copy.isDeviceKnown = self.isDeviceKnown; copy->_secretId = [self.secretId copyWithZone:zone]; copy->_appSecret = [self.appSecret copyWithZone:zone]; + copy->_isSKAdNetworkHandlingActive = self.isSKAdNetworkHandlingActive; + copy->_urlStrategy = [self.urlStrategy copyWithZone:zone]; // adjust delegate not copied } diff --git a/Adjust/ADJDeviceInfo.m b/Adjust/ADJDeviceInfo.m index c8c386e71..3a283a6ea 100644 --- a/Adjust/ADJDeviceInfo.m +++ b/Adjust/ADJDeviceInfo.m @@ -14,7 +14,7 @@ #import "NSData+ADJAdditions.h" #import "ADJReachability.h" -#if !TARGET_OS_TV +#if !TARGET_OS_TV && !TARGET_OS_MACCATALYST #import #import #endif diff --git a/Adjust/ADJEvent.m b/Adjust/ADJEvent.m index 87132abb1..ecb6b1cd8 100644 --- a/Adjust/ADJEvent.m +++ b/Adjust/ADJEvent.m @@ -10,11 +10,12 @@ #import "ADJAdjustFactory.h" #import "ADJUtil.h" -#pragma mark - @interface ADJEvent() + @property (nonatomic, weak) id logger; -@property (nonatomic, strong) NSMutableDictionary* callbackMutableParameters; -@property (nonatomic, strong) NSMutableDictionary* partnerMutableParameters; +@property (nonatomic, strong) NSMutableDictionary *callbackMutableParameters; +@property (nonatomic, strong) NSMutableDictionary *partnerMutableParameters; + @end @implementation ADJEvent @@ -23,86 +24,109 @@ + (ADJEvent *)eventWithEventToken:(NSString *)eventToken { return [[ADJEvent alloc] initWithEventToken:eventToken]; } -- (id) initWithEventToken:(NSString *)eventToken { +- (id)initWithEventToken:(NSString *)eventToken { self = [super init]; - if (self == nil) return nil; + if (self == nil) { + return nil; + } self.logger = ADJAdjustFactory.logger; - if (![self checkEventToken:eventToken]) return self; + if (![self checkEventToken:eventToken]) { + return self; + } - _eventToken = eventToken; + _eventToken = [eventToken copy]; return self; } -- (void) addCallbackParameter:(NSString *)key - value:(NSString *)value -{ - if (![ADJUtil isValidParameter:key - attributeType:@"key" - parameterName:@"Callback"]) return; +- (void)addCallbackParameter:(NSString *)key value:(NSString *)value { + @synchronized (self) { + NSString *immutableKey = [key copy]; + NSString *immutableValue = [value copy]; - if (![ADJUtil isValidParameter:value - attributeType:@"value" - parameterName:@"Callback"]) return; - - if (self.callbackMutableParameters == nil) { - self.callbackMutableParameters = [[NSMutableDictionary alloc] init]; - } + if (![ADJUtil isValidParameter:immutableKey + attributeType:@"key" + parameterName:@"Callback"]) { + return; + } + if (![ADJUtil isValidParameter:immutableValue + attributeType:@"value" + parameterName:@"Callback"]) { + return; + } - if ([self.callbackMutableParameters objectForKey:key]) { - [self.logger warn:@"key %@ was overwritten", key]; + if (self.callbackMutableParameters == nil) { + self.callbackMutableParameters = [[NSMutableDictionary alloc] init]; + } + if ([self.callbackMutableParameters objectForKey:immutableKey]) { + [self.logger warn:@"Callback parameter key %@ was overwritten", immutableKey]; + } + [self.callbackMutableParameters setObject:immutableValue forKey:immutableKey]; } - - [self.callbackMutableParameters setObject:value forKey:key]; } -- (void) addPartnerParameter:(NSString *)key - value:(NSString *)value { - - if (![ADJUtil isValidParameter:key - attributeType:@"key" - parameterName:@"Partner"]) return; +- (void)addPartnerParameter:(NSString *)key value:(NSString *)value { + @synchronized (self) { + NSString *immutableKey = [key copy]; + NSString *immutableValue = [value copy]; - if (![ADJUtil isValidParameter:value - attributeType:@"value" - parameterName:@"Partner"]) return; - - if (self.partnerMutableParameters == nil) { - self.partnerMutableParameters = [[NSMutableDictionary alloc] init]; - } + if (![ADJUtil isValidParameter:immutableKey + attributeType:@"key" + parameterName:@"Partner"]) { + return; + } + if (![ADJUtil isValidParameter:immutableValue + attributeType:@"value" + parameterName:@"Partner"]) { + return; + } - if ([self.partnerMutableParameters objectForKey:key]) { - [self.logger warn:@"key %@ was overwritten", key]; + if (self.partnerMutableParameters == nil) { + self.partnerMutableParameters = [[NSMutableDictionary alloc] init]; + } + if ([self.partnerMutableParameters objectForKey:immutableKey]) { + [self.logger warn:@"Partner parameter key %@ was overwritten", immutableKey]; + } + [self.partnerMutableParameters setObject:immutableValue forKey:immutableKey]; } - - [self.partnerMutableParameters setObject:value forKey:key]; } -- (void) setRevenue:(double) amount currency:(NSString *)currency{ - NSNumber * revenue = [NSNumber numberWithDouble:amount]; - - if (![self checkRevenue:revenue currency:currency]) return; +- (void)setRevenue:(double)amount currency:(NSString *)currency { + NSNumber *revenue = [NSNumber numberWithDouble:amount]; + if (![self checkRevenue:revenue currency:currency]) { + return; + } _revenue = revenue; - _currency = currency; + @synchronized (self) { + _currency = [currency copy]; + } } -- (void) setTransactionId:(NSString *)transactionId { - _transactionId = transactionId; +- (void)setTransactionId:(NSString *)transactionId { + @synchronized (self) { + _transactionId = [transactionId copy]; + } } - (void)setCallbackId:(NSString *)callbackId { - _callbackId = callbackId; + @synchronized (self) { + _callbackId = [callbackId copy]; + } } -- (NSDictionary *) callbackParameters { - return (NSDictionary *) self.callbackMutableParameters; +- (NSDictionary *)callbackParameters { + @synchronized (self) { + return (NSDictionary *)self.callbackMutableParameters; + } } -- (NSDictionary *) partnerParameters { - return (NSDictionary *) self.partnerMutableParameters; +- (NSDictionary *)partnerParameters { + @synchronized (self) { + return (NSDictionary *)self.partnerMutableParameters; + } } - (BOOL)checkEventToken:(NSString *)eventToken { @@ -117,21 +141,17 @@ - (BOOL)checkEventToken:(NSString *)eventToken { return YES; } -- (BOOL) checkRevenue:(NSNumber*) revenue - currency:(NSString*) currency -{ +- (BOOL)checkRevenue:(NSNumber *)revenue currency:(NSString *)currency { if (![ADJUtil isNull:revenue]) { double amount = [revenue doubleValue]; if (amount < 0.0) { [self.logger error:@"Invalid amount %.5f", amount]; return NO; } - if ([ADJUtil isNull:currency]) { [self.logger error:@"Currency must be set with revenue"]; return NO; } - if ([currency isEqualToString:@""]) { [self.logger error:@"Currency is empty"]; return NO; @@ -146,12 +166,14 @@ - (BOOL) checkRevenue:(NSNumber*) revenue return YES; } -- (BOOL) isValid { +- (BOOL)isValid { return self.eventToken != nil; } -- (void) setReceipt:(NSData *)receipt transactionId:(NSString *)transactionId { - if (![self checkReceipt:receipt transactionId:transactionId]) return; +- (void)setReceipt:(NSData *)receipt transactionId:(NSString *)transactionId { + if (![self checkReceipt:receipt transactionId:transactionId]) { + return; + } if ([ADJUtil isNull:receipt] || [receipt length] == 0) { _emptyReceipt = YES; @@ -160,7 +182,7 @@ - (void) setReceipt:(NSData *)receipt transactionId:(NSString *)transactionId { _transactionId = transactionId; } -- (BOOL) checkReceipt:(NSData *)receipt transactionId:(NSString *)transactionId { +- (BOOL)checkReceipt:(NSData *)receipt transactionId:(NSString *)transactionId { if ([ADJUtil isNotNull:receipt] && [ADJUtil isNull:transactionId]) { [self.logger error:@"Missing transactionId"]; return NO; @@ -168,9 +190,9 @@ - (BOOL) checkReceipt:(NSData *)receipt transactionId:(NSString *)transactionId return YES; } --(id)copyWithZone:(NSZone *)zone -{ - ADJEvent* copy = [[[self class] allocWithZone:zone] init]; +- (id)copyWithZone:(NSZone *)zone { + ADJEvent *copy = [[[self class] allocWithZone:zone] init]; + if (copy) { copy->_eventToken = [self.eventToken copyWithZone:zone]; copy->_revenue = [self.revenue copyWithZone:zone]; @@ -181,6 +203,7 @@ -(id)copyWithZone:(NSZone *)zone copy->_receipt = [self.receipt copyWithZone:zone]; copy->_emptyReceipt = self.emptyReceipt; } + return copy; } diff --git a/Adjust/ADJPackageBuilder.h b/Adjust/ADJPackageBuilder.h index 026079dc9..e25752995 100644 --- a/Adjust/ADJPackageBuilder.h +++ b/Adjust/ADJPackageBuilder.h @@ -13,6 +13,7 @@ #import "ADJActivityPackage.h" #import "ADJSessionParameters.h" #import +#import "ADJActivityHandler.h" @interface ADJPackageBuilder : NSObject @@ -32,6 +33,7 @@ activityState:(ADJActivityState *)activityState config:(ADJConfig *)adjustConfig sessionParameters:(ADJSessionParameters *)sessionParameters + trackingStatusManager:(ADJTrackingStatusManager *)trackingStatusManager createdAt:(double)createdAt; - (ADJActivityPackage *)buildSessionPackage:(BOOL)isInDelay; @@ -51,6 +53,9 @@ - (ADJActivityPackage *)buildDisableThirdPartySharingPackage; +- (ADJActivityPackage *)buildSubscriptionPackage:(ADJSubscription *)subscription + isInDelay:(BOOL)isInDelay; + + (void)parameters:(NSMutableDictionary *)parameters setDictionary:(NSDictionary *)dictionary forKey:(NSString *)key; @@ -59,4 +64,8 @@ setString:(NSString *)value forKey:(NSString *)key; ++ (void)parameters:(NSMutableDictionary *)parameters + setInt:(int)value + forKey:(NSString *)key; + @end diff --git a/Adjust/ADJPackageBuilder.m b/Adjust/ADJPackageBuilder.m index bd961883b..92e0c199a 100644 --- a/Adjust/ADJPackageBuilder.m +++ b/Adjust/ADJPackageBuilder.m @@ -13,6 +13,7 @@ #import "ADJActivityPackage.h" #import "NSData+ADJAdditions.h" #import "UIDevice+ADJAdditions.h" +#import "ADJUserDefaults.h" @interface ADJPackageBuilder() @@ -26,6 +27,8 @@ @interface ADJPackageBuilder() @property (nonatomic, weak) ADJSessionParameters *sessionParameters; +@property (nonatomic, weak) ADJTrackingStatusManager *trackingStatusManager; + @end @implementation ADJPackageBuilder @@ -36,7 +39,9 @@ - (id)initWithDeviceInfo:(ADJDeviceInfo *)deviceInfo activityState:(ADJActivityState *)activityState config:(ADJConfig *)adjustConfig sessionParameters:(ADJSessionParameters *)sessionParameters - createdAt:(double)createdAt { + trackingStatusManager:(ADJTrackingStatusManager *)trackingStatusManager + createdAt:(double)createdAt +{ self = [super init]; if (self == nil) { return nil; @@ -47,6 +52,7 @@ - (id)initWithDeviceInfo:(ADJDeviceInfo *)deviceInfo self.adjustConfig = adjustConfig; self.activityState = activityState; self.sessionParameters = sessionParameters; + self.trackingStatusManager = trackingStatusManager; return self; } @@ -113,6 +119,17 @@ - (ADJActivityPackage *)buildAdRevenuePackage:(NSString *)source payload:(NSData - (ADJActivityPackage *)buildClickPackage:(NSString *)clickSource { NSMutableDictionary *parameters = [self getClickParameters:clickSource]; + + if ([clickSource isEqualToString:ADJiAdPackageKey]) { + // send iAd errors in the parameters + NSDictionary *iAdErrors = [ADJUserDefaults getiAdErrors]; + if (iAdErrors) { + NSData *jsonData = [NSJSONSerialization dataWithJSONObject:iAdErrors options:0 error:nil]; + NSString *jsonStr = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding]; + parameters[@"iad_errors"] = jsonStr; + } + } + ADJActivityPackage *clickPackage = [self defaultActivityPackage]; clickPackage.path = @"/sdk_click"; clickPackage.activityKind = ADJActivityKindClick; @@ -163,6 +180,25 @@ - (ADJActivityPackage *)buildDisableThirdPartySharingPackage { return dtpsPackage; } +- (ADJActivityPackage *)buildSubscriptionPackage:(ADJSubscription *)subscription + isInDelay:(BOOL)isInDelay { + NSMutableDictionary *parameters = [self getSubscriptionParameters:isInDelay forSubscriptionPackage:subscription]; + ADJActivityPackage *subscriptionPackage = [self defaultActivityPackage]; + subscriptionPackage.path = @"/v2/purchase"; + subscriptionPackage.activityKind = ADJActivityKindSubscription; + subscriptionPackage.suffix = @""; + subscriptionPackage.parameters = parameters; + + if (isInDelay) { + subscriptionPackage.callbackParameters = subscriptionPackage.callbackParameters; + subscriptionPackage.partnerParameters = subscriptionPackage.partnerParameters; + } + + [self signWithSigV2Plugin:subscriptionPackage]; + + return subscriptionPackage; +} + + (void)parameters:(NSMutableDictionary *)parameters setDictionary:(NSDictionary *)dictionary forKey:(NSString *)key { if (dictionary == nil) { return; @@ -216,6 +252,32 @@ - (void)signWithSigV2Plugin:(ADJActivityPackage *)activityPackage { [signInvocation setArgument:&sdkVersionChar atIndex: 4]; [signInvocation invoke]; + + SEL getVersionSEL = NSSelectorFromString(@"getVersion"); + if (![signerClass respondsToSelector:getVersionSEL]) { + return; + } + /* + NSString *signerVersion = [ADJSigner getVersion]; + */ + IMP getVersionIMP = [signerClass methodForSelector:getVersionSEL]; + if (!getVersionIMP) { + return; + } + + id (*getVersionFunc)(id, SEL) = (void *)getVersionIMP; + + id signerVersion = getVersionFunc(signerClass, getVersionSEL); + + if (![signerVersion isKindOfClass:[NSString class]]) { + return; + } + + NSString *signerVersionString = (NSString *)signerVersion; + [ADJPackageBuilder parameters:parameters + setString:signerVersionString + forKey:@"native_version"]; + } - (NSMutableDictionary *)getSessionParameters:(BOOL)isInDelay { @@ -247,12 +309,20 @@ - (NSMutableDictionary *)getSessionParameters:(BOOL)isInDelay { [ADJPackageBuilder parameters:parameters setString:self.deviceInfo.installReceiptBase64 forKey:@"install_receipt"]; [ADJPackageBuilder parameters:parameters setString:[ADJUtil getInstallTime] forKey:@"installed_at"]; [ADJPackageBuilder parameters:parameters setString:self.deviceInfo.languageCode forKey:@"language"]; + [ADJPackageBuilder parameters:parameters setString:[[UIDevice currentDevice] adjDeviceId:_deviceInfo] forKey:@"m"]; [ADJPackageBuilder parameters:parameters setBool:YES forKey:@"needs_response_details"]; [ADJPackageBuilder parameters:parameters setString:self.deviceInfo.osBuild forKey:@"os_build"]; [ADJPackageBuilder parameters:parameters setString:self.deviceInfo.osName forKey:@"os_name"]; [ADJPackageBuilder parameters:parameters setString:self.deviceInfo.systemVersion forKey:@"os_version"]; [ADJPackageBuilder parameters:parameters setString:self.adjustConfig.secretId forKey:@"secret_id"]; - [ADJPackageBuilder parameters:parameters setInt:UIDevice.currentDevice.adjTrackingEnabled forKey:@"tracking_enabled"]; + + if ([self.trackingStatusManager canGetAttStatus]) { + [ADJPackageBuilder parameters:parameters setInt:self.trackingStatusManager.attStatus + forKey:@"att_status"]; + } else { + [ADJPackageBuilder parameters:parameters setInt:self.trackingStatusManager.trackingEnabled + forKey:@"tracking_enabled"]; + } if (self.adjustConfig.isDeviceKnown) { [ADJPackageBuilder parameters:parameters setBool:self.adjustConfig.isDeviceKnown forKey:@"device_known"]; @@ -273,11 +343,11 @@ - (NSMutableDictionary *)getSessionParameters:(BOOL)isInDelay { } if (!isInDelay) { - [ADJPackageBuilder parameters:parameters setDictionary:self.sessionParameters.callbackParameters forKey:@"callback_params"]; - [ADJPackageBuilder parameters:parameters setDictionary:self.sessionParameters.partnerParameters forKey:@"partner_params"]; + [ADJPackageBuilder parameters:parameters setDictionary:[self.sessionParameters.callbackParameters copy] forKey:@"callback_params"]; + [ADJPackageBuilder parameters:parameters setDictionary:[self.sessionParameters.partnerParameters copy] forKey:@"partner_params"]; } -#if !TARGET_OS_TV +#if !TARGET_OS_TV && !TARGET_OS_MACCATALYST [ADJPackageBuilder parameters:parameters setString:[ADJUtil readMCC] forKey:@"mcc"]; [ADJPackageBuilder parameters:parameters setString:[ADJUtil readMNC] forKey:@"mnc"]; [ADJPackageBuilder parameters:parameters setString:[ADJUtil readCurrentRadioAccessTechnology] forKey:@"network_type"]; @@ -315,13 +385,21 @@ - (NSMutableDictionary *)getEventParameters:(BOOL)isInDelay forEventPackage:(ADJ [ADJPackageBuilder parameters:parameters setString:self.deviceInfo.vendorId forKey:@"idfv"]; [ADJPackageBuilder parameters:parameters setString:self.deviceInfo.installReceiptBase64 forKey:@"install_receipt"]; [ADJPackageBuilder parameters:parameters setString:self.deviceInfo.languageCode forKey:@"language"]; + [ADJPackageBuilder parameters:parameters setString:[[UIDevice currentDevice] adjDeviceId:_deviceInfo] forKey:@"m"]; [ADJPackageBuilder parameters:parameters setBool:YES forKey:@"needs_response_details"]; [ADJPackageBuilder parameters:parameters setString:self.deviceInfo.osBuild forKey:@"os_build"]; [ADJPackageBuilder parameters:parameters setString:self.deviceInfo.osName forKey:@"os_name"]; [ADJPackageBuilder parameters:parameters setString:self.deviceInfo.systemVersion forKey:@"os_version"]; [ADJPackageBuilder parameters:parameters setNumber:event.revenue forKey:@"revenue"]; [ADJPackageBuilder parameters:parameters setString:self.adjustConfig.secretId forKey:@"secret_id"]; - [ADJPackageBuilder parameters:parameters setInt:UIDevice.currentDevice.adjTrackingEnabled forKey:@"tracking_enabled"]; + + if ([self.trackingStatusManager canGetAttStatus]) { + [ADJPackageBuilder parameters:parameters setInt:self.trackingStatusManager.attStatus + forKey:@"att_status"]; + } else { + [ADJPackageBuilder parameters:parameters setInt:self.trackingStatusManager.trackingEnabled + forKey:@"tracking_enabled"]; + } if (self.adjustConfig.isDeviceKnown) { [ADJPackageBuilder parameters:parameters setBool:self.adjustConfig.isDeviceKnown forKey:@"device_known"]; @@ -342,11 +420,11 @@ - (NSMutableDictionary *)getEventParameters:(BOOL)isInDelay forEventPackage:(ADJ } if (!isInDelay) { - NSDictionary *mergedCallbackParameters = [ADJUtil mergeParameters:self.sessionParameters.callbackParameters - source:event.callbackParameters + NSDictionary *mergedCallbackParameters = [ADJUtil mergeParameters:[self.sessionParameters.callbackParameters copy] + source:[event.callbackParameters copy] parameterName:@"Callback"]; - NSDictionary *mergedPartnerParameters = [ADJUtil mergeParameters:self.sessionParameters.partnerParameters - source:event.partnerParameters + NSDictionary *mergedPartnerParameters = [ADJUtil mergeParameters:[self.sessionParameters.partnerParameters copy] + source:[event.partnerParameters copy] parameterName:@"Partner"]; [ADJPackageBuilder parameters:parameters setDictionary:mergedCallbackParameters forKey:@"callback_params"]; @@ -363,7 +441,7 @@ - (NSMutableDictionary *)getEventParameters:(BOOL)isInDelay forEventPackage:(ADJ [ADJPackageBuilder parameters:parameters setString:event.transactionId forKey:@"transaction_id"]; } -#if !TARGET_OS_TV +#if !TARGET_OS_TV && !TARGET_OS_MACCATALYST [ADJPackageBuilder parameters:parameters setString:[ADJUtil readMCC] forKey:@"mcc"]; [ADJPackageBuilder parameters:parameters setString:[ADJUtil readMNC] forKey:@"mnc"]; [ADJPackageBuilder parameters:parameters setString:[ADJUtil readCurrentRadioAccessTechnology] forKey:@"network_type"]; @@ -375,27 +453,66 @@ - (NSMutableDictionary *)getEventParameters:(BOOL)isInDelay forEventPackage:(ADJ - (NSMutableDictionary *)getInfoParameters:(NSString *)source { NSMutableDictionary *parameters = [NSMutableDictionary dictionary]; - [ADJPackageBuilder parameters:parameters setString:self.adjustConfig.appToken forKey:@"app_token"]; [ADJPackageBuilder parameters:parameters setString:self.adjustConfig.appSecret forKey:@"app_secret"]; + [ADJPackageBuilder parameters:parameters setString:self.adjustConfig.appToken forKey:@"app_token"]; + [ADJPackageBuilder parameters:parameters setString:[ADJUtil getUpdateTime] forKey:@"app_updated_at"]; + [ADJPackageBuilder parameters:parameters setString:self.deviceInfo.bundleVersion forKey:@"app_version"]; + [ADJPackageBuilder parameters:parameters setString:self.deviceInfo.bundleShortVersion forKey:@"app_version_short"]; [ADJPackageBuilder parameters:parameters setBool:YES forKey:@"attribution_deeplink"]; + [ADJPackageBuilder parameters:parameters setString:self.deviceInfo.bundeIdentifier forKey:@"bundle_id"]; + [ADJPackageBuilder parameters:parameters setDictionary:[self.sessionParameters.callbackParameters copy] forKey:@"callback_params"]; + [ADJPackageBuilder parameters:parameters setDate:self.clickTime forKey:@"click_time"]; + [ADJPackageBuilder parameters:parameters setNumberInt:[ADJUtil readReachabilityFlags] forKey:@"connectivity_type"]; + [ADJPackageBuilder parameters:parameters setString:self.deviceInfo.countryCode forKey:@"country"]; + [ADJPackageBuilder parameters:parameters setString:self.deviceInfo.cpuSubtype forKey:@"cpu_type"]; [ADJPackageBuilder parameters:parameters setDate1970:self.createdAt forKey:@"created_at"]; + [ADJPackageBuilder parameters:parameters setString:self.deeplink forKey:@"deeplink"]; + [ADJPackageBuilder parameters:parameters setString:self.adjustConfig.defaultTracker forKey:@"default_tracker"]; + [ADJPackageBuilder parameters:parameters setDictionary:self.attributionDetails forKey:@"details"]; + [ADJPackageBuilder parameters:parameters setString:self.deviceInfo.deviceName forKey:@"device_name"]; + [ADJPackageBuilder parameters:parameters setString:self.deviceInfo.deviceType forKey:@"device_type"]; [ADJPackageBuilder parameters:parameters setString:self.adjustConfig.environment forKey:@"environment"]; [ADJPackageBuilder parameters:parameters setBool:self.adjustConfig.eventBufferingEnabled forKey:@"event_buffering_enabled"]; [ADJPackageBuilder parameters:parameters setString:self.adjustConfig.externalDeviceId forKey:@"external_device_id"]; + [ADJPackageBuilder parameters:parameters setString:self.deviceInfo.fbAnonymousId forKey:@"fb_anon_id"]; + [ADJPackageBuilder parameters:parameters setString:self.deviceInfo.machineModel forKey:@"hardware_name"]; if (self.adjustConfig.allowIdfaReading == YES) { [ADJPackageBuilder parameters:parameters setString:UIDevice.currentDevice.adjIdForAdvertisers forKey:@"idfa"]; } [ADJPackageBuilder parameters:parameters setString:self.deviceInfo.vendorId forKey:@"idfv"]; + [ADJPackageBuilder parameters:parameters setString:self.deviceInfo.installReceiptBase64 forKey:@"install_receipt"]; + [ADJPackageBuilder parameters:parameters setString:[ADJUtil getInstallTime] forKey:@"installed_at"]; + [ADJPackageBuilder parameters:parameters setString:self.deviceInfo.languageCode forKey:@"language"]; + [ADJPackageBuilder parameters:parameters setString:[[UIDevice currentDevice] adjDeviceId:_deviceInfo] forKey:@"m"]; [ADJPackageBuilder parameters:parameters setBool:YES forKey:@"needs_response_details"]; + [ADJPackageBuilder parameters:parameters setString:self.deviceInfo.osBuild forKey:@"os_build"]; + [ADJPackageBuilder parameters:parameters setString:self.deviceInfo.osName forKey:@"os_name"]; + [ADJPackageBuilder parameters:parameters setString:self.deviceInfo.systemVersion forKey:@"os_version"]; + [ADJPackageBuilder parameters:parameters setDictionary:self.deeplinkParameters forKey:@"params"]; + [ADJPackageBuilder parameters:parameters setDictionary:[self.sessionParameters.partnerParameters copy] forKey:@"partner_params"]; + [ADJPackageBuilder parameters:parameters setDate:self.purchaseTime forKey:@"purchase_time"]; [ADJPackageBuilder parameters:parameters setString:self.adjustConfig.secretId forKey:@"secret_id"]; [ADJPackageBuilder parameters:parameters setString:source forKey:@"source"]; + + if ([self.trackingStatusManager canGetAttStatus]) { + [ADJPackageBuilder parameters:parameters setInt:self.trackingStatusManager.attStatus + forKey:@"att_status"]; + } else { + [ADJPackageBuilder parameters:parameters setInt:self.trackingStatusManager.trackingEnabled + forKey:@"tracking_enabled"]; + } if (self.adjustConfig.isDeviceKnown) { [ADJPackageBuilder parameters:parameters setBool:self.adjustConfig.isDeviceKnown forKey:@"device_known"]; } if (self.activityState != nil) { + [ADJPackageBuilder parameters:parameters setDuration:self.activityState.lastInterval forKey:@"last_interval"]; [ADJPackageBuilder parameters:parameters setString:self.activityState.deviceToken forKey:@"push_token"]; + [ADJPackageBuilder parameters:parameters setInt:self.activityState.sessionCount forKey:@"session_count"]; + [ADJPackageBuilder parameters:parameters setDuration:self.activityState.sessionLength forKey:@"session_length"]; + [ADJPackageBuilder parameters:parameters setInt:self.activityState.subsessionCount forKey:@"subsession_count"]; + [ADJPackageBuilder parameters:parameters setDuration:self.activityState.timeSpent forKey:@"time_spent"]; if (self.activityState.isPersisted) { [ADJPackageBuilder parameters:parameters setString:self.activityState.uuid forKey:@"persistent_ios_uuid"]; } else { @@ -403,6 +520,19 @@ - (NSMutableDictionary *)getInfoParameters:(NSString *)source { } } + if (self.attribution != nil) { + [ADJPackageBuilder parameters:parameters setString:self.attribution.adgroup forKey:@"adgroup"]; + [ADJPackageBuilder parameters:parameters setString:self.attribution.campaign forKey:@"campaign"]; + [ADJPackageBuilder parameters:parameters setString:self.attribution.creative forKey:@"creative"]; + [ADJPackageBuilder parameters:parameters setString:self.attribution.trackerName forKey:@"tracker"]; + } + +#if !TARGET_OS_TV && !TARGET_OS_MACCATALYST + [ADJPackageBuilder parameters:parameters setString:[ADJUtil readMCC] forKey:@"mcc"]; + [ADJPackageBuilder parameters:parameters setString:[ADJUtil readMNC] forKey:@"mnc"]; + [ADJPackageBuilder parameters:parameters setString:[ADJUtil readCurrentRadioAccessTechnology] forKey:@"network_type"]; +#endif + return parameters; } @@ -434,6 +564,7 @@ - (NSMutableDictionary *)getAdRevenueParameters:(NSString *)source payload:(NSDa [ADJPackageBuilder parameters:parameters setString:self.deviceInfo.installReceiptBase64 forKey:@"install_receipt"]; [ADJPackageBuilder parameters:parameters setString:[ADJUtil getInstallTime] forKey:@"installed_at"]; [ADJPackageBuilder parameters:parameters setString:self.deviceInfo.languageCode forKey:@"language"]; + [ADJPackageBuilder parameters:parameters setString:[[UIDevice currentDevice] adjDeviceId:_deviceInfo] forKey:@"m"]; [ADJPackageBuilder parameters:parameters setBool:YES forKey:@"needs_response_details"]; [ADJPackageBuilder parameters:parameters setString:self.deviceInfo.osBuild forKey:@"os_build"]; [ADJPackageBuilder parameters:parameters setString:self.deviceInfo.osName forKey:@"os_name"]; @@ -441,7 +572,14 @@ - (NSMutableDictionary *)getAdRevenueParameters:(NSString *)source payload:(NSDa [ADJPackageBuilder parameters:parameters setString:self.adjustConfig.secretId forKey:@"secret_id"]; [ADJPackageBuilder parameters:parameters setString:source forKey:@"source"]; [ADJPackageBuilder parameters:parameters setData:payload forKey:@"payload"]; - [ADJPackageBuilder parameters:parameters setInt:UIDevice.currentDevice.adjTrackingEnabled forKey:@"tracking_enabled"]; + + if ([self.trackingStatusManager canGetAttStatus]) { + [ADJPackageBuilder parameters:parameters setInt:self.trackingStatusManager.attStatus + forKey:@"att_status"]; + } else { + [ADJPackageBuilder parameters:parameters setInt:self.trackingStatusManager.trackingEnabled + forKey:@"tracking_enabled"]; + } if (self.adjustConfig.isDeviceKnown) { [ADJPackageBuilder parameters:parameters setBool:self.adjustConfig.isDeviceKnown forKey:@"device_known"]; @@ -461,7 +599,7 @@ - (NSMutableDictionary *)getAdRevenueParameters:(NSString *)source payload:(NSDa } } -#if !TARGET_OS_TV +#if !TARGET_OS_TV && !TARGET_OS_MACCATALYST [ADJPackageBuilder parameters:parameters setString:[ADJUtil readMCC] forKey:@"mcc"]; [ADJPackageBuilder parameters:parameters setString:[ADJUtil readMNC] forKey:@"mnc"]; [ADJPackageBuilder parameters:parameters setString:[ADJUtil readCurrentRadioAccessTechnology] forKey:@"network_type"]; @@ -481,7 +619,7 @@ - (NSMutableDictionary *)getClickParameters:(NSString *)source { [ADJPackageBuilder parameters:parameters setString:self.deviceInfo.bundleShortVersion forKey:@"app_version_short"]; [ADJPackageBuilder parameters:parameters setBool:YES forKey:@"attribution_deeplink"]; [ADJPackageBuilder parameters:parameters setString:self.deviceInfo.bundeIdentifier forKey:@"bundle_id"]; - [ADJPackageBuilder parameters:parameters setDictionary:self.sessionParameters.callbackParameters forKey:@"callback_params"]; + [ADJPackageBuilder parameters:parameters setDictionary:[self.sessionParameters.callbackParameters copy] forKey:@"callback_params"]; [ADJPackageBuilder parameters:parameters setDate:self.clickTime forKey:@"click_time"]; [ADJPackageBuilder parameters:parameters setNumberInt:[ADJUtil readReachabilityFlags] forKey:@"connectivity_type"]; [ADJPackageBuilder parameters:parameters setString:self.deviceInfo.countryCode forKey:@"country"]; @@ -504,16 +642,24 @@ - (NSMutableDictionary *)getClickParameters:(NSString *)source { [ADJPackageBuilder parameters:parameters setString:self.deviceInfo.installReceiptBase64 forKey:@"install_receipt"]; [ADJPackageBuilder parameters:parameters setString:[ADJUtil getInstallTime] forKey:@"installed_at"]; [ADJPackageBuilder parameters:parameters setString:self.deviceInfo.languageCode forKey:@"language"]; + [ADJPackageBuilder parameters:parameters setString:[[UIDevice currentDevice] adjDeviceId:_deviceInfo] forKey:@"m"]; [ADJPackageBuilder parameters:parameters setBool:YES forKey:@"needs_response_details"]; [ADJPackageBuilder parameters:parameters setString:self.deviceInfo.osBuild forKey:@"os_build"]; [ADJPackageBuilder parameters:parameters setString:self.deviceInfo.osName forKey:@"os_name"]; [ADJPackageBuilder parameters:parameters setString:self.deviceInfo.systemVersion forKey:@"os_version"]; [ADJPackageBuilder parameters:parameters setDictionary:self.deeplinkParameters forKey:@"params"]; - [ADJPackageBuilder parameters:parameters setDictionary:self.sessionParameters.partnerParameters forKey:@"partner_params"]; + [ADJPackageBuilder parameters:parameters setDictionary:[self.sessionParameters.partnerParameters copy] forKey:@"partner_params"]; [ADJPackageBuilder parameters:parameters setDate:self.purchaseTime forKey:@"purchase_time"]; [ADJPackageBuilder parameters:parameters setString:self.adjustConfig.secretId forKey:@"secret_id"]; [ADJPackageBuilder parameters:parameters setString:source forKey:@"source"]; - [ADJPackageBuilder parameters:parameters setInt:UIDevice.currentDevice.adjTrackingEnabled forKey:@"tracking_enabled"]; + + if ([self.trackingStatusManager canGetAttStatus]) { + [ADJPackageBuilder parameters:parameters setInt:self.trackingStatusManager.attStatus + forKey:@"att_status"]; + } else { + [ADJPackageBuilder parameters:parameters setInt:self.trackingStatusManager.trackingEnabled + forKey:@"tracking_enabled"]; + } if (self.adjustConfig.isDeviceKnown) { [ADJPackageBuilder parameters:parameters setBool:self.adjustConfig.isDeviceKnown forKey:@"device_known"]; @@ -540,7 +686,7 @@ - (NSMutableDictionary *)getClickParameters:(NSString *)source { [ADJPackageBuilder parameters:parameters setString:self.attribution.trackerName forKey:@"tracker"]; } -#if !TARGET_OS_TV +#if !TARGET_OS_TV && !TARGET_OS_MACCATALYST [ADJPackageBuilder parameters:parameters setString:[ADJUtil readMCC] forKey:@"mcc"]; [ADJPackageBuilder parameters:parameters setString:[ADJUtil readMNC] forKey:@"mnc"]; [ADJPackageBuilder parameters:parameters setString:[ADJUtil readCurrentRadioAccessTechnology] forKey:@"network_type"]; @@ -569,6 +715,7 @@ - (NSMutableDictionary *)getAttributionParameters:(NSString *)initiatedBy { } [ADJPackageBuilder parameters:parameters setString:self.deviceInfo.vendorId forKey:@"idfv"]; [ADJPackageBuilder parameters:parameters setString:initiatedBy forKey:@"initiated_by"]; + [ADJPackageBuilder parameters:parameters setString:[[UIDevice currentDevice] adjDeviceId:_deviceInfo] forKey:@"m"]; [ADJPackageBuilder parameters:parameters setBool:YES forKey:@"needs_response_details"]; [ADJPackageBuilder parameters:parameters setString:self.deviceInfo.osBuild forKey:@"os_build"]; [ADJPackageBuilder parameters:parameters setString:self.deviceInfo.osName forKey:@"os_name"]; @@ -578,6 +725,14 @@ - (NSMutableDictionary *)getAttributionParameters:(NSString *)initiatedBy { if (self.adjustConfig.isDeviceKnown) { [ADJPackageBuilder parameters:parameters setBool:self.adjustConfig.isDeviceKnown forKey:@"device_known"]; } + + if ([self.trackingStatusManager canGetAttStatus]) { + [ADJPackageBuilder parameters:parameters setInt:self.trackingStatusManager.attStatus + forKey:@"att_status"]; + } else { + [ADJPackageBuilder parameters:parameters setInt:self.trackingStatusManager.trackingEnabled + forKey:@"tracking_enabled"]; + } if (self.activityState != nil) { if (self.activityState.isPersisted) { @@ -609,6 +764,7 @@ - (NSMutableDictionary *)getGdprParameters { [ADJPackageBuilder parameters:parameters setString:UIDevice.currentDevice.adjIdForAdvertisers forKey:@"idfa"]; } [ADJPackageBuilder parameters:parameters setString:self.deviceInfo.vendorId forKey:@"idfv"]; + [ADJPackageBuilder parameters:parameters setString:[[UIDevice currentDevice] adjDeviceId:_deviceInfo] forKey:@"m"]; [ADJPackageBuilder parameters:parameters setBool:YES forKey:@"needs_response_details"]; [ADJPackageBuilder parameters:parameters setString:self.deviceInfo.osBuild forKey:@"os_build"]; [ADJPackageBuilder parameters:parameters setString:self.deviceInfo.osName forKey:@"os_name"]; @@ -618,6 +774,14 @@ - (NSMutableDictionary *)getGdprParameters { if (self.adjustConfig.isDeviceKnown) { [ADJPackageBuilder parameters:parameters setBool:self.adjustConfig.isDeviceKnown forKey:@"device_known"]; } + + if ([self.trackingStatusManager canGetAttStatus]) { + [ADJPackageBuilder parameters:parameters setInt:self.trackingStatusManager.attStatus + forKey:@"att_status"]; + } else { + [ADJPackageBuilder parameters:parameters setInt:self.trackingStatusManager.trackingEnabled + forKey:@"tracking_enabled"]; + } if (self.activityState != nil) { if (self.activityState.isPersisted) { @@ -640,7 +804,7 @@ - (NSMutableDictionary *)getDisableThirdPartySharingParameters { [ADJPackageBuilder parameters:parameters setString:self.deviceInfo.bundleShortVersion forKey:@"app_version_short"]; [ADJPackageBuilder parameters:parameters setBool:YES forKey:@"attribution_deeplink"]; [ADJPackageBuilder parameters:parameters setString:self.deviceInfo.bundeIdentifier forKey:@"bundle_id"]; - [ADJPackageBuilder parameters:parameters setDictionary:self.sessionParameters.callbackParameters forKey:@"callback_params"]; + [ADJPackageBuilder parameters:parameters setDictionary:[self.sessionParameters.callbackParameters copy] forKey:@"callback_params"]; [ADJPackageBuilder parameters:parameters setDate:self.clickTime forKey:@"click_time"]; [ADJPackageBuilder parameters:parameters setNumberInt:[ADJUtil readReachabilityFlags] forKey:@"connectivity_type"]; [ADJPackageBuilder parameters:parameters setString:self.deviceInfo.countryCode forKey:@"country"]; @@ -663,16 +827,24 @@ - (NSMutableDictionary *)getDisableThirdPartySharingParameters { [ADJPackageBuilder parameters:parameters setString:self.deviceInfo.installReceiptBase64 forKey:@"install_receipt"]; [ADJPackageBuilder parameters:parameters setString:[ADJUtil getInstallTime] forKey:@"installed_at"]; [ADJPackageBuilder parameters:parameters setString:self.deviceInfo.languageCode forKey:@"language"]; + [ADJPackageBuilder parameters:parameters setString:[[UIDevice currentDevice] adjDeviceId:_deviceInfo] forKey:@"m"]; [ADJPackageBuilder parameters:parameters setBool:YES forKey:@"needs_response_details"]; [ADJPackageBuilder parameters:parameters setString:self.deviceInfo.osBuild forKey:@"os_build"]; [ADJPackageBuilder parameters:parameters setString:self.deviceInfo.osName forKey:@"os_name"]; [ADJPackageBuilder parameters:parameters setString:self.deviceInfo.systemVersion forKey:@"os_version"]; [ADJPackageBuilder parameters:parameters setDictionary:self.deeplinkParameters forKey:@"params"]; - [ADJPackageBuilder parameters:parameters setDictionary:self.sessionParameters.partnerParameters forKey:@"partner_params"]; + [ADJPackageBuilder parameters:parameters setDictionary:[self.sessionParameters.partnerParameters copy] forKey:@"partner_params"]; [ADJPackageBuilder parameters:parameters setDate:self.purchaseTime forKey:@"purchase_time"]; [ADJPackageBuilder parameters:parameters setString:self.adjustConfig.secretId forKey:@"secret_id"]; - [ADJPackageBuilder parameters:parameters setInt:UIDevice.currentDevice.adjTrackingEnabled forKey:@"tracking_enabled"]; + if ([self.trackingStatusManager canGetAttStatus]) { + [ADJPackageBuilder parameters:parameters setInt:self.trackingStatusManager.attStatus + forKey:@"att_status"]; + } else { + [ADJPackageBuilder parameters:parameters setInt:self.trackingStatusManager.trackingEnabled + forKey:@"tracking_enabled"]; + } + if (self.adjustConfig.isDeviceKnown) { [ADJPackageBuilder parameters:parameters setBool:self.adjustConfig.isDeviceKnown forKey:@"device_known"]; } @@ -691,7 +863,7 @@ - (NSMutableDictionary *)getDisableThirdPartySharingParameters { } } -#if !TARGET_OS_TV +#if !TARGET_OS_TV && !TARGET_OS_MACCATALYST [ADJPackageBuilder parameters:parameters setString:[ADJUtil readMCC] forKey:@"mcc"]; [ADJPackageBuilder parameters:parameters setString:[ADJUtil readMNC] forKey:@"mnc"]; [ADJPackageBuilder parameters:parameters setString:[ADJUtil readCurrentRadioAccessTechnology] forKey:@"network_type"]; @@ -700,6 +872,91 @@ - (NSMutableDictionary *)getDisableThirdPartySharingParameters { return parameters; } +- (NSMutableDictionary *)getSubscriptionParameters:(BOOL)isInDelay forSubscriptionPackage:(ADJSubscription *)subscription { + NSMutableDictionary *parameters = [NSMutableDictionary dictionary]; + + [ADJPackageBuilder parameters:parameters setString:self.adjustConfig.appSecret forKey:@"app_secret"]; + [ADJPackageBuilder parameters:parameters setString:self.adjustConfig.appToken forKey:@"app_token"]; + [ADJPackageBuilder parameters:parameters setString:self.deviceInfo.bundleVersion forKey:@"app_version"]; + [ADJPackageBuilder parameters:parameters setString:self.deviceInfo.bundleShortVersion forKey:@"app_version_short"]; + [ADJPackageBuilder parameters:parameters setBool:YES forKey:@"attribution_deeplink"]; + [ADJPackageBuilder parameters:parameters setString:self.deviceInfo.bundeIdentifier forKey:@"bundle_id"]; + [ADJPackageBuilder parameters:parameters setNumberInt:[ADJUtil readReachabilityFlags] forKey:@"connectivity_type"]; + [ADJPackageBuilder parameters:parameters setString:self.deviceInfo.countryCode forKey:@"country"]; + [ADJPackageBuilder parameters:parameters setString:self.deviceInfo.cpuSubtype forKey:@"cpu_type"]; + [ADJPackageBuilder parameters:parameters setDate1970:self.createdAt forKey:@"created_at"]; + [ADJPackageBuilder parameters:parameters setString:self.deviceInfo.deviceName forKey:@"device_name"]; + [ADJPackageBuilder parameters:parameters setString:self.deviceInfo.deviceType forKey:@"device_type"]; + [ADJPackageBuilder parameters:parameters setString:self.adjustConfig.environment forKey:@"environment"]; + [ADJPackageBuilder parameters:parameters setBool:self.adjustConfig.eventBufferingEnabled forKey:@"event_buffering_enabled"]; + [ADJPackageBuilder parameters:parameters setString:self.adjustConfig.externalDeviceId forKey:@"external_device_id"]; + [ADJPackageBuilder parameters:parameters setString:self.deviceInfo.fbAnonymousId forKey:@"fb_anon_id"]; + [ADJPackageBuilder parameters:parameters setString:self.deviceInfo.machineModel forKey:@"hardware_name"]; + if (self.adjustConfig.allowIdfaReading == YES) { + [ADJPackageBuilder parameters:parameters setString:UIDevice.currentDevice.adjIdForAdvertisers forKey:@"idfa"]; + } + [ADJPackageBuilder parameters:parameters setString:self.deviceInfo.vendorId forKey:@"idfv"]; + [ADJPackageBuilder parameters:parameters setString:self.deviceInfo.languageCode forKey:@"language"]; + [ADJPackageBuilder parameters:parameters setString:[[UIDevice currentDevice] adjDeviceId:_deviceInfo] forKey:@"m"]; + [ADJPackageBuilder parameters:parameters setBool:YES forKey:@"needs_response_details"]; + [ADJPackageBuilder parameters:parameters setString:self.deviceInfo.osBuild forKey:@"os_build"]; + [ADJPackageBuilder parameters:parameters setString:self.deviceInfo.osName forKey:@"os_name"]; + [ADJPackageBuilder parameters:parameters setString:self.deviceInfo.systemVersion forKey:@"os_version"]; + [ADJPackageBuilder parameters:parameters setString:self.adjustConfig.secretId forKey:@"secret_id"]; + + if ([self.trackingStatusManager canGetAttStatus]) { + [ADJPackageBuilder parameters:parameters setInt:self.trackingStatusManager.attStatus + forKey:@"att_status"]; + } else { + [ADJPackageBuilder parameters:parameters setInt:self.trackingStatusManager.trackingEnabled + forKey:@"tracking_enabled"]; + } + + if (self.adjustConfig.isDeviceKnown) { + [ADJPackageBuilder parameters:parameters setBool:self.adjustConfig.isDeviceKnown forKey:@"device_known"]; + } + + if (self.activityState != nil) { + [ADJPackageBuilder parameters:parameters setString:self.activityState.deviceToken forKey:@"push_token"]; + [ADJPackageBuilder parameters:parameters setInt:self.activityState.sessionCount forKey:@"session_count"]; + [ADJPackageBuilder parameters:parameters setDuration:self.activityState.sessionLength forKey:@"session_length"]; + [ADJPackageBuilder parameters:parameters setInt:self.activityState.subsessionCount forKey:@"subsession_count"]; + [ADJPackageBuilder parameters:parameters setDuration:self.activityState.timeSpent forKey:@"time_spent"]; + if (self.activityState.isPersisted) { + [ADJPackageBuilder parameters:parameters setString:self.activityState.uuid forKey:@"persistent_ios_uuid"]; + } else { + [ADJPackageBuilder parameters:parameters setString:self.activityState.uuid forKey:@"ios_uuid"]; + } + } + + if (!isInDelay) { + NSDictionary *mergedCallbackParameters = [ADJUtil mergeParameters:self.sessionParameters.callbackParameters + source:subscription.callbackParameters + parameterName:@"Callback"]; + NSDictionary *mergedPartnerParameters = [ADJUtil mergeParameters:self.sessionParameters.partnerParameters + source:subscription.partnerParameters + parameterName:@"Partner"]; + + [ADJPackageBuilder parameters:parameters setDictionary:mergedCallbackParameters forKey:@"callback_params"]; + [ADJPackageBuilder parameters:parameters setDictionary:mergedPartnerParameters forKey:@"partner_params"]; + } + + [ADJPackageBuilder parameters:parameters setNumber:subscription.price forKey:@"revenue"]; + [ADJPackageBuilder parameters:parameters setString:subscription.currency forKey:@"currency"]; + [ADJPackageBuilder parameters:parameters setString:subscription.transactionId forKey:@"transaction_id"]; + [ADJPackageBuilder parameters:parameters setString:[subscription.receipt adjEncodeBase64] forKey:@"receipt"]; + [ADJPackageBuilder parameters:parameters setString:subscription.billingStore forKey:@"billing_store"]; + [ADJPackageBuilder parameters:parameters setDate:subscription.transactionDate forKey:@"transaction_date"]; + [ADJPackageBuilder parameters:parameters setString:subscription.salesRegion forKey:@"sales_region"]; + +#if !TARGET_OS_TV && !TARGET_OS_MACCATALYST + [ADJPackageBuilder parameters:parameters setString:[ADJUtil readMCC] forKey:@"mcc"]; + [ADJPackageBuilder parameters:parameters setString:[ADJUtil readMNC] forKey:@"mnc"]; + [ADJPackageBuilder parameters:parameters setString:[ADJUtil readCurrentRadioAccessTechnology] forKey:@"network_type"]; +#endif + + return parameters; +} - (ADJActivityPackage *)defaultActivityPackage { ADJActivityPackage *activityPackage = [[ADJActivityPackage alloc] init]; diff --git a/Adjust/ADJPackageHandler.h b/Adjust/ADJPackageHandler.h index a69a2df97..2cd77a52c 100644 --- a/Adjust/ADJPackageHandler.h +++ b/Adjust/ADJPackageHandler.h @@ -12,31 +12,25 @@ #import "ADJActivityHandler.h" #import "ADJResponseData.h" #import "ADJSessionParameters.h" +#import "ADJRequestHandler.h" +#import "ADJUrlStrategy.h" -@protocol ADJPackageHandler +@interface ADJPackageHandler : NSObject - (id)initWithActivityHandler:(id)activityHandler - startsSending:(BOOL)startsSending; + startsSending:(BOOL)startsSending + userAgent:(NSString *)userAgent + urlStrategy:(ADJUrlStrategy *)urlStrategy; + //extraPath:(NSString *)extraPath; - (void)addPackage:(ADJActivityPackage *)package; - (void)sendFirstPackage; -- (void)sendNextPackage:(ADJResponseData *)responseData; -- (void)closeFirstPackage:(ADJResponseData *)responseData - activityPackage:(ADJActivityPackage *)activityPackage; - (void)pauseSending; - (void)resumeSending; - (void)updatePackages:(ADJSessionParameters *)sessionParameters; - (void)flush; -- (NSString *)getBasePath; -- (NSString *)getGdprPath; - (void)teardown; + (void)deleteState; -@end - -@interface ADJPackageHandler : NSObject - -+ (id)handlerWithActivityHandler:(id)activityHandler - startsSending:(BOOL)startsSending; @end diff --git a/Adjust/ADJPackageHandler.m b/Adjust/ADJPackageHandler.m index 38122469b..8be21e94e 100644 --- a/Adjust/ADJPackageHandler.m +++ b/Adjust/ADJPackageHandler.m @@ -6,7 +6,7 @@ // Copyright (c) 2013 adjust GmbH. All rights reserved. // -#import "ADJRequestHandler.h" +#import "ADJPackageHandler.h" #import "ADJActivityPackage.h" #import "ADJLogger.h" #import "ADJUtil.h" @@ -24,29 +24,24 @@ @interface ADJPackageHandler() @property (nonatomic, strong) dispatch_queue_t internalQueue; @property (nonatomic, strong) dispatch_semaphore_t sendingSemaphore; -@property (nonatomic, strong) id requestHandler; +@property (nonatomic, strong) ADJRequestHandler *requestHandler; @property (nonatomic, strong) NSMutableArray *packageQueue; @property (nonatomic, strong) ADJBackoffStrategy *backoffStrategy; @property (nonatomic, strong) ADJBackoffStrategy *backoffStrategyForInstallSession; @property (nonatomic, assign) BOOL paused; @property (nonatomic, weak) id activityHandler; @property (nonatomic, weak) id logger; -@property (nonatomic, copy) NSString *basePath; -@property (nonatomic, copy) NSString *gdprPath; +@property (nonatomic, assign) NSInteger lastPackageRetriesCount; @end #pragma mark - @implementation ADJPackageHandler -+ (id)handlerWithActivityHandler:(id)activityHandler - startsSending:(BOOL)startsSending -{ - return [[ADJPackageHandler alloc] initWithActivityHandler:activityHandler startsSending:startsSending]; -} - - (id)initWithActivityHandler:(id)activityHandler startsSending:(BOOL)startsSending + userAgent:(NSString *)userAgent + urlStrategy:(ADJUrlStrategy *)urlStrategy { self = [super init]; if (self == nil) return nil; @@ -54,15 +49,16 @@ - (id)initWithActivityHandler:(id)activityHandler self.internalQueue = dispatch_queue_create(kInternalQueueName, DISPATCH_QUEUE_SERIAL); self.backoffStrategy = [ADJAdjustFactory packageHandlerBackoffStrategy]; self.backoffStrategyForInstallSession = [ADJAdjustFactory installSessionBackoffStrategy]; - self.basePath = [activityHandler getBasePath]; - self.gdprPath = [activityHandler getGdprPath]; + self.lastPackageRetriesCount = 0; [ADJUtil launchInQueue:self.internalQueue selfInject:self block:^(ADJPackageHandler * selfI) { [selfI initI:selfI activityHandler:activityHandler - startsSending:startsSending]; + startsSending:startsSending + userAgent:userAgent + urlStrategy:urlStrategy]; }]; return self; @@ -84,7 +80,28 @@ - (void)sendFirstPackage { }]; } -- (void)sendNextPackage:(ADJResponseData *)responseData{ +- (void)responseCallback:(ADJResponseData *)responseData { + if (responseData.jsonResponse) { + [self.logger debug:@"Got JSON response with message: %@", responseData.message]; + } else { + [self.logger error:@"Could not get JSON response with message: %@", responseData.message]; + } + // Check if any package response contains information that user has opted out. + // If yes, disable SDK and flush any potentially stored packages that happened afterwards. + if (responseData.trackingState == ADJTrackingStateOptedOut) { + [self.activityHandler setTrackingStateOptedOut]; + return; + } + if (responseData.jsonResponse == nil) { + [self closeFirstPackage:responseData]; + } else { + [self sendNextPackage:responseData]; + } +} + +- (void)sendNextPackage:(ADJResponseData *)responseData { + self.lastPackageRetriesCount = 0; + [ADJUtil launchInQueue:self.internalQueue selfInject:self block:^(ADJPackageHandler* selfI) { @@ -95,34 +112,31 @@ - (void)sendNextPackage:(ADJResponseData *)responseData{ } - (void)closeFirstPackage:(ADJResponseData *)responseData - activityPackage:(ADJActivityPackage *)activityPackage { responseData.willRetry = YES; [self.activityHandler finishedTracking:responseData]; - dispatch_block_t work = ^{ - [self.logger verbose:@"Package handler can send"]; - dispatch_semaphore_signal(self.sendingSemaphore); + self.lastPackageRetriesCount++; - [self sendFirstPackage]; - }; - - if (activityPackage == nil) { - work(); - return; - } - - NSInteger retries = [activityPackage increaseRetries]; NSTimeInterval waitTime; - if ([activityPackage activityKind] == ADJActivityKindSession && [ADJUserDefaults getInstallTracked] == NO) { - waitTime = [ADJUtil waitingTime:retries backoffStrategy:self.backoffStrategyForInstallSession]; + if (responseData.activityKind == ADJActivityKindSession && [ADJUserDefaults getInstallTracked] == NO) { + waitTime = [ADJUtil waitingTime:self.lastPackageRetriesCount backoffStrategy:self.backoffStrategyForInstallSession]; } else { - waitTime = [ADJUtil waitingTime:retries backoffStrategy:self.backoffStrategy]; + waitTime = [ADJUtil waitingTime:self.lastPackageRetriesCount backoffStrategy:self.backoffStrategy]; } NSString *waitTimeFormatted = [ADJUtil secondsNumberFormat:waitTime]; - [self.logger verbose:@"Waiting for %@ seconds before retrying the %d time", waitTimeFormatted, retries]; - dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(waitTime * NSEC_PER_SEC)), self.internalQueue, work); + [self.logger verbose:@"Waiting for %@ seconds before retrying the %d time", waitTimeFormatted, self.lastPackageRetriesCount]; + dispatch_after + (dispatch_time(DISPATCH_TIME_NOW, (int64_t)(waitTime * NSEC_PER_SEC)), + self.internalQueue, + ^{ + [self.logger verbose:@"Package handler finished waiting"]; + + dispatch_semaphore_signal(self.sendingSemaphore); + + [self sendFirstPackage]; + }); } - (void)pauseSending { @@ -151,22 +165,11 @@ - (void)flush { }]; } -- (NSString *)getBasePath { - return _basePath; -} - -- (NSString *)getGdprPath { - return _gdprPath; -} - - (void)teardown { [ADJAdjustFactory.logger verbose:@"ADJPackageHandler teardown"]; if (self.sendingSemaphore != nil) { dispatch_semaphore_signal(self.sendingSemaphore); } - if (self.requestHandler != nil) { - [self.requestHandler teardown]; - } [self teardownPackageQueueS]; self.internalQueue = nil; self.sendingSemaphore = nil; @@ -185,14 +188,20 @@ + (void)deletePackageQueue { } #pragma mark - internal -- (void)initI:(ADJPackageHandler *)selfI -activityHandler:(id)activityHandler -startsSending:(BOOL)startsSending +- (void) + initI:(ADJPackageHandler *)selfI + activityHandler:(id)activityHandler + startsSending:(BOOL)startsSending + userAgent:(NSString *)userAgent + urlStrategy:(ADJUrlStrategy *)urlStrategy { selfI.activityHandler = activityHandler; selfI.paused = !startsSending; - selfI.requestHandler = [ADJAdjustFactory requestHandlerForPackageHandler:selfI - andActivityHandler:selfI.activityHandler]; + selfI.requestHandler = [[ADJRequestHandler alloc] + initWithResponseCallback:self + urlStrategy:urlStrategy + userAgent:userAgent + requestTimeout:[ADJAdjustFactory requestTimeout]]; selfI.logger = ADJAdjustFactory.logger; selfI.sendingSemaphore = dispatch_semaphore_create(1); [selfI readPackageQueueI:selfI]; @@ -201,7 +210,10 @@ - (void)initI:(ADJPackageHandler *)selfI - (void)addI:(ADJPackageHandler *)selfI package:(ADJActivityPackage *)newPackage { - [selfI.packageQueue addObject:newPackage]; + [ADJUtil launchSynchronisedWithObject:[ADJPackageHandler class] + block:^{ + [selfI.packageQueue addObject:newPackage]; + }]; [selfI.logger debug:@"Added package %d (%@)", selfI.packageQueue.count, newPackage]; [selfI.logger verbose:@"%@", newPackage.extendedString]; @@ -230,13 +242,26 @@ - (void)sendFirstI:(ADJPackageHandler *)selfI return; } - [selfI.requestHandler sendPackage:activityPackage - queueSize:queueSize - 1]; + NSMutableDictionary *sendingParameters = [NSMutableDictionary dictionaryWithCapacity:2]; + if (queueSize - 1 > 0) { + [ADJPackageBuilder parameters:sendingParameters + setInt:(int)queueSize - 1 + forKey:@"queue_size"]; + } + [ADJPackageBuilder parameters:sendingParameters + setString:[ADJUtil formatSeconds1970:[NSDate.date timeIntervalSince1970]] + forKey:@"sent_at"]; + + [selfI.requestHandler sendPackageByPOST:activityPackage + sendingParameters:[sendingParameters copy]]; } - (void)sendNextI:(ADJPackageHandler *)selfI { if ([selfI.packageQueue count] > 0) { - [selfI.packageQueue removeObjectAtIndex:0]; + [ADJUtil launchSynchronisedWithObject:[ADJPackageHandler class] + block:^{ + [selfI.packageQueue removeObjectAtIndex:0]; + }]; [selfI writePackageQueueS:selfI]; } @@ -251,66 +276,83 @@ - (void)updatePackagesI:(ADJPackageHandler *)selfI [selfI.logger verbose:@"Session callback parameters: %@", sessionParameters.callbackParameters]; [selfI.logger verbose:@"Session partner parameters: %@", sessionParameters.partnerParameters]; - for (ADJActivityPackage * activityPackage in selfI.packageQueue) { - // callback parameters - NSDictionary * mergedCallbackParameters = [ADJUtil mergeParameters:sessionParameters.callbackParameters - source:activityPackage.callbackParameters - parameterName:@"Callback"]; - - [ADJPackageBuilder parameters:activityPackage.parameters - setDictionary:mergedCallbackParameters - forKey:@"callback_params"]; - - // partner parameters - NSDictionary * mergedPartnerParameters = [ADJUtil mergeParameters:sessionParameters.partnerParameters - source:activityPackage.partnerParameters - parameterName:@"Partner"]; - - [ADJPackageBuilder parameters:activityPackage.parameters - setDictionary:mergedPartnerParameters - forKey:@"partner_params"]; - } + [ADJUtil launchSynchronisedWithObject:[ADJPackageHandler class] + block:^{ + for (ADJActivityPackage * activityPackage in selfI.packageQueue) { + // callback parameters + NSDictionary * mergedCallbackParameters = [ADJUtil mergeParameters:sessionParameters.callbackParameters + source:activityPackage.callbackParameters + parameterName:@"Callback"]; + + [ADJPackageBuilder parameters:activityPackage.parameters + setDictionary:mergedCallbackParameters + forKey:@"callback_params"]; + + // partner parameters + NSDictionary * mergedPartnerParameters = [ADJUtil mergeParameters:sessionParameters.partnerParameters + source:activityPackage.partnerParameters + parameterName:@"Partner"]; + + [ADJPackageBuilder parameters:activityPackage.parameters + setDictionary:mergedPartnerParameters + forKey:@"partner_params"]; + } + }]; [selfI writePackageQueueS:selfI]; } - (void)flushI:(ADJPackageHandler *)selfI { - [selfI.packageQueue removeAllObjects]; + [ADJUtil launchSynchronisedWithObject:[ADJPackageHandler class] + block:^{ + [selfI.packageQueue removeAllObjects]; + }]; [selfI writePackageQueueS:selfI]; } #pragma mark - private - (void)readPackageQueueI:(ADJPackageHandler *)selfI { - [NSKeyedUnarchiver setClass:[ADJActivityPackage class] forClassName:@"AIActivityPackage"]; - - id object = [ADJUtil readObject:kPackageQueueFilename objectName:@"Package queue" class:[NSArray class]]; - - if (object != nil) { - selfI.packageQueue = object; - } else { - selfI.packageQueue = [NSMutableArray array]; - } + [ADJUtil launchSynchronisedWithObject:[ADJPackageHandler class] + block:^{ + [NSKeyedUnarchiver setClass:[ADJActivityPackage class] forClassName:@"AIActivityPackage"]; + + id object = [ADJUtil readObject:kPackageQueueFilename + objectName:@"Package queue" + class:[NSArray class] + syncObject:[ADJPackageHandler class]]; + + if (object != nil) { + selfI.packageQueue = object; + } else { + selfI.packageQueue = [NSMutableArray array]; + } + }]; } - (void)writePackageQueueS:(ADJPackageHandler *)selfS { - @synchronized ([ADJPackageHandler class]) { - if (selfS.packageQueue == nil) { - return; - } - - [ADJUtil writeObject:selfS.packageQueue fileName:kPackageQueueFilename objectName:@"Package queue"]; + if (selfS.packageQueue == nil) { + return; } + + [ADJUtil launchSynchronisedWithObject:[ADJPackageHandler class] + block:^{ + [ADJUtil writeObject:selfS.packageQueue + fileName:kPackageQueueFilename + objectName:@"Package queue" + syncObject:[ADJPackageHandler class]]; + }]; } - (void)teardownPackageQueueS { - @synchronized ([ADJPackageHandler class]) { - if (self.packageQueue == nil) { - return; - } - + if (self.packageQueue == nil) { + return; + } + + [ADJUtil launchSynchronisedWithObject:[ADJPackageHandler class] + block:^{ [self.packageQueue removeAllObjects]; self.packageQueue = nil; - } + }]; } - (void)dealloc { diff --git a/Adjust/ADJRequestHandler.h b/Adjust/ADJRequestHandler.h index 5dc8d1772..75cc2ba88 100644 --- a/Adjust/ADJRequestHandler.h +++ b/Adjust/ADJRequestHandler.h @@ -7,23 +7,24 @@ // #import -#import "ADJPackageHandler.h" +#import "ADJActivityPackage.h" +#import "ADJUrlStrategy.h" -@protocol ADJRequestHandler - -- (id)initWithPackageHandler:(id)packageHandler - andActivityHandler:(id)activityHandler; - -- (void)sendPackage:(ADJActivityPackage *)activityPackage - queueSize:(NSUInteger)queueSize; +@protocol ADJResponseCallback +- (void)responseCallback:(ADJResponseData *)responseData; +@end -- (void)teardown; +@interface ADJRequestHandler : NSObject -@end +- (id)initWithResponseCallback:(id)responseCallback + urlStrategy:(ADJUrlStrategy *)urlStrategy + userAgent:(NSString *)userAgent + requestTimeout:(double)requestTimeout; -@interface ADJRequestHandler : NSObject +- (void)sendPackageByPOST:(ADJActivityPackage *)activityPackage + sendingParameters:(NSDictionary *)sendingParameters; -+ (id)handlerWithPackageHandler:(id)packageHandler - andActivityHandler:(id)activityHandler; +- (void)sendPackageByGET:(ADJActivityPackage *)activityPackage + sendingParameters:(NSDictionary *)sendingParameters; @end diff --git a/Adjust/ADJRequestHandler.m b/Adjust/ADJRequestHandler.m index 5e8e1bc90..461ae7348 100644 --- a/Adjust/ADJRequestHandler.m +++ b/Adjust/ADJRequestHandler.m @@ -13,22 +13,23 @@ #import "ADJPackageBuilder.h" #import "ADJActivityPackage.h" #import "NSString+ADJAdditions.h" +#include -static const char * const kInternalQueueName = "io.adjust.RequestQueue"; +static NSString * const ADJMethodGET = @"MethodGET"; +static NSString * const ADJMethodPOST = @"MethodPOST"; @interface ADJRequestHandler() -@property (nonatomic, strong) dispatch_queue_t internalQueue; +@property (nonatomic, strong) ADJUrlStrategy *urlStrategy; +@property (nonatomic, copy) NSString *userAgent; +@property (nonatomic, assign) double requestTimeout; +@property (nonatomic, weak) id responseCallback; @property (nonatomic, weak) id logger; -@property (nonatomic, weak) id packageHandler; +@property (nonatomic, copy) NSURLSessionConfiguration *defaultSessionConfiguration; -@property (nonatomic, weak) id activityHandler; - -@property (nonatomic, copy) NSString *basePath; - -@property (nonatomic, copy) NSString *gdprPath; +@property (nonatomic, strong) NSHashTable *exceptionKeys; @end @@ -36,87 +37,580 @@ @implementation ADJRequestHandler #pragma mark - Public methods -+ (ADJRequestHandler *)handlerWithPackageHandler:(id)packageHandler - andActivityHandler:(id)activityHandler { - return [[ADJRequestHandler alloc] initWithPackageHandler:packageHandler - andActivityHandler:activityHandler]; -} - -- (id)initWithPackageHandler:(id)packageHandler - andActivityHandler:(id)activityHandler { +- (id)initWithResponseCallback:(id)responseCallback + urlStrategy:(ADJUrlStrategy *)urlStrategy + userAgent:(NSString *)userAgent + requestTimeout:(double)requestTimeout +{ self = [super init]; if (self == nil) { return nil; } - - self.internalQueue = dispatch_queue_create(kInternalQueueName, DISPATCH_QUEUE_SERIAL); - self.packageHandler = packageHandler; - self.activityHandler = activityHandler; + self.urlStrategy = urlStrategy; + self.userAgent = userAgent; + self.requestTimeout = requestTimeout; + self.responseCallback = responseCallback; + self.logger = ADJAdjustFactory.logger; - self.basePath = [packageHandler getBasePath]; - self.gdprPath = [packageHandler getGdprPath]; + self.defaultSessionConfiguration = [NSURLSessionConfiguration defaultSessionConfiguration]; + + self.exceptionKeys = + [NSHashTable hashTableWithOptions:NSHashTableStrongMemory]; + [self.exceptionKeys addObject:@"event_callback_id"]; + [self.exceptionKeys addObject:@"secret_id"]; + [self.exceptionKeys addObject:@"signature"]; + [self.exceptionKeys addObject:@"headers_id"]; + [self.exceptionKeys addObject:@"native_version"]; + [self.exceptionKeys addObject:@"algorithm"]; + [self.exceptionKeys addObject:@"app_secret"]; return self; } -- (void)sendPackage:(ADJActivityPackage *)activityPackage queueSize:(NSUInteger)queueSize { - [ADJUtil launchInQueue:self.internalQueue - selfInject:self - block:^(ADJRequestHandler* selfI) { - [selfI sendI:selfI activityPackage:activityPackage queueSize:queueSize]; - }]; +- (void)sendPackageByPOST:(ADJActivityPackage *)activityPackage + sendingParameters:(NSDictionary *)sendingParameters +{ + NSDictionary *parameters = [[NSDictionary alloc] + initWithDictionary:activityPackage.parameters + copyItems:YES]; + NSString *path = [activityPackage.path copy]; + NSString *clientSdk = [activityPackage.clientSdk copy]; + ADJActivityKind activityKind = activityPackage.activityKind; + + ADJResponseData *responseData = + [ADJResponseData buildResponseData:activityPackage]; + responseData.sendingParameters = [[NSDictionary alloc] + initWithDictionary:sendingParameters + copyItems:YES]; + + NSString * authorizationHeader = [self buildAuthorizationHeader:parameters activityKind:activityKind]; + + NSString *urlHostString = [self.urlStrategy getUrlHostStringByPackageKind: + activityPackage.activityKind]; + NSMutableURLRequest *urlRequest = + [self requestForPostPackage:path + clientSdk:clientSdk + parameters:parameters + urlHostString:urlHostString + sendingParameters:sendingParameters]; + + [self sendRequest:urlRequest + authorizationHeader:authorizationHeader + responseData:responseData + methodTypeInfo:ADJMethodPOST]; } +- (void)sendPackageByGET:(ADJActivityPackage *)activityPackage + sendingParameters:(NSDictionary *)sendingParameters +{ + NSDictionary *parameters = [[NSDictionary alloc] + initWithDictionary:activityPackage.parameters + copyItems:YES]; + NSString *path = [activityPackage.path copy]; + NSString *clientSdk = [activityPackage.clientSdk copy]; + ADJActivityKind activityKind = activityPackage.activityKind; -- (void)teardown { - [ADJAdjustFactory.logger verbose:@"ADJRequestHandler teardown"]; - - self.logger = nil; - self.internalQueue = nil; - self.packageHandler = nil; - self.activityHandler = nil; + ADJResponseData *responseData = + [ADJResponseData buildResponseData:activityPackage]; + responseData.sendingParameters = [[NSDictionary alloc] + initWithDictionary:sendingParameters + copyItems:YES]; + + NSString * authorizationHeader = [self buildAuthorizationHeader:parameters + activityKind:activityKind]; + + NSString *urlHostString = [self.urlStrategy + getUrlHostStringByPackageKind:activityPackage.activityKind]; + + NSMutableURLRequest *urlRequest = + [self requestForGetPackage:path + clientSdk:clientSdk + parameters:parameters + urlHostString:urlHostString + sendingParameters:sendingParameters]; + + [self sendRequest:urlRequest + authorizationHeader:authorizationHeader + responseData:responseData + methodTypeInfo:ADJMethodGET]; } -#pragma mark - Private & helper methods +#pragma mark Internal methods +- (void)sendRequest:(NSMutableURLRequest *)request +authorizationHeader:(NSString *)authorizationHeader + responseData:(ADJResponseData *)responseData + methodTypeInfo:(NSString *)methodTypeInfo -- (void)sendI:(ADJRequestHandler *)selfI activityPackage:(ADJActivityPackage *)activityPackage queueSize:(NSUInteger)queueSize { - NSURL *url; +{ + if (authorizationHeader != nil) { + [ADJAdjustFactory.logger debug:@"authorizationHeader %@", authorizationHeader]; + [request setValue:authorizationHeader forHTTPHeaderField:@"Authorization"]; + } + if (self.userAgent != nil) { + [request setValue:self.userAgent forHTTPHeaderField:@"User-Agent"]; + } - if (activityPackage.activityKind == ADJActivityKindGdpr) { - NSString *gdprUrl = [ADJAdjustFactory gdprUrl]; - if (selfI.gdprPath != nil) { - url = [NSURL URLWithString:[NSString stringWithFormat:@"%@%@", gdprUrl, selfI.gdprPath]]; - } else { - url = [NSURL URLWithString:gdprUrl]; - } + Class NSURLSessionClass = NSClassFromString(@"NSURLSession"); + if (NSURLSessionClass != nil) { + [self sendNSURLSessionRequest:request + responseData:responseData + methodTypeInfo:methodTypeInfo]; } else { - NSString *baseUrl = [ADJAdjustFactory baseUrl]; - if (selfI.basePath != nil) { - url = [NSURL URLWithString:[NSString stringWithFormat:@"%@%@", baseUrl, selfI.basePath]]; - } else { - url = [NSURL URLWithString:baseUrl]; + [self sendNSURLConnectionRequest:request + responseData:responseData + methodTypeInfo:methodTypeInfo]; + } +} + +- (void)sendNSURLSessionRequest:(NSMutableURLRequest *)request + responseData:(ADJResponseData *)responseData + methodTypeInfo:(NSString *)methodTypeInfo + +{ + NSURLSession *session = + [NSURLSession sessionWithConfiguration:self.defaultSessionConfiguration]; + + NSURLSessionDataTask *task = + [session dataTaskWithRequest:request + completionHandler: + ^(NSData *data, NSURLResponse *response, NSError *error) + { + [self handleResponseWithData:data + response:(NSHTTPURLResponse *)response + error:error + responseData:responseData]; + if (responseData.jsonResponse != nil) { + [self.logger debug:@"succeeded with current url strategy"]; + [self.urlStrategy resetAfterSuccess]; + [self.responseCallback responseCallback:responseData]; + } else if ([self.urlStrategy shouldRetryAfterFailure]) { + [self.logger debug:@"failed with current url strategy, but it will retry with new"]; + [self retryWithResponseData:responseData + methodTypeInfo:methodTypeInfo]; + } else { + [self.logger debug:@"failed with current url strategy and it will not retry"]; + // Stop retrying with different type and return to caller + [self.responseCallback responseCallback:responseData]; + } + }]; + + [task resume]; + [session finishTasksAndInvalidate]; +} + +/* Manual testing code to fail certain percentage of requests + // needs .h to comply with NSURLSessionDelegate +- (void) + URLSession:(NSURLSession *)session + didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge + completionHandler: + (void (^) + (NSURLSessionAuthChallengeDisposition disposition, + NSURLCredential * _Nullable credential))completionHandler +{ + uint32_t randomNumber = arc4random_uniform(2); + NSLog(@"URLSession:didReceiveChallenge:completionHandler: random number %d", randomNumber); + if (randomNumber != 0) { + completionHandler(NSURLSessionAuthChallengeCancelAuthenticationChallenge, nil); + return; + } + + //if (self.urlStrategy.usingIpAddress) { + // completionHandler(NSURLSessionAuthChallengeUseCredential, + // [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]); + //} else { + completionHandler(NSURLSessionAuthChallengePerformDefaultHandling, nil); + //} +} + + - (void)connection:(NSURLConnection *)connection + willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge + { + if (challenge.previousFailureCount > 0) { + [challenge.sender continueWithoutCredentialForAuthenticationChallenge:challenge]; + } else { + NSURLCredential *credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]; + [challenge.sender useCredential:credential forAuthenticationChallenge:challenge]; + } + } + */ + +- (void)sendNSURLConnectionRequest:(NSMutableURLRequest *)request + responseData:(ADJResponseData *)responseData + methodTypeInfo:(NSString *)methodTypeInfo +{ + dispatch_async + (dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), + ^{ + NSError *error = nil; + NSURLResponse *response = nil; + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Wdeprecated-declarations" + NSData *data = [NSURLConnection sendSynchronousRequest:request + returningResponse:&response + error:&error]; + #pragma clang diagnostic pop + + [self handleResponseWithData:data + response:(NSHTTPURLResponse *)response + error:error + responseData:responseData]; + + if (responseData.jsonResponse != nil) { + [self.logger debug:@"succeeded with current url strategy"]; + [self.urlStrategy resetAfterSuccess]; + [self.responseCallback responseCallback:responseData]; + } else if ([self.urlStrategy shouldRetryAfterFailure]) { + [self.logger debug:@"failed with current url strategy, but it will retry with new"]; + [self retryWithResponseData:responseData + methodTypeInfo:methodTypeInfo]; + } else { + [self.logger debug:@"failed with current url strategy and it will not retry"]; + // Stop retrying with different type and return to caller + [self.responseCallback responseCallback:responseData]; + } + }); +} + +- (void)retryWithResponseData:(ADJResponseData *)responseData + methodTypeInfo:(NSString *)methodTypeInfo +{ + ADJActivityPackage *activityPackage = responseData.sdkPackage; + NSDictionary *sendingParameters = responseData.sendingParameters; + + if (methodTypeInfo == ADJMethodGET) { + [self sendPackageByGET:activityPackage + sendingParameters:sendingParameters]; + } else { + [self sendPackageByPOST:activityPackage + sendingParameters:sendingParameters]; + } +} + +- (void)handleResponseWithData:(NSData *)data + response:(NSHTTPURLResponse *)urlResponse + error:(NSError *)responseError + responseData:(ADJResponseData *)responseData +{ + // Connection error + if (responseError != nil) { + responseData.message = responseError.description; + return; + } + if ([ADJUtil isNull:data]) { + responseData.message = @"nil response data"; + return; + } + + NSString *responseString = [[[NSString alloc] + initWithData:data encoding:NSUTF8StringEncoding] adjTrim]; + NSInteger statusCode = urlResponse.statusCode; + [self.logger verbose:@"Response: %@", responseString]; + + if (statusCode == 429) { + responseData.message = @"Too frequent requests to the endpoint (429)"; + return; + } + + [self saveJsonResponse:data responseData:responseData]; + if (responseData.jsonResponse == nil) { + return; + } + + NSString *messageResponse = [responseData.jsonResponse objectForKey:@"message"]; + responseData.message = messageResponse; + responseData.timeStamp = [responseData.jsonResponse objectForKey:@"timestamp"]; + responseData.adid = [responseData.jsonResponse objectForKey:@"adid"]; + + NSString *trackingState = [responseData.jsonResponse objectForKey:@"tracking_state"]; + if (trackingState != nil) { + if ([trackingState isEqualToString:@"opted_out"]) { + responseData.trackingState = ADJTrackingStateOptedOut; } } - [ADJUtil sendPostRequest:url - queueSize:queueSize - prefixErrorMessage:activityPackage.failureMessage - suffixErrorMessage:@"Will retry later" - activityPackage:activityPackage - responseDataHandler:^(ADJResponseData *responseData) { - // Check if any package response contains information that user has opted out. - // If yes, disable SDK and flush any potentially stored packages that happened afterwards. - if (responseData.trackingState == ADJTrackingStateOptedOut) { - [selfI.activityHandler setTrackingStateOptedOut]; - return; - } - if (responseData.jsonResponse == nil) { - [selfI.packageHandler closeFirstPackage:responseData activityPackage:activityPackage]; - return; - } - - [selfI.packageHandler sendNextPackage:responseData]; - }]; + if (statusCode == 200) { + responseData.success = YES; + } +} +#pragma mark - URL Request +- (NSMutableURLRequest *) + requestForPostPackage:(NSString *)path + clientSdk:(NSString *)clientSdk + parameters:(NSDictionary *)parameters + urlHostString:(NSString *)urlHostString + sendingParameters: + (NSDictionary *)sendingParameters +{ + NSString *urlString = [NSString stringWithFormat:@"%@%@%@", + urlHostString, self.urlStrategy.extraPath, path]; + + [self.logger verbose:@"requestForPostPackage with urlString: %@", urlString]; + + NSURL *url = [NSURL URLWithString:urlString]; + //NSURL *url = [baseUrl URLByAppendingPathComponent:path]; + NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url]; + request.timeoutInterval = self.requestTimeout; + request.HTTPMethod = @"POST"; + [request setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"]; + [request setValue:clientSdk forHTTPHeaderField:@"Client-Sdk"]; + + NSUInteger sendingParametersCount = sendingParameters? sendingParameters.count : 0; + NSMutableArray *kvParameters = + [NSMutableArray arrayWithCapacity: + parameters.count + sendingParametersCount]; + + [self injectParameters:parameters + kvArray:kvParameters]; + [self injectParameters:sendingParameters + kvArray:kvParameters]; + + NSString *bodyString = [kvParameters componentsJoinedByString:@"&"]; + NSData *body = [NSData dataWithBytes:bodyString.UTF8String length:bodyString.length]; + [request setHTTPBody:body]; + return request; +} + +- (NSMutableURLRequest *) + requestForGetPackage:(NSString *)path + clientSdk:(NSString *)clientSdk + parameters:(NSDictionary *)parameters + urlHostString:(NSString *)urlHostString + sendingParameters:(NSDictionary *)sendingParameters +{ + NSUInteger sendingParametersCount = sendingParameters? sendingParameters.count : 0; + NSMutableArray *kvParameters = + [NSMutableArray arrayWithCapacity: + parameters.count + sendingParametersCount]; + + [self injectParameters:parameters + kvArray:kvParameters]; + [self injectParameters:sendingParameters + kvArray:kvParameters]; + + NSString *queryStringParameters = [kvParameters componentsJoinedByString:@"&"]; + + NSString *urlString = + [NSString stringWithFormat:@"%@%@%@?%@", + urlHostString, self.urlStrategy.extraPath, path, queryStringParameters]; + + [self.logger verbose:@"requestForGetPackage with urlString: %@", urlString]; + + NSURL *url = [NSURL URLWithString:urlString]; + + NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url]; + request.timeoutInterval = self.requestTimeout; + request.HTTPMethod = @"GET"; + [request setValue:clientSdk forHTTPHeaderField:@"Client-Sdk"]; + return request; +} + +- (void) + injectParameters:(NSDictionary *)parameters + kvArray:(NSMutableArray *)kvArray +{ + if (parameters == nil || parameters.count == 0) { + return; + } + + for (NSString *key in parameters) { + if ([self.exceptionKeys containsObject:key]) { + continue; + } + NSString *value = [parameters objectForKey:key]; + NSString *escapedValue = [value adjUrlEncode]; + NSString *escapedKey = [key adjUrlEncode]; + NSString *pair = [NSString stringWithFormat:@"%@=%@", escapedKey, escapedValue]; + [kvArray addObject:pair]; + } +} + +#pragma mark - Authorization Header +- (NSString *)buildAuthorizationHeader:(NSDictionary *)parameters + activityKind:(ADJActivityKind)activityKind +{ + NSString *secretId = [parameters objectForKey:@"secret_id"]; + NSString *signature = [parameters objectForKey:@"signature"]; + NSString *headersId = [parameters objectForKey:@"headers_id"]; + NSString *nativeVersion = [parameters objectForKey:@"native_version"]; + NSString *algorithm = [parameters objectForKey:@"algorithm"]; + NSString *authorizationHeader = [self buildAuthorizationHeaderV2:signature + secretId:secretId + headersId:headersId + nativeVersion:nativeVersion + algorithm:algorithm]; + if (authorizationHeader != nil) { + return authorizationHeader; + } + + NSString * appSecret = [parameters objectForKey:@"app_secret"]; + return [self buildAuthorizationHeaderV1:appSecret + secretId:secretId + parameters:parameters + activityKind:activityKind]; +} + +- (NSString *)buildAuthorizationHeaderV2:(NSString *)signature + secretId:(NSString *)secretId + headersId:(NSString *)headersId + nativeVersion:(NSString *)nativeVersion + algorithm:(NSString *)algorithm +{ + if (secretId == nil || signature == nil || headersId == nil) { + return nil; + } + + NSString * signatureHeader = [NSString stringWithFormat:@"signature=\"%@\"", signature]; + NSString * secretIdHeader = [NSString stringWithFormat:@"secret_id=\"%@\"", secretId]; + NSString * idHeader = [NSString stringWithFormat:@"headers_id=\"%@\"", headersId]; + NSString * algorithmHeader = [NSString stringWithFormat:@"algorithm=\"%@\"", algorithm != nil ? algorithm : @"adj1"]; + + NSString * authorizationHeader = [NSString stringWithFormat:@"Signature %@,%@,%@,%@", + signatureHeader, secretIdHeader, algorithmHeader, idHeader]; + + if (nativeVersion == nil) { + return [authorizationHeader stringByAppendingFormat:@",native_version=\"\""]; + } + return [authorizationHeader stringByAppendingFormat:@",native_version=\"%@\"", nativeVersion]; +} + +- (NSString *)buildAuthorizationHeaderV1:(NSString *)appSecret + secretId:(NSString *)secretId + parameters:(NSDictionary *)parameters + activityKind:(ADJActivityKind)activityKind +{ + if (appSecret == nil) { + return nil; + } + + NSString *activityKindS = [ADJActivityKindUtil activityKindToString:activityKind]; + NSDictionary *signatureParameters = [self buildSignatureParameters:parameters + appSecret:appSecret + activityKindS:activityKindS]; + NSMutableString *fields = [[NSMutableString alloc] initWithCapacity:5]; + NSMutableString *clearSignature = [[NSMutableString alloc] initWithCapacity:5]; + + // signature part of header + for (NSDictionary *key in signatureParameters) { + [fields appendFormat:@"%@ ", key]; + NSString *value = [signatureParameters objectForKey:key]; + [clearSignature appendString:value]; + } + + NSString *secretIdHeader = [NSString stringWithFormat:@"secret_id=\"%@\"", secretId]; + // algorithm part of header + NSString *algorithm = @"sha256"; + NSString *signature = [clearSignature adjSha256]; + NSString *signatureHeader = [NSString stringWithFormat:@"signature=\"%@\"", signature]; + NSString *algorithmHeader = [NSString stringWithFormat:@"algorithm=\"%@\"", algorithm]; + // fields part of header + // Remove last empty space. + if (fields.length > 0) { + [fields deleteCharactersInRange:NSMakeRange(fields.length - 1, 1)]; + } + + NSString *fieldsHeader = [NSString stringWithFormat:@"headers=\"%@\"", fields]; + // putting it all together + NSString *authorizationHeader = [NSString stringWithFormat:@"Signature %@,%@,%@,%@", + secretIdHeader, + signatureHeader, + algorithmHeader, + fieldsHeader]; + return authorizationHeader; +} + +- (NSDictionary *)buildSignatureParameters:(NSDictionary *)parameters + appSecret:(NSString *)appSecret + activityKindS:(NSString *)activityKindS { + NSString *appSecretName = @"app_secret"; + NSString *sourceName = @"source"; + NSString *payloadName = @"payload"; + NSString *activityKindName = @"activity_kind"; + NSString *activityKindValue = activityKindS; + NSString *createdAtName = @"created_at"; + NSString *createdAtValue = [parameters objectForKey:createdAtName]; + NSString *deviceIdentifierName = [self getValidIdentifier:parameters]; + NSString *deviceIdentifierValue = [parameters objectForKey:deviceIdentifierName]; + NSMutableDictionary *signatureParameters = [[NSMutableDictionary alloc] initWithCapacity:6]; + + [self checkAndAddEntry:signatureParameters key:appSecretName value:appSecret]; + [self checkAndAddEntry:signatureParameters key:createdAtName value:createdAtValue]; + [self checkAndAddEntry:signatureParameters key:activityKindName value:activityKindValue]; + [self checkAndAddEntry:signatureParameters key:deviceIdentifierName value:deviceIdentifierValue]; + [self checkAndAddEntry:signatureParameters key:sourceName value:parameters[sourceName]]; + [self checkAndAddEntry:signatureParameters key:payloadName value:parameters[payloadName]]; + + return signatureParameters; +} + +- (void)checkAndAddEntry:(NSMutableDictionary *)parameters + key:(NSString *)key + value:(NSString *)value { + if (key == nil) { + return; + } + + if (value == nil) { + return; + } + + [parameters setObject:value forKey:key]; +} + +- (NSString *)getValidIdentifier:(NSDictionary *)parameters { + NSString *idfaName = @"idfa"; + NSString *persistentUUIDName = @"persistent_ios_uuid"; + NSString *uuidName = @"ios_uuid"; + + if ([parameters objectForKey:idfaName] != nil) { + return idfaName; + } + if ([parameters objectForKey:persistentUUIDName] != nil) { + return persistentUUIDName; + } + if ([parameters objectForKey:uuidName] != nil) { + return uuidName; + } + return nil; +} + +#pragma mark - JSON +- (void)saveJsonResponse:(NSData *)jsonData responseData:(ADJResponseData *)responseData { + NSError *error = nil; + NSException *exception = nil; + NSDictionary *jsonDict = + [self buildJsonDict:jsonData exceptionPtr:&exception errorPtr:&error]; + + if (exception != nil) { + responseData.message = + [NSString stringWithFormat: + @"Failed to parse json response. (%@)", exception.description]; + } else if (error != nil) { + responseData.message = + [NSString stringWithFormat: + @"Failed to parse json response. (%@)", error.localizedDescription]; + } else if ([ADJUtil isNull:jsonDict]) { + responseData.message = [NSString stringWithFormat:@"Failed to parse json response "]; + } else { + responseData.jsonResponse = jsonDict; + } +} + +- (NSDictionary *)buildJsonDict:(NSData *)jsonData + exceptionPtr:(NSException **)exceptionPtr + errorPtr:(NSError **)error { + if (jsonData == nil) { + return nil; + } + + NSDictionary *jsonDict = nil; + @try { + jsonDict = [NSJSONSerialization JSONObjectWithData:jsonData options:0 error:error]; + } @catch (NSException *ex) { + *exceptionPtr = ex; + return nil; + } + return jsonDict; } @end diff --git a/Adjust/ADJResponseData.h b/Adjust/ADJResponseData.h index 57b209398..dc4014062 100644 --- a/Adjust/ADJResponseData.h +++ b/Adjust/ADJResponseData.h @@ -39,9 +39,11 @@ typedef NS_ENUM(int, ADJTrackingState) { @property (nonatomic, copy) ADJAttribution *attribution; -- (id)init; +@property (nonatomic, copy) NSDictionary *sendingParameters; -+ (ADJResponseData *)responseData; +@property (nonatomic, strong) ADJActivityPackage *sdkClickPackage; + +@property (nonatomic, strong) ADJActivityPackage *sdkPackage; + (id)buildResponseData:(ADJActivityPackage *)activityPackage; @@ -68,9 +70,8 @@ typedef NS_ENUM(int, ADJTrackingState) { - (ADJEventFailure *)failureResponseData; -- (id)initWithActivityPackage:(ADJActivityPackage *)activityPackage; - -+ (ADJResponseData *)responseDataWithActivityPackage:(ADJActivityPackage *)activityPackage; +- (id)initWithEventToken:(NSString *)eventToken + callbackId:(NSString *)callbackId; @end diff --git a/Adjust/ADJResponseData.m b/Adjust/ADJResponseData.m index 986043723..977e8d12c 100644 --- a/Adjust/ADJResponseData.m +++ b/Adjust/ADJResponseData.m @@ -11,13 +11,14 @@ @implementation ADJResponseData -- (id)init { +- (id)init +{ self = [super init]; if (self == nil) { return nil; } - + return self; } @@ -42,9 +43,16 @@ + (id)buildResponseData:(ADJActivityPackage *)activityPackage { break; case ADJActivityKindClick: responseData = [[ADJSdkClickResponseData alloc] init]; + responseData.sdkClickPackage = activityPackage; break; case ADJActivityKindEvent: - responseData = [[ADJEventResponseData alloc] initWithActivityPackage:activityPackage]; + responseData = [[ADJEventResponseData alloc] + initWithEventToken: + [activityPackage.parameters + objectForKey:@"event_token"] + callbackId: + [activityPackage.parameters + objectForKey:@"event_callback_id"]]; break; case ADJActivityKindAttribution: responseData = [[ADJAttributionResponseData alloc] init]; @@ -54,6 +62,7 @@ + (id)buildResponseData:(ADJActivityPackage *)activityPackage { break; } + responseData.sdkPackage = activityPackage; responseData.activityKind = activityKind; return responseData; @@ -73,7 +82,6 @@ - (id)copyWithZone:(NSZone *)zone { copy.message = [self.message copyWithZone:zone]; copy.timeStamp = [self.timeStamp copyWithZone:zone]; copy.adid = [self.adid copyWithZone:zone]; - copy.success = self.success; copy.willRetry = self.willRetry; copy.trackingState = self.trackingState; copy.jsonResponse = [self.jsonResponse copyWithZone:zone]; @@ -87,16 +95,6 @@ - (id)copyWithZone:(NSZone *)zone { @implementation ADJSessionResponseData -- (id)initWithActivityPackage:(ADJActivityPackage *)activityPackage { - self = [super init]; - - if (self == nil) { - return nil; - } - - return self; -} - - (ADJSessionSuccess *)successResponseData { ADJSessionSuccess *successResponseData = [ADJSessionSuccess sessionSuccessResponseData]; @@ -133,19 +131,17 @@ @implementation ADJSdkClickResponseData @implementation ADJEventResponseData -+ (ADJEventResponseData *)responseDataWithActivityPackage:(ADJActivityPackage *)activityPackage { - return [[ADJEventResponseData alloc] initWithActivityPackage:activityPackage]; -} - -- (id)initWithActivityPackage:(ADJActivityPackage *)activityPackage { +- (id)initWithEventToken:(NSString *)eventToken + callbackId:(NSString *)callbackId +{ self = [super init]; if (self == nil) { return nil; } - self.eventToken = [activityPackage.parameters objectForKey:@"event_token"]; - self.callbackId = [activityPackage.parameters objectForKey:@"event_callback_id"]; + self.eventToken = eventToken; + self.callbackId = callbackId; return self; } @@ -196,16 +192,6 @@ - (id)copyWithZone:(NSZone *)zone { @implementation ADJAttributionResponseData -- (id)initWithActivityPackage:(ADJActivityPackage *)activityPackage { - self = [super init]; - - if (self == nil) { - return nil; - } - - return self; -} - - (id)copyWithZone:(NSZone *)zone { ADJAttributionResponseData *copy = [super copyWithZone:zone]; diff --git a/Adjust/ADJSdkClickHandler.h b/Adjust/ADJSdkClickHandler.h index b74ddfda7..3175aa3fd 100644 --- a/Adjust/ADJSdkClickHandler.h +++ b/Adjust/ADJSdkClickHandler.h @@ -9,21 +9,18 @@ #import #import "ADJActivityPackage.h" #import "ADJActivityHandler.h" +#import "ADJRequestHandler.h" +#import "ADJUrlStrategy.h" -@protocol ADJSdkClickHandler +@interface ADJSdkClickHandler : NSObject - (id)initWithActivityHandler:(id)activityHandler - startsSending:(BOOL)startsSending; + startsSending:(BOOL)startsSending + userAgent:(NSString *)userAgent + urlStrategy:(ADJUrlStrategy *)urlStrategy; - (void)pauseSending; - (void)resumeSending; - (void)sendSdkClick:(ADJActivityPackage *)sdkClickPackage; - (void)teardown; @end - -@interface ADJSdkClickHandler : NSObject - -+ (id)handlerWithActivityHandler:(id)activityHandler - startsSending:(BOOL)startsSending; - -@end diff --git a/Adjust/ADJSdkClickHandler.m b/Adjust/ADJSdkClickHandler.m index fe8da9019..309250297 100644 --- a/Adjust/ADJSdkClickHandler.m +++ b/Adjust/ADJSdkClickHandler.m @@ -11,14 +11,15 @@ #import "ADJAdjustFactory.h" #import "ADJSdkClickHandler.h" #import "ADJBackoffStrategy.h" +#import "ADJUserDefaults.h" static const char * const kInternalQueueName = "com.adjust.SdkClickQueue"; @interface ADJSdkClickHandler() -@property (nonatomic, copy) NSString *basePath; @property (nonatomic, strong) NSMutableArray *packageQueue; @property (nonatomic, strong) dispatch_queue_t internalQueue; +@property (nonatomic, strong) ADJRequestHandler *requestHandler; @property (nonatomic, assign) BOOL paused; @property (nonatomic, strong) ADJBackoffStrategy *backoffStrategy; @@ -26,22 +27,19 @@ @interface ADJSdkClickHandler() @property (nonatomic, weak) id logger; @property (nonatomic, weak) id activityHandler; +@property (nonatomic, assign) NSInteger lastPackageRetriesCount; + @end @implementation ADJSdkClickHandler -#pragma mark - Public class methods - -+ (id)handlerWithActivityHandler:(id)activityHandler - startsSending:(BOOL)startsSending { - return [[ADJSdkClickHandler alloc] initWithActivityHandler:activityHandler - startsSending:startsSending]; -} - #pragma mark - Public instance methods - (id)initWithActivityHandler:(id)activityHandler - startsSending:(BOOL)startsSending { + startsSending:(BOOL)startsSending + userAgent:(NSString *)userAgent + urlStrategy:(ADJUrlStrategy *)urlStrategy +{ self = [super init]; if (self == nil) { return nil; @@ -49,7 +47,13 @@ - (id)initWithActivityHandler:(id)activityHandler self.internalQueue = dispatch_queue_create(kInternalQueueName, DISPATCH_QUEUE_SERIAL); self.logger = ADJAdjustFactory.logger; - self.basePath = [activityHandler getBasePath]; + self.lastPackageRetriesCount = 0; + + self.requestHandler = [[ADJRequestHandler alloc] + initWithResponseCallback:self + urlStrategy:urlStrategy + userAgent:userAgent + requestTimeout:[ADJAdjustFactory requestTimeout]]; [ADJUtil launchInQueue:self.internalQueue selfInject:self @@ -141,51 +145,58 @@ - (void)sendNextSdkClickI:(ADJSdkClickHandler *)selfI { return; } - NSURL *url; - NSString *baseUrl = [ADJAdjustFactory baseUrl]; - if (selfI.basePath != nil) { - url = [NSURL URLWithString:[NSString stringWithFormat:@"%@%@", baseUrl, selfI.basePath]]; - } else { - url = [NSURL URLWithString:baseUrl]; - } - dispatch_block_t work = ^{ - [ADJUtil sendPostRequest:url - queueSize:queueSize - 1 - prefixErrorMessage:sdkClickPackage.failureMessage - suffixErrorMessage:@"Will retry later" - activityPackage:sdkClickPackage - responseDataHandler:^(ADJResponseData *responseData) { - // Check if any package response contains information that user has opted out. - // If yes, disable SDK and flush any potentially stored packages that happened afterwards. - if (responseData.trackingState == ADJTrackingStateOptedOut) { - [selfI.activityHandler setTrackingStateOptedOut]; - return; - } - if (responseData.jsonResponse == nil) { - NSInteger retries = [sdkClickPackage increaseRetries]; - [selfI.logger error:@"Retrying sdk_click package for the %d time", retries]; - [selfI sendSdkClick:sdkClickPackage]; - return; - } - - [selfI.activityHandler finishedTracking:responseData]; - }]; + NSDictionary *sendingParameters = @{ + @"sent_at": [ADJUtil formatSeconds1970:[NSDate.date timeIntervalSince1970]] + }; + + [selfI.requestHandler sendPackageByPOST:sdkClickPackage + sendingParameters:sendingParameters]; [selfI sendNextSdkClick]; }; - NSInteger retries = [sdkClickPackage retries]; - if (retries <= 0) { + if (selfI.lastPackageRetriesCount <= 0) { work(); return; } - NSTimeInterval waitTime = [ADJUtil waitingTime:retries backoffStrategy:self.backoffStrategy]; + NSTimeInterval waitTime = [ADJUtil waitingTime:selfI.lastPackageRetriesCount backoffStrategy:self.backoffStrategy]; NSString *waitTimeFormatted = [ADJUtil secondsNumberFormat:waitTime]; - [self.logger verbose:@"Waiting for %@ seconds before retrying sdk_click for the %d time", waitTimeFormatted, retries]; + [self.logger verbose:@"Waiting for %@ seconds before retrying sdk_click for the %d time", waitTimeFormatted, selfI.lastPackageRetriesCount]; dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(waitTime * NSEC_PER_SEC)), self.internalQueue, work); } +- (void)responseCallback:(ADJResponseData *)responseData { + if (responseData.jsonResponse) { + [self.logger debug: + @"Got click JSON response with message: %@", responseData.message]; + } else { + [self.logger error: + @"Could not get click JSON response with message: %@", responseData.message]; + } + // Check if any package response contains information that user has opted out. + // If yes, disable SDK and flush any potentially stored packages that happened afterwards. + if (responseData.trackingState == ADJTrackingStateOptedOut) { + self.lastPackageRetriesCount = 0; + [self.activityHandler setTrackingStateOptedOut]; + return; + } + if (responseData.jsonResponse == nil) { + self.lastPackageRetriesCount++; + [self.logger error:@"Retrying sdk_click package for the %d time", self.lastPackageRetriesCount]; + [self sendSdkClick:responseData.sdkClickPackage]; + return; + } + self.lastPackageRetriesCount = 0; + + if ([responseData.sdkClickPackage.parameters.allValues containsObject:ADJiAdPackageKey]) { + // received iAd click package response, clear the errors from UserDefaults + [ADJUserDefaults cleariAdErrors]; + } + + [self.activityHandler finishedTracking:responseData]; +} + @end diff --git a/Adjust/ADJSubscription.h b/Adjust/ADJSubscription.h new file mode 100644 index 000000000..92f5395ed --- /dev/null +++ b/Adjust/ADJSubscription.h @@ -0,0 +1,44 @@ +// +// ADJSubscription.h +// Adjust +// +// Created by Uglješa Erceg on 16.04.20. +// Copyright © 2020 adjust GmbH. All rights reserved. +// + +#import + +@interface ADJSubscription : NSObject + +@property (nonatomic, copy, readonly, nonnull) NSDecimalNumber *price; // [M] revenue + +@property (nonatomic, copy, readonly, nonnull) NSString *currency; // [M] currency + +@property (nonatomic, copy, readonly, nonnull) NSString *transactionId; // [M] transaction_id + +@property (nonatomic, copy, readonly, nonnull) NSData *receipt; // [M] receipt + +@property (nonatomic, copy, readonly, nonnull) NSString *billingStore; // [M] billing_store + +@property (nonatomic, copy, readonly, nonnull) NSDate *transactionDate; // [O] transaction_date + +@property (nonatomic, copy, readonly, nonnull) NSString *salesRegion; // [O] sales_region + +@property (nonatomic, copy, readonly, nonnull) NSDictionary *callbackParameters; // [O] callback_params + +@property (nonatomic, copy, readonly, nonnull) NSDictionary *partnerParameters; // [O] partner_params + +- (nullable id)initWithPrice:(nonnull NSDecimalNumber *)price + currency:(nonnull NSString *)currency + transactionId:(nonnull NSString *)transactionId + andReceipt:(nonnull NSData *)receipt; + +- (void)setTransactionDate:(nonnull NSDate *)transactionDate; + +- (void)setSalesRegion:(nonnull NSString *)salesRegion; + +- (void)addCallbackParameter:(nonnull NSString *)key value:(nonnull NSString *)value; + +- (void)addPartnerParameter:(nonnull NSString *)key value:(nonnull NSString *)value; + +@end diff --git a/Adjust/ADJSubscription.m b/Adjust/ADJSubscription.m new file mode 100644 index 000000000..4b7b76cc1 --- /dev/null +++ b/Adjust/ADJSubscription.m @@ -0,0 +1,143 @@ +// +// ADJSubscription.m +// Adjust +// +// Created by Uglješa Erceg on 16.04.20. +// Copyright © 2020 adjust GmbH. All rights reserved. +// + +#import "ADJUtil.h" +#import "ADJSubscription.h" +#import "ADJAdjustFactory.h" + +@interface ADJSubscription() + +@property (nonatomic, weak) id logger; + +@property (nonatomic, strong) NSMutableDictionary *mutableCallbackParameters; + +@property (nonatomic, strong) NSMutableDictionary *mutablePartnerParameters; + +@end + +@implementation ADJSubscription + +- (nullable id)initWithPrice:(nonnull NSDecimalNumber *)price + currency:(nonnull NSString *)currency + transactionId:(nonnull NSString *)transactionId + andReceipt:(nonnull NSData *)receipt { + self = [super init]; + if (self == nil) { + return nil; + } + + _price = [price copy]; + _currency = [currency copy]; + _transactionId = [transactionId copy]; + _receipt = [receipt copy]; + _billingStore = @"iOS"; + + _logger = ADJAdjustFactory.logger; + + return self; +} + +- (void)setTransactionDate:(NSDate *)transactionDate { + @synchronized (self) { + _transactionDate = [transactionDate copy]; + } +} + +- (void)setSalesRegion:(NSString *)salesRegion { + @synchronized (self) { + _salesRegion = [salesRegion copy]; + } +} + +- (void)addCallbackParameter:(nonnull NSString *)key + value:(nonnull NSString *)value +{ + @synchronized (self) { + NSString *immutableKey = [key copy]; + NSString *immutableValue = [value copy]; + + if (![ADJUtil isValidParameter:immutableKey + attributeType:@"key" + parameterName:@"Callback"]) { + return; + } + if (![ADJUtil isValidParameter:immutableValue + attributeType:@"value" + parameterName:@"Callback"]) { + return; + } + + if (self.mutableCallbackParameters == nil) { + self.mutableCallbackParameters = [[NSMutableDictionary alloc] init]; + } + + if ([self.mutableCallbackParameters objectForKey:immutableKey]) { + [self.logger warn:@"key %@ was overwritten", immutableKey]; + } + + [self.mutableCallbackParameters setObject:immutableValue forKey:immutableKey]; + } +} + +- (void)addPartnerParameter:(nonnull NSString *)key + value:(nonnull NSString *)value +{ + @synchronized (self) { + NSString *immutableKey = [key copy]; + NSString *immutableValue = [value copy]; + + if (![ADJUtil isValidParameter:immutableKey + attributeType:@"key" + parameterName:@"Partner"]) { + return; + } + if (![ADJUtil isValidParameter:immutableValue + attributeType:@"value" + parameterName:@"Partner"]) { + return; + } + + if (self.mutablePartnerParameters == nil) { + self.mutablePartnerParameters = [[NSMutableDictionary alloc] init]; + } + + if ([self.mutablePartnerParameters objectForKey:immutableKey]) { + [self.logger warn:@"key %@ was overwritten", immutableKey]; + } + + [self.mutablePartnerParameters setObject:immutableValue forKey:immutableKey]; + } +} + +- (nonnull NSDictionary *)callbackParameters { + return [self.mutableCallbackParameters copy]; +} + +- (nonnull NSDictionary *)partnerParameters { + return [self.mutablePartnerParameters copy]; +} + +- (id)copyWithZone:(NSZone *)zone { + ADJSubscription *copy = [[[self class] allocWithZone:zone] init]; + + if (copy) { + copy->_price = [self.price copyWithZone:zone]; + copy->_currency = [self.currency copyWithZone:zone]; + copy->_transactionId = [self.transactionId copyWithZone:zone]; + copy->_receipt = [self.receipt copyWithZone:zone]; + copy->_billingStore = [self.billingStore copyWithZone:zone]; + copy->_transactionDate = [self.transactionDate copyWithZone:zone]; + copy->_salesRegion = [self.salesRegion copyWithZone:zone]; + copy.mutableCallbackParameters = [self.mutableCallbackParameters copyWithZone:zone]; + copy.mutablePartnerParameters = [self.mutablePartnerParameters copyWithZone:zone]; + } + + return copy; +} + +@end diff --git a/Adjust/ADJSystemProfile.h b/Adjust/ADJSystemProfile.h index 280d2a1b6..d51d8dbc1 100644 --- a/Adjust/ADJSystemProfile.h +++ b/Adjust/ADJSystemProfile.h @@ -20,17 +20,24 @@ @interface ADJSystemProfile : NSObject + (BOOL) is64bit; -+ (NSString*) cpuFamily; -+ (NSString*) osVersion; ++ (NSString *)cpuFamily; ++ (NSString *)osVersion; + (int) cpuCount; -+ (NSString*) machineArch; -+ (NSString*) machineModel; -+ (NSString*) cpuBrand; -+ (NSString*) cpuFeatures; -+ (NSString*) cpuVendor; -+ (NSString*) appleLanguage; -+ (long long) cpuSpeed; -+ (long long) ramsize; -+ (NSString*) cpuType; -+ (NSString*) cpuSubtype; ++ (NSString *)machineArch; ++ (NSString *)machineModel; ++ (NSString *)cpuBrand; ++ (NSString *)cpuFeatures; ++ (NSString *)cpuVendor; ++ (NSString *)appleLanguage; ++ (long long)cpuSpeed; ++ (long long)ramsize; ++ (NSString *)cpuType; ++ (NSString *)cpuSubtype; ++ (NSUInteger)totalDiskSpace; ++ (NSUInteger)freeDiskSpace; ++ (NSUInteger)batteryLevel; ++ (NSUInteger)chargingStatus; ++ (NSUInteger)systemUptime; ++ (NSUInteger)lastBootTime; + @end diff --git a/Adjust/ADJSystemProfile.m b/Adjust/ADJSystemProfile.m index 313174751..050390beb 100644 --- a/Adjust/ADJSystemProfile.m +++ b/Adjust/ADJSystemProfile.m @@ -21,25 +21,23 @@ #import #import "ADJAdjustFactory.h" #import "ADJLogger.h" +#import "UIDevice+ADJAdditions.h" +#import "ADJUtil.h" @implementation ADJSystemProfile -+ (BOOL) is64bit -{ ++ (BOOL)is64bit { int error = 0; int value = 0; size_t length = sizeof(value); error = sysctlbyname("hw.cpu64bit_capable", &value, &length, NULL, 0); - - if(error != 0) { + if (error != 0) { error = sysctlbyname("hw.optional.x86_64", &value, &length, NULL, 0); //x86 specific } - - if(error != 0) { + if (error != 0) { error = sysctlbyname("hw.optional.64bitops", &value, &length, NULL, 0); //PPC specific } - if (error != 0) { return NO; } @@ -47,16 +45,15 @@ + (BOOL) is64bit return value == 1; } -+ (NSString*) cpuFamily -{ ++ (NSString *)cpuFamily { int cpufamily = -1; size_t length = sizeof(cpufamily); int error = sysctlbyname("hw.cpufamily", &cpufamily, &length, NULL, 0); - if (error != 0) { [ADJAdjustFactory.logger error:@"Failed to obtain CPU family (%d)", error]; return nil; } + switch (cpufamily) { #ifdef CPUFAMILY_UNKNOWN @@ -168,22 +165,21 @@ + (NSString*) cpuFamily return @"CPUFAMILY_ARM_HURRICANE"; #endif } - NSString * unknowCpuFamily = [NSString stringWithFormat:@"Unknown CPU family %d", cpufamily]; + NSString *unknowCpuFamily = [NSString stringWithFormat:@"Unknown CPU family %d", cpufamily]; [ADJAdjustFactory.logger warn:@"%@", unknowCpuFamily]; return unknowCpuFamily; } /* original function operatingSystemVersionString should not be parsed - https://developer.apple.com/reference/foundation/nsprocessinfo/1408730-operatingsystemversionstring?language=objc -+ (NSString*) osVersion -{ + https://developer.apple.com/reference/foundation/nsprocessinfo/1408730-operatingsystemversionstring?language=objc ++ (NSString*) osVersion { NSProcessInfo *info = [NSProcessInfo processInfo]; if (info == nil) { return nil; } + NSString *version = [info operatingSystemVersionString]; - if ([version hasPrefix:@"Version "]) { version = [version substringFromIndex:8]; } @@ -191,13 +187,13 @@ + (NSString*) osVersion return version; } */ -+ (int) cpuCount -{ + ++ (int)cpuCount { int error = 0; int value = 0; size_t length = sizeof(value); error = sysctlbyname("hw.ncpu", &value, &length, NULL, 0); - + if (error != 0) { [ADJAdjustFactory.logger error:@"Failed to obtain CPU count (%d)", error]; return 1; @@ -206,39 +202,32 @@ + (int) cpuCount return value; } -+ (NSString*) machineArch -{ ++ (NSString *)machineArch { return [ADJSystemProfile readSysctlbByNameString:"hw.machinearch" errorLog:@"Failed to obtain machine arch"]; } -+ (NSString*) machineModel -{ ++ (NSString *)machineModel { return [ADJSystemProfile readSysctlbByNameString:"hw.model" errorLog:@"Failed to obtain machine model"]; } -+ (NSString*) cpuBrand -{ ++ (NSString *)cpuBrand { return [ADJSystemProfile readSysctlbByNameString:"machdep.cpu.brand_string" errorLog:@"Failed to obtain CPU brand"]; } -+ (NSString*) cpuFeatures -{ ++ (NSString *)cpuFeatures { return [ADJSystemProfile readSysctlbByNameString:"machdep.cpu.features" errorLog:@"Failed to obtain CPU features"]; } -+ (NSString*) cpuVendor -{ ++ (NSString *)cpuVendor { return [ADJSystemProfile readSysctlbByNameString:"machdep.cpu.vendor" errorLog:@"Failed to obtain CPU vendor"]; } -+ (NSString*) osVersion -{ ++ (NSString *)osVersion { return [ADJSystemProfile readSysctlbByNameString:"kern.osversion" errorLog:@"Failed to obtain OS version"]; } -+ (NSString*) readSysctlbByNameString:(const char *)name - errorLog:(NSString*)errorLog -{ ++ (NSString *)readSysctlbByNameString:(const char*)name + errorLog:(NSString *)errorLog { int error = 0; size_t length = 0; error = sysctlbyname(name, NULL, &length, NULL, 0); @@ -259,16 +248,12 @@ + (NSString*) readSysctlbByNameString:(const char *)name return nil; } - NSString * result = [NSString stringWithUTF8String:p]; - + NSString *result = [NSString stringWithUTF8String:p]; free(p); - return result; - } -+ (NSString*) appleLanguage -{ ++ (NSString *)appleLanguage { NSUserDefaults *defs = [NSUserDefaults standardUserDefaults]; NSArray *languages = [defs objectForKey:@"AppleLanguages"]; @@ -276,84 +261,72 @@ + (NSString*) appleLanguage [ADJAdjustFactory.logger error:@"Failed to obtain preferred language"]; return nil; } - + return [languages objectAtIndex:0]; } -+ (long long) cpuSpeed -{ ++ (long long)cpuSpeed { long long result = 0; - int error = 0; - int64_t hertz = 0; size_t size = sizeof(hertz); int mib[2] = {CTL_HW, HW_CPU_FREQ}; error = sysctl(mib, 2, &hertz, &size, NULL, 0); - if (error) { [ADJAdjustFactory.logger error:@"Failed to obtain CPU speed (%d)", error]; return -1; } - - result = (long long)(hertz/1000000); // Convert to MHz - + + result = (long long)(hertz/1000000); // convert to MHz return result; } -+ (long long) ramsize -{ ++ (long long)ramsize { long long result = 0; - int error = 0; int64_t value = 0; size_t length = sizeof(value); - + error = sysctlbyname("hw.memsize", &value, &length, NULL, 0); if (error) { [ADJAdjustFactory.logger error:@"Failed to obtain RAM size (%d)", error]; return -1; } + const int64_t kBytesPerMebibyte = 1024*1024; result = (long long)(value/kBytesPerMebibyte); - return result; } -+ (NSString*) cpuType -{ ++ (NSString *)cpuType { int error = 0; - int cputype = -1; size_t length = sizeof(cputype); - error = sysctlbyname("hw.cputype", &cputype, &length, NULL, 0); + error = sysctlbyname("hw.cputype", &cputype, &length, NULL, 0); if (error != 0) { [ADJAdjustFactory.logger error:@"Failed to obtain CPU type (%d)", error]; return nil; } - NSString * cpuTypeString = [ADJSystemProfile readCpuTypeSubtype:cputype readSubType:NO cpusubtype:0]; - + NSString *cpuTypeString = [ADJSystemProfile readCpuTypeSubtype:cputype readSubType:NO cpusubtype:0]; if (cpuTypeString != nil) { return cpuTypeString; } - NSString * unknowCpuType = [NSString stringWithFormat:@"Unknown CPU type %d", cputype]; + NSString *unknowCpuType = [NSString stringWithFormat:@"Unknown CPU type %d", cputype]; [ADJAdjustFactory.logger warn:@"%@", unknowCpuType]; return unknowCpuType; } -+ (NSString*) cpuSubtype -{ ++ (NSString *)cpuSubtype { int error = 0; - int cputype = -1; size_t length = sizeof(cputype); - error = sysctlbyname("hw.cputype", &cputype, &length, NULL, 0); + error = sysctlbyname("hw.cputype", &cputype, &length, NULL, 0); if (error != 0) { [ADJAdjustFactory.logger error:@"Failed to obtain CPU type (%d)", error]; return nil; @@ -368,22 +341,19 @@ + (NSString*) cpuSubtype return nil; } - - NSString * cpuSubtypeString = [ADJSystemProfile readCpuTypeSubtype:cputype readSubType:YES cpusubtype:cpuSubtype]; - + NSString *cpuSubtypeString = [ADJSystemProfile readCpuTypeSubtype:cputype readSubType:YES cpusubtype:cpuSubtype]; if (cpuSubtypeString != nil) { return cpuSubtypeString; } - NSString * unknowCpuSubtype = [NSString stringWithFormat:@"Unknown CPU subtype %d", cpuSubtype]; + NSString *unknowCpuSubtype = [NSString stringWithFormat:@"Unknown CPU subtype %d", cpuSubtype]; [ADJAdjustFactory.logger warn:@"%@", unknowCpuSubtype]; return unknowCpuSubtype; } -+ (NSString*) readCpuTypeSubtype:(int)cputype ++ (NSString *)readCpuTypeSubtype:(int)cputype readSubType:(BOOL)readSubType - cpusubtype:(int)cpusubtype -{ + cpusubtype:(int)cpusubtype { switch (cputype) { #ifdef CPU_TYPE_ANY @@ -633,6 +603,10 @@ + (NSString*) readCpuTypeSubtype:(int)cputype #ifdef CPU_SUBTYPE_ARM64_V8 case CPU_SUBTYPE_ARM64_V8: return @"CPU_SUBTYPE_ARM64_V8"; +#endif +#ifdef CPU_SUBTYPE_ARM64E + case CPU_SUBTYPE_ARM64E: + return @"CPU_SUBTYPE_ARM64E"; #endif } break; @@ -678,6 +652,10 @@ + (NSString*) readCpuTypeSubtype:(int)cputype case CPU_SUBTYPE_ARM_V7K: return @"CPU_SUBTYPE_ARM_V7K"; #endif +#ifdef CPU_SUBTYPE_ARM_V8 + case CPU_SUBTYPE_ARM_V8: + return @"CPU_SUBTYPE_ARM_V8"; +#endif #ifdef CPU_SUBTYPE_ARM_V6M case CPU_SUBTYPE_ARM_V6M: return @"CPU_SUBTYPE_ARM_V6M"; @@ -690,9 +668,25 @@ + (NSString*) readCpuTypeSubtype:(int)cputype case CPU_SUBTYPE_ARM_V7EM: return @"CPU_SUBTYPE_ARM_V7EM"; #endif -#ifdef CPU_SUBTYPE_ARM_V8 - case CPU_SUBTYPE_ARM_V8: - return @"CPU_SUBTYPE_ARM_V8"; +#ifdef CPU_SUBTYPE_ARM_V8M + case CPU_SUBTYPE_ARM_V8M: + return @"CPU_SUBTYPE_ARM_V8M"; +#endif + } + break; +#endif +#ifdef CPU_TYPE_ARM64_32 + case CPU_TYPE_ARM64_32: + if (!readSubType) return @"CPU_TYPE_ARM64_32"; + switch (cpusubtype) + { +#ifdef CPU_SUBTYPE_ARM64_32_ALL + case CPU_SUBTYPE_ARM64_32_ALL: + return @"CPU_SUBTYPE_ARM64_32_ALL"; +#endif +#ifdef CPU_SUBTYPE_ARM64_32_V8 + case CPU_SUBTYPE_ARM64_32_V8: + return @"CPU_SUBTYPE_ARM64_32_V8"; #endif } break; @@ -815,4 +809,66 @@ + (NSString*) readCpuTypeSubtype:(int)cputype return nil; } ++ (NSUInteger)totalDiskSpace { + long long totalSpace = [[[[NSFileManager defaultManager] attributesOfFileSystemForPath:NSHomeDirectory() + error:nil] + objectForKey:NSFileSystemSize] longLongValue]; + NSUInteger totalSpaceMB = (NSUInteger)round((totalSpace * 1.0 / (1000 * 1000))); + return totalSpaceMB; +} + ++ (NSUInteger)freeDiskSpace { + long long freeSpace = [[[[NSFileManager defaultManager] attributesOfFileSystemForPath:NSHomeDirectory() + error:nil] + objectForKey:NSFileSystemFreeSize] longLongValue]; + NSUInteger freeSpaceMB = (NSUInteger)round((freeSpace * 1.0 / (1000 * 1000))); + return freeSpaceMB; +} + ++ (NSUInteger)batteryLevel { +#if TARGET_OS_TV + return 0; +#else + if (![[UIDevice currentDevice] isBatteryMonitoringEnabled]) { + [[UIDevice currentDevice] setBatteryMonitoringEnabled:YES]; + } + NSUInteger batteryLevel = (NSUInteger)(UIDevice.currentDevice.batteryLevel * 100); + return batteryLevel; +#endif +} + ++ (NSUInteger)chargingStatus { +#if TARGET_OS_TV + return 0; +#else + if (![[UIDevice currentDevice] isBatteryMonitoringEnabled]) { + [[UIDevice currentDevice] setBatteryMonitoringEnabled:YES]; + } + NSUInteger chargingStatus = (NSUInteger)UIDevice.currentDevice.batteryState; + return chargingStatus; +#endif +} + ++ (NSUInteger)systemUptime { + NSTimeInterval timeInterval = [[NSProcessInfo processInfo] systemUptime]; + NSUInteger seconds = (NSUInteger)round(timeInterval); + return seconds; +} + +// https://stackoverflow.com/a/10331716/1498352 ++ (NSUInteger)lastBootTime { + int MIB_SIZE = 2; + int mib[MIB_SIZE]; + size_t size; + struct timeval boottime; + mib[0] = CTL_KERN; + mib[1] = KERN_BOOTTIME; + size = sizeof(boottime); + if (sysctl(mib, MIB_SIZE, &boottime, &size, NULL, 0) != -1) { + NSDate *bootDate = [NSDate dateWithTimeIntervalSince1970:boottime.tv_sec]; + return (NSUInteger)round([bootDate timeIntervalSince1970]); + } + return 0; +} + @end diff --git a/Adjust/ADJTimerOnce.m b/Adjust/ADJTimerOnce.m index bfa4d8545..e6ea63e78 100644 --- a/Adjust/ADJTimerOnce.m +++ b/Adjust/ADJTimerOnce.m @@ -72,6 +72,15 @@ - (void)startIn:(NSTimeInterval)startIn { self.source = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, self.internalQueue); + if (!self.source) { + [self.logger error:@"%@ could not start witouth source", self.name]; + return; + } + if (!self.block) { + [self.logger error:@"%@ could not start witouth block", self.name]; + return; + } + dispatch_source_set_timer(self.source, dispatch_walltime(NULL, startIn * NSEC_PER_SEC), DISPATCH_TIME_FOREVER, diff --git a/Adjust/ADJUrlStrategy.h b/Adjust/ADJUrlStrategy.h new file mode 100644 index 000000000..146c9c66a --- /dev/null +++ b/Adjust/ADJUrlStrategy.h @@ -0,0 +1,24 @@ +// +// ADJUrlStrategy.h +// Adjust +// +// Created by Pedro S. on 11.08.20. +// Copyright © 2020 adjust GmbH. All rights reserved. +// + +#import +#import "ADJActivityKind.h" + +@interface ADJUrlStrategy : NSObject + +@property (nonatomic, readonly, copy) NSString *extraPath; + +- (instancetype)initWithUrlStrategyInfo:(NSString *)urlStrategyInfo + extraPath:(NSString *)extraPath; + +- (NSString *)getUrlHostStringByPackageKind:(ADJActivityKind)activityKind; + +- (void)resetAfterSuccess; +- (BOOL)shouldRetryAfterFailure; + +@end diff --git a/Adjust/ADJUrlStrategy.m b/Adjust/ADJUrlStrategy.m new file mode 100644 index 000000000..7fb65deda --- /dev/null +++ b/Adjust/ADJUrlStrategy.m @@ -0,0 +1,138 @@ +// +// ADJUrlStrategy.m +// Adjust +// +// Created by Pedro S. on 11.08.20. +// Copyright © 2020 adjust GmbH. All rights reserved. +// + +#import "ADJUrlStrategy.h" +#import "Adjust.h" +#import "ADJAdjustFactory.h" + +static NSString * const baseUrl = @"https://app.adjust.com"; +static NSString * const gdprUrl = @"https://gdpr.adjust.com"; +static NSString * const subscriptionUrl = @"https://subscription.adjust.com"; + +static NSString * const baseUrlIndia = @"https://app.adjust.net.in"; +static NSString * const gdprUrlIndia = @"https://gdpr.adjust.net.in"; +static NSString * const subscritionUrlIndia = @"https://subscription.adjust.net.in"; + +static NSString * const baseUrlChina = @"https://app.adjust.world"; +static NSString * const gdprUrlChina = @"https://gdpr.adjust.world"; +static NSString * const subscritionUrlChina = @"https://subscription.adjust.world"; + +@interface ADJUrlStrategy () + +@property (nonatomic, copy) NSArray *baseUrlChoicesArray; +@property (nonatomic, copy) NSArray *gdprUrlChoicesArray; +@property (nonatomic, copy) NSArray *subscriptionUrlChoicesArray; + +@property (nonatomic, copy) NSString *overridenBaseUrl; +@property (nonatomic, copy) NSString *overridenGdprUrl; +@property (nonatomic, copy) NSString *overridenSubscriptionUrl; + +@property (nonatomic, assign) BOOL wasLastAttemptSuccess; + +@property (nonatomic, assign) NSUInteger choiceIndex; +@property (nonatomic, assign) NSUInteger startingChoiceIndex; + +@end + +@implementation ADJUrlStrategy + +- (instancetype)initWithUrlStrategyInfo:(NSString *)urlStrategyInfo + extraPath:(NSString *)extraPath +{ + self = [super init]; + + _extraPath = extraPath ?: @""; + + _baseUrlChoicesArray = [ADJUrlStrategy baseUrlChoicesWithWithUrlStrategyInfo:urlStrategyInfo]; + _gdprUrlChoicesArray = [ADJUrlStrategy gdprUrlChoicesWithWithUrlStrategyInfo:urlStrategyInfo]; + _subscriptionUrlChoicesArray = [ADJUrlStrategy + subscriptionUrlChoicesWithWithUrlStrategyInfo:urlStrategyInfo]; + + _overridenBaseUrl = [ADJAdjustFactory baseUrl]; + _overridenGdprUrl = [ADJAdjustFactory gdprUrl]; + _overridenSubscriptionUrl = [ADJAdjustFactory subscriptionUrl]; + + _wasLastAttemptSuccess = NO; + + _choiceIndex = 0; + _startingChoiceIndex = 0; + + return self; +} + ++ (NSArray *)baseUrlChoicesWithWithUrlStrategyInfo:(NSString *)urlStrategyInfo +{ + if ([urlStrategyInfo isEqualToString:ADJUrlStrategyIndia]) { + return @[baseUrlIndia, baseUrl]; + } else if ([urlStrategyInfo isEqualToString:ADJUrlStrategyChina]) { + return @[baseUrlChina, baseUrl]; + } else { + return @[baseUrl, baseUrlIndia, baseUrlChina]; + } +} + ++ (NSArray *)gdprUrlChoicesWithWithUrlStrategyInfo:(NSString *)urlStrategyInfo +{ + if ([urlStrategyInfo isEqualToString:ADJUrlStrategyIndia]) { + return @[gdprUrlIndia, gdprUrl]; + } else if ([urlStrategyInfo isEqualToString:ADJUrlStrategyChina]) { + return @[gdprUrlChina, gdprUrl]; + } else { + return @[gdprUrl, gdprUrlIndia, gdprUrlChina]; + } +} + ++ (NSArray *)subscriptionUrlChoicesWithWithUrlStrategyInfo:(NSString *)urlStrategyInfo +{ + if ([urlStrategyInfo isEqualToString:ADJUrlStrategyIndia]) { + return @[subscritionUrlIndia, subscriptionUrl]; + } else if ([urlStrategyInfo isEqualToString:ADJUrlStrategyChina]) { + return @[subscritionUrlChina, subscriptionUrl]; + } else { + return @[subscriptionUrl, subscritionUrlIndia, subscritionUrlChina]; + } +} + +- (NSString *)getUrlHostStringByPackageKind:(ADJActivityKind)activityKind { + if (activityKind == ADJActivityKindGdpr) { + if (self.overridenGdprUrl != nil) { + return self.overridenGdprUrl; + } else { + return [self.gdprUrlChoicesArray objectAtIndex:self.choiceIndex]; + } + } else if (activityKind == ADJActivityKindSubscription) { + if (self.overridenSubscriptionUrl != nil) { + return self.overridenSubscriptionUrl; + } else { + return [self.subscriptionUrlChoicesArray objectAtIndex:self.choiceIndex]; + } + } else { + if (self.overridenBaseUrl != nil) { + return self.overridenBaseUrl; + } else { + return [self.baseUrlChoicesArray objectAtIndex:self.choiceIndex]; + } + } +} + +- (void)resetAfterSuccess { + self.startingChoiceIndex = self.choiceIndex; + self.wasLastAttemptSuccess = YES; +} + +- (BOOL)shouldRetryAfterFailure { + NSUInteger nextChoiceIndex = (self.choiceIndex + 1) % self.baseUrlChoicesArray.count; + self.choiceIndex = nextChoiceIndex; + + self.wasLastAttemptSuccess = NO; + + BOOL nextChoiceHasNotReturnedToStartingChoice = self.choiceIndex != self.startingChoiceIndex; + return nextChoiceHasNotReturnedToStartingChoice; +} + +@end diff --git a/Adjust/ADJUserDefaults.h b/Adjust/ADJUserDefaults.h index 300cb73d0..8849702f0 100644 --- a/Adjust/ADJUserDefaults.h +++ b/Adjust/ADJUserDefaults.h @@ -47,4 +47,8 @@ + (void)clearAdjustStuff; ++ (void)saveiAdErrorKey:(NSString *)key; ++ (NSDictionary *)getiAdErrors; ++ (void)cleariAdErrors; + @end diff --git a/Adjust/ADJUserDefaults.m b/Adjust/ADJUserDefaults.m index 97cb7e643..c28db5045 100644 --- a/Adjust/ADJUserDefaults.m +++ b/Adjust/ADJUserDefaults.m @@ -15,6 +15,7 @@ static NSString * const PREFS_KEY_DEEPLINK_URL = @"adj_deeplink_url"; static NSString * const PREFS_KEY_DEEPLINK_CLICK_TIME = @"adj_deeplink_click_time"; static NSString * const PREFS_KEY_DISABLE_THIRD_PARTY_SHARING = @"adj_disable_third_party_sharing"; +static NSString * const PREFS_KEY_IAD_ERRORS = @"adj_iad_errors"; @implementation ADJUserDefaults @@ -22,12 +23,10 @@ @implementation ADJUserDefaults + (void)savePushTokenData:(NSData *)pushToken { [[NSUserDefaults standardUserDefaults] setObject:pushToken forKey:PREFS_KEY_PUSH_TOKEN_DATA]; - [[NSUserDefaults standardUserDefaults] synchronize]; } + (void)savePushTokenString:(NSString *)pushToken { [[NSUserDefaults standardUserDefaults] setObject:pushToken forKey:PREFS_KEY_PUSH_TOKEN_STRING]; - [[NSUserDefaults standardUserDefaults] synchronize]; } + (NSData *)getPushTokenData { @@ -41,12 +40,10 @@ + (NSString *)getPushTokenString { + (void)removePushToken { [[NSUserDefaults standardUserDefaults] removeObjectForKey:PREFS_KEY_PUSH_TOKEN_DATA]; [[NSUserDefaults standardUserDefaults] removeObjectForKey:PREFS_KEY_PUSH_TOKEN_STRING]; - [[NSUserDefaults standardUserDefaults] synchronize]; } + (void)setInstallTracked { [[NSUserDefaults standardUserDefaults] setBool:YES forKey:PREFS_KEY_INSTALL_TRACKED]; - [[NSUserDefaults standardUserDefaults] synchronize]; } + (BOOL)getInstallTracked { @@ -55,7 +52,6 @@ + (BOOL)getInstallTracked { + (void)setGdprForgetMe { [[NSUserDefaults standardUserDefaults] setBool:YES forKey:PREFS_KEY_GDPR_FORGET_ME]; - [[NSUserDefaults standardUserDefaults] synchronize]; } + (BOOL)getGdprForgetMe { @@ -64,13 +60,11 @@ + (BOOL)getGdprForgetMe { + (void)removeGdprForgetMe { [[NSUserDefaults standardUserDefaults] removeObjectForKey:PREFS_KEY_GDPR_FORGET_ME]; - [[NSUserDefaults standardUserDefaults] synchronize]; } + (void)saveDeeplinkUrl:(NSURL *)deeplink andClickTime:(NSDate *)clickTime { [[NSUserDefaults standardUserDefaults] setURL:deeplink forKey:PREFS_KEY_DEEPLINK_URL]; [[NSUserDefaults standardUserDefaults] setObject:clickTime forKey:PREFS_KEY_DEEPLINK_CLICK_TIME]; - [[NSUserDefaults standardUserDefaults] synchronize]; } + (NSURL *)getDeeplinkUrl { @@ -84,12 +78,10 @@ + (NSDate *)getDeeplinkClickTime { + (void)removeDeeplink { [[NSUserDefaults standardUserDefaults] removeObjectForKey:PREFS_KEY_DEEPLINK_URL]; [[NSUserDefaults standardUserDefaults] removeObjectForKey:PREFS_KEY_DEEPLINK_CLICK_TIME]; - [[NSUserDefaults standardUserDefaults] synchronize]; } + (void)setDisableThirdPartySharing { [[NSUserDefaults standardUserDefaults] setBool:YES forKey:PREFS_KEY_DISABLE_THIRD_PARTY_SHARING]; - [[NSUserDefaults standardUserDefaults] synchronize]; } + (BOOL)getDisableThirdPartySharing { @@ -98,7 +90,34 @@ + (BOOL)getDisableThirdPartySharing { + (void)removeDisableThirdPartySharing { [[NSUserDefaults standardUserDefaults] removeObjectForKey:PREFS_KEY_DISABLE_THIRD_PARTY_SHARING]; - [[NSUserDefaults standardUserDefaults] synchronize]; +} + ++ (void)saveiAdErrorKey:(NSString *)key { + NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults]; + + NSMutableDictionary *errors = [[userDefaults dictionaryForKey:PREFS_KEY_IAD_ERRORS] mutableCopy]; + if (errors) { + NSNumber *value = errors[key]; + if (!value) { + value = @(1); + } else { + value = @([value integerValue] + 1); + } + + errors[key] = value; + } else { + errors[key] = @(1); + } + + [userDefaults setObject:errors forKey:PREFS_KEY_IAD_ERRORS]; +} + ++ (NSDictionary *)getiAdErrors { + return [[NSUserDefaults standardUserDefaults] dictionaryForKey:PREFS_KEY_IAD_ERRORS]; +} + ++ (void)cleariAdErrors { + [[NSUserDefaults standardUserDefaults] removeObjectForKey:PREFS_KEY_IAD_ERRORS]; } + (void)clearAdjustStuff { @@ -109,7 +128,6 @@ + (void)clearAdjustStuff { [[NSUserDefaults standardUserDefaults] removeObjectForKey:PREFS_KEY_DEEPLINK_URL]; [[NSUserDefaults standardUserDefaults] removeObjectForKey:PREFS_KEY_DEEPLINK_CLICK_TIME]; [[NSUserDefaults standardUserDefaults] removeObjectForKey:PREFS_KEY_DISABLE_THIRD_PARTY_SHARING]; - [[NSUserDefaults standardUserDefaults] synchronize]; } @end diff --git a/Adjust/ADJUtil.h b/Adjust/ADJUtil.h index dc5082c09..e4608a3cb 100644 --- a/Adjust/ADJUtil.h +++ b/Adjust/ADJUtil.h @@ -15,7 +15,11 @@ #import "ADJActivityPackage.h" #import "ADJBackoffStrategy.h" +// https://stackoverflow.com/a/5337804/1498352 +#define SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedAscending) + typedef void (^selfInjectedBlock)(id); +typedef void (^synchronisedBlock)(void); typedef void (^isInactiveInjected)(BOOL); @interface ADJUtil : NSObject @@ -24,7 +28,8 @@ typedef void (^isInactiveInjected)(BOOL); + (id)readObject:(NSString *)fileName objectName:(NSString *)objectName - class:(Class)classToRead; + class:(Class)classToRead + syncObject:(id)syncObject; + (void)excludeFromBackup:(NSString *)filename; @@ -42,7 +47,8 @@ typedef void (^isInactiveInjected)(BOOL); + (void)writeObject:(id)object fileName:(NSString *)fileName - objectName:(NSString *)objectName; + objectName:(NSString *)objectName + syncObject:(id)syncObject; + (void)launchInMainThread:(NSObject *)receiver selector:(SEL)selector @@ -52,18 +58,8 @@ typedef void (^isInactiveInjected)(BOOL); selfInject:(id)selfInject block:(selfInjectedBlock)block; -+ (void)sendGetRequest:(NSURL *)baseUrl - basePath:(NSString *)basePath - prefixErrorMessage:(NSString *)prefixErrorMessage - activityPackage:(ADJActivityPackage *)activityPackage - responseDataHandler:(void (^)(ADJResponseData *responseData))responseDataHandler; - -+ (void)sendPostRequest:(NSURL *)baseUrl - queueSize:(NSUInteger)queueSize - prefixErrorMessage:(NSString *)prefixErrorMessage - suffixErrorMessage:(NSString *)suffixErrorMessage - activityPackage:(ADJActivityPackage *)activityPackage - responseDataHandler:(void (^)(ADJResponseData *responseData))responseDataHandler; ++ (void)launchSynchronisedWithObject:(id)synchronisationObject + block:(synchronisedBlock)block; + (NSString *)idfa; @@ -81,6 +77,9 @@ typedef void (^isInactiveInjected)(BOOL); + (NSString *)queryString:(NSDictionary *)parameters; ++ (NSString *)queryString:(NSDictionary *)parameters + queueSize:(NSUInteger)queueSize; + + (NSString *)convertDeviceToken:(NSData *)deviceToken; + (BOOL)isNull:(id)value; @@ -97,10 +96,6 @@ typedef void (^isInactiveInjected)(BOOL); + (NSDictionary *)convertDictionaryValues:(NSDictionary *)dictionary; -+ (NSDictionary *)buildJsonDict:(NSData *)jsonData - exceptionPtr:(NSException **)exceptionPtr - errorPtr:(NSError **)error; - + (NSDictionary *)mergeParameters:(NSDictionary *)target source:(NSDictionary *)source parameterName:(NSString *)parameterName; @@ -116,12 +111,17 @@ typedef void (^isInactiveInjected)(BOOL); + (NSString *)sdkVersion; -#if !TARGET_OS_TV + (NSString *)readMCC; + (NSString *)readMNC; + (NSString *)readCurrentRadioAccessTechnology; -#endif + ++ (NSString *)stringToBinaryString:(NSString *)str; + ++ (NSString *)decimalToBinaryString:(NSUInteger)decInt; + ++ (NSString *)enforceParameterLength:(NSString *)parameter + withMaxlength:(int)maxLength; @end diff --git a/Adjust/ADJUtil.m b/Adjust/ADJUtil.m index 523ab3450..b383f60f0 100644 --- a/Adjust/ADJUtil.m +++ b/Adjust/ADJUtil.m @@ -19,13 +19,11 @@ #import "UIDevice+ADJAdditions.h" #import "NSString+ADJAdditions.h" -#if !TARGET_OS_TV +#if !TARGET_OS_TV && !TARGET_OS_MACCATALYST #import #import #endif -static const double kRequestTimeout = 60; // 60 seconds - static NSString *userAgent = nil; static ADJReachability *reachability = nil; static NSRegularExpression *universalLinkRegex = nil; @@ -33,14 +31,13 @@ static NSRegularExpression *optionalRedirectRegex = nil; static NSRegularExpression *shortUniversalLinkRegex = nil; static NSRegularExpression *excludedDeeplinkRegex = nil; -static NSURLSessionConfiguration *urlSessionConfiguration = nil; -#if !TARGET_OS_TV +#if !TARGET_OS_TV && !TARGET_OS_MACCATALYST static CTCarrier *carrier = nil; static CTTelephonyNetworkInfo *networkInfo = nil; #endif -static NSString * const kClientSdk = @"ios4.21.0"; +static NSString * const kClientSdk = @"ios4.23.0"; static NSString * const kDeeplinkParam = @"deep_link="; static NSString * const kSchemeDelimiter = @"://"; static NSString * const kDefaultScheme = @"AdjustUniversalScheme"; @@ -62,9 +59,8 @@ + (void)initialize { [self initializeShortUniversalLinkRegex]; [self initializeOptionalRedirectRegex]; [self initializeExcludedDeeplinkRegex]; - [self initializeUrlSessionConfiguration]; [self initializeReachability]; -#if !TARGET_OS_TV +#if !TARGET_OS_TV && !TARGET_OS_MACCATALYST [self initializeNetworkInfoAndCarrier]; #endif } @@ -75,8 +71,7 @@ + (void)teardown { secondsNumberFormatter = nil; optionalRedirectRegex = nil; shortUniversalLinkRegex = nil; - urlSessionConfiguration = nil; -#if !TARGET_OS_TV +#if !TARGET_OS_TV && !TARGET_OS_MACCATALYST networkInfo = nil; carrier = nil; #endif @@ -136,19 +131,7 @@ + (void)initializeSecondsNumberFormatter { [secondsNumberFormatter setPositiveFormat:@"0.0"]; } -+ (NSURLSessionConfiguration *)getUrlSessionConfiguration { - if (urlSessionConfiguration != nil) { - return urlSessionConfiguration; - } else { - return [NSURLSessionConfiguration defaultSessionConfiguration]; - } -} - -+ (void)initializeUrlSessionConfiguration { - urlSessionConfiguration = [NSURLSessionConfiguration defaultSessionConfiguration]; -} - -#if !TARGET_OS_TV +#if !TARGET_OS_TV && !TARGET_OS_MACCATALYST + (void)initializeNetworkInfoAndCarrier { networkInfo = [[CTTelephonyNetworkInfo alloc] init]; carrier = [networkInfo subscriberCellularProvider]; @@ -245,160 +228,131 @@ + (NSString *)formatDate:(NSDate *)value { return [dateFormatter stringFromDate:value]; } -+ (void)saveJsonResponse:(NSData *)jsonData responseData:(ADJResponseData *)responseData { - NSError *error = nil; - NSException *exception = nil; - NSDictionary *jsonDict = [ADJUtil buildJsonDict:jsonData exceptionPtr:&exception errorPtr:&error]; - - if (exception != nil) { - NSString *message = [NSString stringWithFormat:@"Failed to parse json response. (%@)", exception.description]; - [ADJAdjustFactory.logger error:message]; - responseData.message = message; - return; - } - if (error != nil) { - NSString *message = [NSString stringWithFormat:@"Failed to parse json response. (%@)", error.localizedDescription]; - [ADJAdjustFactory.logger error:message]; - responseData.message = message; - return; - } - - responseData.jsonResponse = jsonDict; -} - -+ (NSDictionary *)buildJsonDict:(NSData *)jsonData - exceptionPtr:(NSException **)exceptionPtr - errorPtr:(NSError **)error { - if (jsonData == nil) { - return nil; - } - - NSDictionary *jsonDict = nil; - @try { - jsonDict = [NSJSONSerialization JSONObjectWithData:jsonData options:0 error:error]; - } @catch (NSException *ex) { - *exceptionPtr = ex; - return nil; - } - return jsonDict; -} - + (id)readObject:(NSString *)fileName objectName:(NSString *)objectName - class:(Class)classToRead { - NSString *documentsFilePath = [ADJUtil getFilePathInDocumentsDir:fileName]; - NSString *appSupportFilePath = [ADJUtil getFilePathInAppSupportDir:fileName]; + class:(Class)classToRead + syncObject:(id)syncObject +{ + @synchronized(syncObject) { + NSString *documentsFilePath = [ADJUtil getFilePathInDocumentsDir:fileName]; + NSString *appSupportFilePath = [ADJUtil getFilePathInAppSupportDir:fileName]; + + // Try to read from Application Support directory first. + @try { + id appSupportObject; + if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"11.0")) { + NSData *data = [NSData dataWithContentsOfFile:appSupportFilePath]; + NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data]; + [unarchiver setRequiresSecureCoding:NO]; + appSupportObject = [unarchiver decodeObjectOfClass:classToRead forKey:NSKeyedArchiveRootObjectKey]; + } else { + appSupportObject = [NSKeyedUnarchiver unarchiveObjectWithFile:appSupportFilePath]; + } - // Try to read from Application Support directory first. - @try { - id appSupportObject; -#if !TARGET_OS_TV - if (@available(iOS 11.0, *)) { -#else - if (@available(tvOS 11.0, *)) { -#endif - NSData *data = [NSData dataWithContentsOfFile:appSupportFilePath]; - NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data]; - [unarchiver setRequiresSecureCoding:NO]; - appSupportObject = [unarchiver decodeObjectOfClass:classToRead forKey:NSKeyedArchiveRootObjectKey]; - } else { - appSupportObject = [NSKeyedUnarchiver unarchiveObjectWithFile:appSupportFilePath]; - } - - if (appSupportObject != nil) { - if ([appSupportObject isKindOfClass:classToRead]) { - // Successfully read object from Application Support folder, return it. - if ([appSupportObject isKindOfClass:[NSArray class]]) { - [[ADJAdjustFactory logger] debug:@"Package handler read %d packages", [appSupportObject count]]; - } else { - [[ADJAdjustFactory logger] debug:@"Read %@: %@", objectName, appSupportObject]; - } + if (appSupportObject != nil) { + if ([appSupportObject isKindOfClass:classToRead]) { + // Successfully read object from Application Support folder, return it. + if ([appSupportObject isKindOfClass:[NSArray class]]) { + [[ADJAdjustFactory logger] debug:@"Package handler read %d packages", [appSupportObject count]]; + } else { + [[ADJAdjustFactory logger] debug:@"Read %@: %@", objectName, appSupportObject]; + } - // Just in case check if old file exists in Documents folder and if yes, remove it. - [ADJUtil deleteFileInPath:documentsFilePath]; + // Just in case check if old file exists in Documents folder and if yes, remove it. + [ADJUtil deleteFileInPath:documentsFilePath]; - return appSupportObject; + return appSupportObject; + } + } else { + // [[ADJAdjustFactory logger] error:@"Failed to read %@ file", appSupportFilePath]; + [[ADJAdjustFactory logger] debug:@"File %@ not found in \"Application Support/Adjust\" folder", fileName]; } - } else { - // [[ADJAdjustFactory logger] error:@"Failed to read %@ file", appSupportFilePath]; - [[ADJAdjustFactory logger] debug:@"File %@ not found in \"Application Support/Adjust\" folder", fileName]; + } @catch (NSException *ex) { + // [[ADJAdjustFactory logger] error:@"Failed to read %@ file (%@)", appSupportFilePath, ex]; + [[ADJAdjustFactory logger] error:@"Failed to read %@ file from \"Application Support/Adjust\" folder (%@)", fileName, ex]; } - } @catch (NSException *ex) { - // [[ADJAdjustFactory logger] error:@"Failed to read %@ file (%@)", appSupportFilePath, ex]; - [[ADJAdjustFactory logger] error:@"Failed to read %@ file from \"Application Support/Adjust\" folder (%@)", fileName, ex]; - } - // If in here, for some reason, reading of file from Application Support folder failed. - // Let's check the Documents folder. - @try { - id documentsObject; -#if !TARGET_OS_TV - if (@available(iOS 11.0, *)) { -#else - if (@available(tvOS 11.0, *)) { -#endif - NSData *data = [NSData dataWithContentsOfFile:documentsFilePath]; - NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data]; - [unarchiver setRequiresSecureCoding:NO]; - documentsObject = [unarchiver decodeObjectOfClass:classToRead forKey:NSKeyedArchiveRootObjectKey]; - } else { - documentsObject = [NSKeyedUnarchiver unarchiveObjectWithFile:documentsFilePath]; - } - - if (documentsObject != nil) { - // Successfully read object from Documents folder. - if ([documentsObject isKindOfClass:[NSArray class]]) { - [[ADJAdjustFactory logger] debug:@"Package handler read %d packages", [documentsObject count]]; + // If in here, for some reason, reading of file from Application Support folder failed. + // Let's check the Documents folder. + @try { + id documentsObject; + if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"11.0")) { + NSData *data = [NSData dataWithContentsOfFile:documentsFilePath]; + NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data]; + [unarchiver setRequiresSecureCoding:NO]; + documentsObject = [unarchiver decodeObjectOfClass:classToRead forKey:NSKeyedArchiveRootObjectKey]; } else { - [[ADJAdjustFactory logger] debug:@"Read %@: %@", objectName, documentsObject]; + documentsObject = [NSKeyedUnarchiver unarchiveObjectWithFile:documentsFilePath]; } - // Do the file migration. - [[ADJAdjustFactory logger] verbose:@"Migrating %@ file from Documents to \"Application Support/Adjust\" folder", fileName]; - [ADJUtil migrateFileFromPath:documentsFilePath toPath:appSupportFilePath]; + if (documentsObject != nil) { + // Successfully read object from Documents folder. + if ([documentsObject isKindOfClass:[NSArray class]]) { + [[ADJAdjustFactory logger] debug:@"Package handler read %d packages", [documentsObject count]]; + } else { + [[ADJAdjustFactory logger] debug:@"Read %@: %@", objectName, documentsObject]; + } - return documentsObject; - } else { - // [[ADJAdjustFactory logger] error:@"Failed to read %@ file", documentsFilePath]; - [[ADJAdjustFactory logger] debug:@"File %@ not found in Documents folder", fileName]; + // Do the file migration. + [[ADJAdjustFactory logger] verbose:@"Migrating %@ file from Documents to \"Application Support/Adjust\" folder", fileName]; + [ADJUtil migrateFileFromPath:documentsFilePath toPath:appSupportFilePath]; + + return documentsObject; + } else { + // [[ADJAdjustFactory logger] error:@"Failed to read %@ file", documentsFilePath]; + [[ADJAdjustFactory logger] debug:@"File %@ not found in Documents folder", fileName]; + } + } @catch (NSException *ex) { + // [[ADJAdjustFactory logger] error:@"Failed to read %@ file (%@)", documentsFilePath, ex]; + [[ADJAdjustFactory logger] error:@"Failed to read %@ file from Documents folder (%@)", fileName, ex]; } - } @catch (NSException *ex) { - // [[ADJAdjustFactory logger] error:@"Failed to read %@ file (%@)", documentsFilePath, ex]; - [[ADJAdjustFactory logger] error:@"Failed to read %@ file from Documents folder (%@)", fileName, ex]; - } - return nil; + return nil; + } } + (void)writeObject:(id)object fileName:(NSString *)fileName - objectName:(NSString *)objectName { - BOOL result; - NSString *filePath = [ADJUtil getFilePathInAppSupportDir:fileName]; + objectName:(NSString *)objectName + syncObject:(id)syncObject { + @synchronized(syncObject) { + @try { + BOOL result; + NSString *filePath = [ADJUtil getFilePathInAppSupportDir:fileName]; + if (!filePath) { + [[ADJAdjustFactory logger] error:@"Cannot get filepath from filename: %@, to write %@ file", fileName, objectName]; + return; + } -#if !TARGET_OS_TV - if (@available(iOS 11.0, *)) { -#else - if (@available(tvOS 11.0, *)) { -#endif - NSError *errorArchiving = nil; - NSError *errorWriting = nil; - NSData *data = [NSKeyedArchiver archivedDataWithRootObject:object requiringSecureCoding:NO error:&errorArchiving]; - [data writeToFile:filePath options:NSDataWritingAtomic error:&errorWriting]; - result = (filePath != nil) && (errorArchiving == nil) && (errorWriting == nil); - } else { - result = (filePath != nil) && [NSKeyedArchiver archiveRootObject:object toFile:filePath]; - } - - if (result == YES) { - [ADJUtil excludeFromBackup:filePath]; - if ([object isKindOfClass:[NSArray class]]) { - [[ADJAdjustFactory logger] debug:@"Package handler wrote %d packages", [object count]]; - } else { - [[ADJAdjustFactory logger] debug:@"Wrote %@: %@", objectName, object]; + if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"11.0")) { + NSError *errorArchiving = nil; +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunguarded-availability" + NSData *data = [NSKeyedArchiver archivedDataWithRootObject:object requiringSecureCoding:NO error:&errorArchiving]; +#pragma clang diagnostic pop + if (data && errorArchiving == nil) { + NSError *errorWriting = nil; + result = [data writeToFile:filePath options:NSDataWritingAtomic error:&errorWriting]; + result = result && (errorWriting == nil); + } else { + result = NO; + } + } else { + result = [NSKeyedArchiver archiveRootObject:object toFile:filePath]; + } + if (result == YES) { + [ADJUtil excludeFromBackup:filePath]; + if ([object isKindOfClass:[NSArray class]]) { + [[ADJAdjustFactory logger] debug:@"Package handler wrote %d packages", [object count]]; + } else { + [[ADJAdjustFactory logger] debug:@"Wrote %@: %@", objectName, object]; + } + } else { + [[ADJAdjustFactory logger] error:@"Failed to write %@ file", objectName]; + } + } @catch (NSException *exception) { + [[ADJAdjustFactory logger] error:@"Failed to write %@ file (%@)", objectName, exception]; } - } else { - [[ADJAdjustFactory logger] error:@"Failed to write %@ file", objectName]; } } @@ -496,436 +450,20 @@ + (BOOL)isNotNull:(id)value { return value != nil && value != (id)[NSNull null]; } -+ (NSString *)formatErrorMessage:(NSString *)prefixErrorMessage - systemErrorMessage:(NSString *)systemErrorMessage - suffixErrorMessage:(NSString *)suffixErrorMessage { - NSString *errorMessage = [NSString stringWithFormat:@"%@ (%@)", prefixErrorMessage, systemErrorMessage]; - if (suffixErrorMessage == nil) { - return errorMessage; - } else { - return [errorMessage stringByAppendingFormat:@" %@", suffixErrorMessage]; - } -} - -+ (void)sendGetRequest:(NSURL *)baseUrl - basePath:(NSString *)basePath - prefixErrorMessage:(NSString *)prefixErrorMessage - activityPackage:(ADJActivityPackage *)activityPackage - responseDataHandler:(void (^)(ADJResponseData *responseData))responseDataHandler { - NSMutableDictionary *parametersCopy = [[NSMutableDictionary alloc] initWithCapacity:[activityPackage.parameters count]]; - [parametersCopy addEntriesFromDictionary:activityPackage.parameters]; - - [ADJUtil extractEventCallbackId:parametersCopy]; - - NSString * authorizationHeader = [ADJUtil buildAuthorizationHeader:parametersCopy activityKind:activityPackage.activityKind]; - - NSMutableURLRequest *request = [ADJUtil requestForGetPackage:activityPackage.path - clientSdk:activityPackage.clientSdk - parameters:parametersCopy - baseUrl:baseUrl - basePath:basePath]; - [ADJUtil sendRequest:request - prefixErrorMessage:prefixErrorMessage - activityPackage:activityPackage - authorizationHeader:authorizationHeader - responseDataHandler:responseDataHandler]; -} - -+ (void)sendRequest:(NSMutableURLRequest *)request - prefixErrorMessage:(NSString *)prefixErrorMessage - activityPackage:(ADJActivityPackage *)activityPackage -authorizationHeader:(NSString *)authorizationHeader -responseDataHandler:(void (^)(ADJResponseData *responseData))responseDataHandler { - [ADJUtil sendRequest:request - prefixErrorMessage:prefixErrorMessage - suffixErrorMessage:nil - authorizationHeader:authorizationHeader - activityPackage:activityPackage - responseDataHandler:responseDataHandler]; -} - -+ (void)sendPostRequest:(NSURL *)baseUrl - queueSize:(NSUInteger)queueSize - prefixErrorMessage:(NSString *)prefixErrorMessage - suffixErrorMessage:(NSString *)suffixErrorMessage - activityPackage:(ADJActivityPackage *)activityPackage - responseDataHandler:(void (^)(ADJResponseData *responseData))responseDataHandler -{ - NSMutableDictionary *parametersCopy = [[NSMutableDictionary alloc] initWithCapacity:[activityPackage.parameters count]]; - [parametersCopy addEntriesFromDictionary:activityPackage.parameters]; - - [ADJUtil extractEventCallbackId:parametersCopy]; - - NSString * authorizationHeader = [ADJUtil buildAuthorizationHeader:parametersCopy activityKind:activityPackage.activityKind]; - - NSMutableURLRequest *request = [ADJUtil requestForPostPackage:activityPackage.path - clientSdk:activityPackage.clientSdk - parameters:parametersCopy - baseUrl:baseUrl queueSize:queueSize]; - [ADJUtil sendRequest:request - prefixErrorMessage:prefixErrorMessage - suffixErrorMessage:suffixErrorMessage - authorizationHeader:authorizationHeader - activityPackage:activityPackage - responseDataHandler:responseDataHandler]; -} - -+ (void)sendRequest:(NSMutableURLRequest *)request - prefixErrorMessage:(NSString *)prefixErrorMessage - suffixErrorMessage:(NSString *)suffixErrorMessage -authorizationHeader:(NSString *)authorizationHeader - activityPackage:(ADJActivityPackage *)activityPackage -responseDataHandler:(void (^)(ADJResponseData *responseData))responseDataHandler -{ - if (authorizationHeader != nil) { - [ADJAdjustFactory.logger debug:@"authorizationHeader %@", authorizationHeader]; - [request setValue:authorizationHeader forHTTPHeaderField:@"Authorization"]; - } - if (userAgent != nil) { - [request setValue:userAgent forHTTPHeaderField:@"User-Agent"]; - } - - Class NSURLSessionClass = NSClassFromString(@"NSURLSession"); - if (NSURLSessionClass != nil) { - [ADJUtil sendNSURLSessionRequest:request - prefixErrorMessage:prefixErrorMessage - suffixErrorMessage:suffixErrorMessage - activityPackage:activityPackage - responseDataHandler:responseDataHandler]; - } else { - [ADJUtil sendNSURLConnectionRequest:request - prefixErrorMessage:prefixErrorMessage - suffixErrorMessage:suffixErrorMessage - activityPackage:activityPackage - responseDataHandler:responseDataHandler]; - } -} - -+ (NSString *)buildAuthorizationHeader:(NSMutableDictionary *)parameters - activityKind:(ADJActivityKind)activityKind -{ - NSString * secretId = [ADJUtil extractSecretId:parameters]; - NSString * signature = [ADJUtil extractSignature:parameters]; - NSString * headersId = [ADJUtil extractHeadersId:parameters]; - NSString * authorizationHeader = [ADJUtil buildAuthorizationHeaderV2:signature - secretId:secretId - headersId:headersId]; - if (authorizationHeader != nil) { - return authorizationHeader; - } - - NSString * appSecret = [ADJUtil extractAppSecret:parameters]; - return [ADJUtil buildAuthorizationHeaderV1:appSecret - secretId:secretId - parameters:parameters - activityKind:activityKind]; -} - -+ (NSString *)extractSecretId:(NSMutableDictionary *)parameters { - NSString *appSecret = [parameters objectForKey:@"secret_id"]; - if (appSecret == nil) { - return nil; - } - [parameters removeObjectForKey:@"secret_id"]; - return appSecret; -} - -+ (NSString *)extractSignature:(NSMutableDictionary *)parameters { - NSString *appSecret = [parameters objectForKey:@"signature"]; - if (appSecret == nil) { - return nil; - } - [parameters removeObjectForKey:@"signature"]; - return appSecret; -} - -+ (NSString *)extractHeadersId:(NSMutableDictionary *)parameters { - NSString *appSecret = [parameters objectForKey:@"headers_id"]; - if (appSecret == nil) { - return nil; - } - [parameters removeObjectForKey:@"headers_id"]; - return appSecret; -} - -+ (NSString *)extractAppSecret:(NSMutableDictionary *)parameters { - NSString *appSecret = [parameters objectForKey:@"app_secret"]; - if (appSecret == nil) { - return nil; - } - [parameters removeObjectForKey:@"app_secret"]; - return appSecret; -} - -+ (NSString *)buildAuthorizationHeaderV2:(NSString *)signature - secretId:(NSString*)secretId - headersId:(NSString*)headersId -{ - if (secretId == nil || signature == nil || headersId == nil) { - return nil; - } - NSString * signatureHeader = [NSString stringWithFormat:@"signature=\"%@\"", signature]; - NSString * secretIdHeader = [NSString stringWithFormat:@"secret_id=\"%@\"", secretId]; - NSString * idHeader = [NSString stringWithFormat:@"headers_id=\"%@\"", headersId]; - NSString * algorithmHeader = [NSString stringWithFormat:@"algorithm=\"adj1\""]; - NSString * authorizationHeader = [NSString stringWithFormat:@"Signature %@,%@,%@,%@", - signatureHeader, secretIdHeader, algorithmHeader, idHeader]; - return authorizationHeader; -} -+ (void)extractEventCallbackId:(NSMutableDictionary *)parameters { - NSString *eventCallbackId = [parameters objectForKey:@"event_callback_id"]; - if (eventCallbackId == nil) { - return; - } - [parameters removeObjectForKey:@"event_callback_id"]; -} -+ (NSMutableURLRequest *)requestForGetPackage:(NSString *)path - clientSdk:(NSString *)clientSdk - parameters:(NSDictionary *)parameters - baseUrl:(NSURL *)baseUrl - basePath:(NSString *)basePath { - NSString *queryStringParameters = [ADJUtil queryString:parameters]; - NSString *relativePath; - if (basePath != nil) { - relativePath = [NSString stringWithFormat:@"%@%@?%@", basePath, path, queryStringParameters]; - } else { - relativePath = [NSString stringWithFormat:@"%@?%@", path, queryStringParameters]; - } - NSURL *url = [NSURL URLWithString:relativePath relativeToURL:baseUrl]; - NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url]; - request.timeoutInterval = kRequestTimeout; - request.HTTPMethod = @"GET"; - [request setValue:clientSdk forHTTPHeaderField:@"Client-Sdk"]; - return request; -} -+ (NSMutableURLRequest *)requestForPostPackage:(NSString *)path - clientSdk:(NSString *)clientSdk - parameters:(NSDictionary *)parameters - baseUrl:(NSURL *)baseUrl - queueSize:(NSUInteger)queueSize { - NSURL *url = [baseUrl URLByAppendingPathComponent:path]; - NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url]; - request.timeoutInterval = kRequestTimeout; - request.HTTPMethod = @"POST"; - [request setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"]; - [request setValue:clientSdk forHTTPHeaderField:@"Client-Sdk"]; - - NSString *bodyString = [ADJUtil queryString:parameters queueSize:queueSize]; - NSData *body = [NSData dataWithBytes:bodyString.UTF8String length:bodyString.length]; - [request setHTTPBody:body]; - return request; -} -+ (NSString *)buildAuthorizationHeaderV1:(NSString *)appSecret - secretId:(NSString *)secretId - parameters:(NSMutableDictionary *)parameters - activityKind:(ADJActivityKind)activityKind -{ - if (appSecret == nil) { - return nil; - } - NSString *activityKindS = [ADJActivityKindUtil activityKindToString:activityKind]; - NSDictionary *signatureParameters = [ADJUtil buildSignatureParameters:parameters - appSecret:appSecret - activityKindS:activityKindS]; - NSMutableString *fields = [[NSMutableString alloc] initWithCapacity:5]; - NSMutableString *clearSignature = [[NSMutableString alloc] initWithCapacity:5]; - - // signature part of header - for (NSDictionary *key in signatureParameters) { - [fields appendFormat:@"%@ ", key]; - NSString *value = [signatureParameters objectForKey:key]; - [clearSignature appendString:value]; - } - - NSString *secretIdHeader = [NSString stringWithFormat:@"secret_id=\"%@\"", secretId]; - // algorithm part of header - NSString *algorithm = @"sha256"; - NSString *signature = [clearSignature adjSha256]; - NSString *signatureHeader = [NSString stringWithFormat:@"signature=\"%@\"", signature]; - NSString *algorithmHeader = [NSString stringWithFormat:@"algorithm=\"%@\"", algorithm]; - // fields part of header - // Remove last empty space. - if (fields.length > 0) { - [fields deleteCharactersInRange:NSMakeRange(fields.length - 1, 1)]; - } - - NSString *fieldsHeader = [NSString stringWithFormat:@"headers=\"%@\"", fields]; - // putting it all together - NSString *authorizationHeader = [NSString stringWithFormat:@"Signature %@,%@,%@,%@", - secretIdHeader, - signatureHeader, - algorithmHeader, - fieldsHeader]; - return authorizationHeader; -} -+ (NSDictionary *)buildSignatureParameters:(NSMutableDictionary *)parameters - appSecret:(NSString *)appSecret - activityKindS:(NSString *)activityKindS { - NSString *appSecretName = @"app_secret"; - NSString *sourceName = @"source"; - NSString *payloadName = @"payload"; - NSString *activityKindName = @"activity_kind"; - NSString *activityKindValue = activityKindS; - NSString *createdAtName = @"created_at"; - NSString *createdAtValue = [parameters objectForKey:createdAtName]; - NSString *deviceIdentifierName = [ADJUtil getValidIdentifier:parameters]; - NSString *deviceIdentifierValue = [parameters objectForKey:deviceIdentifierName]; - NSMutableDictionary *signatureParameters = [[NSMutableDictionary alloc] initWithCapacity:6]; - - [ADJUtil checkAndAddEntry:signatureParameters key:appSecretName value:appSecret]; - [ADJUtil checkAndAddEntry:signatureParameters key:createdAtName value:createdAtValue]; - [ADJUtil checkAndAddEntry:signatureParameters key:activityKindName value:activityKindValue]; - [ADJUtil checkAndAddEntry:signatureParameters key:deviceIdentifierName value:deviceIdentifierValue]; - [ADJUtil checkAndAddEntry:signatureParameters key:sourceName value:parameters[sourceName]]; - [ADJUtil checkAndAddEntry:signatureParameters key:payloadName value:parameters[payloadName]]; - - return signatureParameters; -} -+ (void)checkAndAddEntry:(NSMutableDictionary *)parameters - key:(NSString *)key - value:(NSString *)value { - if (key == nil) { - return; - } - if (value == nil) { - return; - } - [parameters setObject:value forKey:key]; -} -+ (NSString *)getValidIdentifier:(NSMutableDictionary *)parameters { - NSString *idfaName = @"idfa"; - NSString *persistentUUIDName = @"persistent_ios_uuid"; - NSString *uuidName = @"ios_uuid"; - - if ([parameters objectForKey:idfaName] != nil) { - return idfaName; - } - if ([parameters objectForKey:persistentUUIDName] != nil) { - return persistentUUIDName; - } - if ([parameters objectForKey:uuidName] != nil) { - return uuidName; - } - return nil; -} - -+ (void)sendNSURLSessionRequest:(NSMutableURLRequest *)request - prefixErrorMessage:(NSString *)prefixErrorMessage - suffixErrorMessage:(NSString *)suffixErrorMessage - activityPackage:(ADJActivityPackage *)activityPackage - responseDataHandler:(void (^)(ADJResponseData *responseData))responseDataHandler { - NSURLSession *session = [NSURLSession sessionWithConfiguration:[ADJUtil getUrlSessionConfiguration]]; - NSURLSessionDataTask *task = [session dataTaskWithRequest:request - completionHandler: - ^(NSData *data, NSURLResponse *response, NSError *error) { - ADJResponseData *responseData = [ADJUtil completionHandler:data - response:(NSHTTPURLResponse *)response - error:error - prefixErrorMessage:prefixErrorMessage - suffixErrorMessage:suffixErrorMessage - activityPackage:activityPackage]; - responseDataHandler(responseData); - }]; - [task resume]; - [session finishTasksAndInvalidate]; -} - -+ (void)sendNSURLConnectionRequest:(NSMutableURLRequest *)request - prefixErrorMessage:(NSString *)prefixErrorMessage - suffixErrorMessage:(NSString *)suffixErrorMessage - activityPackage:(ADJActivityPackage *)activityPackage - responseDataHandler:(void (^)(ADJResponseData *responseData))responseDataHandler { - NSError *responseError = nil; - NSHTTPURLResponse *urlResponse = nil; -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" - NSData *data = [NSURLConnection sendSynchronousRequest:request - returningResponse:&urlResponse - error:&responseError]; -#pragma clang diagnostic pop - ADJResponseData *responseData = [ADJUtil completionHandler:data - response:(NSHTTPURLResponse *)urlResponse - error:responseError - prefixErrorMessage:prefixErrorMessage - suffixErrorMessage:suffixErrorMessage - activityPackage:activityPackage]; - responseDataHandler(responseData); -} - -+ (ADJResponseData *)completionHandler:(NSData *)data - response:(NSHTTPURLResponse *)urlResponse - error:(NSError *)responseError - prefixErrorMessage:(NSString *)prefixErrorMessage - suffixErrorMessage:(NSString *)suffixErrorMessage - activityPackage:(ADJActivityPackage *)activityPackage { - ADJResponseData *responseData = [ADJResponseData buildResponseData:activityPackage]; - // Connection error - if (responseError != nil) { - NSString *errorMessage = [ADJUtil formatErrorMessage:prefixErrorMessage - systemErrorMessage:responseError.localizedDescription - suffixErrorMessage:suffixErrorMessage]; - [ADJAdjustFactory.logger error:errorMessage]; - responseData.message = errorMessage; - return responseData; - } - if ([ADJUtil isNull:data]) { - NSString *errorMessage = [ADJUtil formatErrorMessage:prefixErrorMessage - systemErrorMessage:@"empty error" - suffixErrorMessage:suffixErrorMessage]; - [ADJAdjustFactory.logger error:errorMessage]; - responseData.message = errorMessage; - return responseData; - } - - NSString *responseString = [[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] adjTrim]; - NSInteger statusCode = urlResponse.statusCode; - [ADJAdjustFactory.logger verbose:@"Response: %@", responseString]; - - if (statusCode == 429) { - [ADJAdjustFactory.logger error:@"Too frequent requests to the endpoint (429)"]; - return responseData; - } - [ADJUtil saveJsonResponse:data responseData:responseData]; - if ([ADJUtil isNull:responseData.jsonResponse]) { - return responseData; - } - - NSString *messageResponse = [responseData.jsonResponse objectForKey:@"message"]; - responseData.message = messageResponse; - responseData.timeStamp = [responseData.jsonResponse objectForKey:@"timestamp"]; - responseData.adid = [responseData.jsonResponse objectForKey:@"adid"]; - - NSString *trackingState = [responseData.jsonResponse objectForKey:@"tracking_state"]; - if (trackingState != nil) { - if ([trackingState isEqualToString:@"opted_out"]) { - responseData.trackingState = ADJTrackingStateOptedOut; - } - } - if (messageResponse == nil) { - messageResponse = @"No message found"; - } - if (statusCode == 200) { - [ADJAdjustFactory.logger info:@"%@", messageResponse]; - responseData.success = YES; - } else { - [ADJAdjustFactory.logger error:@"%@", messageResponse]; - } - return responseData; -} // Convert all values to strings, if value is dictionary -> recursive call + (NSDictionary *)convertDictionaryValues:(NSDictionary *)dictionary { @@ -1242,6 +780,13 @@ + (void)launchInQueue:(dispatch_queue_t)queue }); } ++ (void)launchSynchronisedWithObject:(id)synchronisationObject + block:(synchronisedBlock)block { + @synchronized (synchronisationObject) { + block(); + } +} + + (BOOL)deleteFileWithName:(NSString *)fileName { NSString *documentsFilePath = [ADJUtil getFilePathInDocumentsDir:fileName]; NSString *appSupportFilePath = [ADJUtil getFilePathInAppSupportDir:fileName]; @@ -1327,11 +872,11 @@ + (NSString *)convertDeviceToken:(NSData *)deviceToken { NSMutableString *hexString = [NSMutableString stringWithCapacity:(dataLength * 2)]; - for (int i = 0; i < dataLength; ++i) { + for (NSUInteger i = 0; i < dataLength; ++i) { [hexString appendString:[NSString stringWithFormat:@"%02lx", (unsigned long)dataBuffer[i]]]; } - return [NSString stringWithString:hexString]; + return [hexString copy]; } + (BOOL)checkAttributionDetails:(NSDictionary *)attributionDetails { @@ -1415,22 +960,32 @@ + (NSString *)sdkVersion { return kClientSdk; } -#if !TARGET_OS_TV + (NSString *)readMCC { +#if TARGET_OS_TV || TARGET_OS_MACCATALYST + return nil; +#else if (carrier == nil) { return nil; } return [carrier mobileCountryCode]; +#endif } + (NSString *)readMNC { +#if TARGET_OS_TV || TARGET_OS_MACCATALYST + return nil; +#else if (carrier == nil) { return nil; } return [carrier mobileNetworkCode]; +#endif } + (NSString *)readCurrentRadioAccessTechnology { +#if TARGET_OS_TV || TARGET_OS_MACCATALYST + return nil; +#else if (networkInfo == nil) { return nil; } @@ -1443,7 +998,70 @@ + (NSString *)readCurrentRadioAccessTechnology { id radioTech = [networkInfo performSelector:radioTechSelector]; #pragma clang diagnostic pop return radioTech; -} #endif +} + ++ (NSString *)stringToBinaryString:(NSString *)str { + if (str == nil) { + return nil; + } + NSMutableString *binStr = [[NSMutableString alloc] init]; + const char *cstr = [str UTF8String]; + size_t len = strlen(cstr); + for (size_t i = 0; i < len; i++) { + uint8_t c = cstr[i]; + for (int j = 0; j < 8; j++) { + [binStr appendString:((c & 0x80) ? @"1" : @"0")]; + c <<= 1; + } + } + return binStr; +} + ++ (NSString *)decimalToBinaryString:(NSUInteger)decInt { + if (decInt == 0) { + return @"0"; + } + NSString *string = @"" ; + NSUInteger x = decInt; + while (x > 0) { + string = [[NSString stringWithFormat: @"%lu", x&1] stringByAppendingString:string]; + x = x >> 1; + } + return string; +} + ++ (NSString *)enforceParameterLength:(NSString *)parameter + withMaxlength:(int)maxLength { + if (parameter == nil) { + // failed to read parameter + // fill in with zeros + NSString *failed = @""; + for (int i = 0; i < maxLength; i += 1) { + failed = [failed stringByAppendingString:@"0"]; + } + return failed; + } + if (parameter.length == maxLength) { + // all dandy + return parameter; + } + if (parameter.length > maxLength) { + // overflow + // in overflow case, fill parameter with all ones + NSString *stringOverflow = @""; + for (int i = 0; i < maxLength; i += 1) { + stringOverflow = [stringOverflow stringByAppendingString:@"1"]; + } + return stringOverflow; + } + // parameter too short + // expand it with prepended zeros to fit the protocol + NSString *expandedParameter = [NSString stringWithString:parameter]; + for (int i = 0; i < maxLength - parameter.length; i += 1) { + expandedParameter = [@"0" stringByAppendingString:expandedParameter]; + } + return expandedParameter; +} @end diff --git a/Adjust/Adjust.h b/Adjust/Adjust.h index bf1d1163d..4e1942597 100644 --- a/Adjust/Adjust.h +++ b/Adjust/Adjust.h @@ -2,7 +2,7 @@ // Adjust.h // Adjust // -// V4.21.0 +// V4.23.0 // Created by Christian Wellenbrock (wellle) on 23rd July 2013. // Copyright © 2012-2017 Adjust GmbH. All rights reserved. // @@ -10,13 +10,14 @@ #import "ADJEvent.h" #import "ADJConfig.h" #import "ADJAttribution.h" +#import "ADJSubscription.h" @interface AdjustTestOptions : NSObject @property (nonatomic, copy, nullable) NSString *baseUrl; @property (nonatomic, copy, nullable) NSString *gdprUrl; -@property (nonatomic, copy, nullable) NSString *basePath; -@property (nonatomic, copy, nullable) NSString *gdprPath; +@property (nonatomic, copy, nullable) NSString *subscriptionUrl; +@property (nonatomic, copy, nullable) NSString *extraPath; @property (nonatomic, copy, nullable) NSNumber *timerIntervalInMilliseconds; @property (nonatomic, copy, nullable) NSNumber *timerStartInMilliseconds; @property (nonatomic, copy, nullable) NSNumber *sessionIntervalInMilliseconds; @@ -58,6 +59,12 @@ extern NSString * __nonnull const ADJAdRevenueSourceUnityads; extern NSString * __nonnull const ADJAdRevenueSourceAdtoapp; extern NSString * __nonnull const ADJAdRevenueSourceTapdaq; +/** + * Constants for country apps url strategies. + */ +extern NSString * __nonnull const ADJUrlStrategyIndia; +extern NSString * __nonnull const ADJUrlStrategyChina; + /** * @brief The main interface to Adjust. * @@ -266,6 +273,15 @@ extern NSString * __nonnull const ADJAdRevenueSourceTapdaq; */ + (void)disableThirdPartySharing; +/** + * @brief Track subscription. + * + * @param subscription Subscription object. + */ ++ (void)trackSubscription:(nonnull ADJSubscription *)subscription; + ++ (void)requestTrackingAuthorizationWithCompletionHandler:(void (^_Nullable)(NSUInteger status))completion; + /** * Obtain singleton Adjust object. */ @@ -311,6 +327,8 @@ extern NSString * __nonnull const ADJAdRevenueSourceTapdaq; - (void)trackAdRevenue:(nonnull NSString *)source payload:(nonnull NSData *)payload; +- (void)trackSubscription:(nonnull ADJSubscription *)subscription; + - (BOOL)isEnabled; - (nullable NSString *)adid; @@ -323,4 +341,6 @@ extern NSString * __nonnull const ADJAdRevenueSourceTapdaq; - (nullable NSURL *)convertUniversalLink:(nonnull NSURL *)url scheme:(nonnull NSString *)scheme; +- (void)requestTrackingAuthorizationWithCompletionHandler:(void (^_Nullable)(NSUInteger status))completion; + @end diff --git a/Adjust/Adjust.m b/Adjust/Adjust.m index 0e0d01042..ce9b05071 100644 --- a/Adjust/Adjust.m +++ b/Adjust/Adjust.m @@ -12,6 +12,7 @@ #import "ADJUserDefaults.h" #import "ADJAdjustFactory.h" #import "ADJActivityHandler.h" +#import "UIDevice+ADJAdditions.h" #if !__has_feature(objc_arc) #error Adjust requires ARC @@ -40,6 +41,9 @@ NSString * const ADJAdRevenueSourceAdtoapp = @"adtoapp"; NSString * const ADJAdRevenueSourceTapdaq = @"tapdaq"; +NSString * const ADJUrlStrategyIndia = @"UrlStrategyIndia"; +NSString * const ADJUrlStrategyChina = @"UrlStrategyChina"; + @implementation AdjustTestOptions @end @@ -85,44 +89,64 @@ - (id)init { #pragma mark - Public static methods + (void)appDidLaunch:(ADJConfig *)adjustConfig { - [[Adjust getInstance] appDidLaunch:adjustConfig]; + @synchronized (self) { + [[Adjust getInstance] appDidLaunch:adjustConfig]; + } } + (void)trackEvent:(ADJEvent *)event { - [[Adjust getInstance] trackEvent:event]; + @synchronized (self) { + [[Adjust getInstance] trackEvent:event]; + } } + (void)trackSubsessionStart { - [[Adjust getInstance] trackSubsessionStart]; + @synchronized (self) { + [[Adjust getInstance] trackSubsessionStart]; + } } + (void)trackSubsessionEnd { - [[Adjust getInstance] trackSubsessionEnd]; + @synchronized (self) { + [[Adjust getInstance] trackSubsessionEnd]; + } } + (void)setEnabled:(BOOL)enabled { - Adjust *instance = [Adjust getInstance]; - [instance setEnabled:enabled]; + @synchronized (self) { + Adjust *instance = [Adjust getInstance]; + [instance setEnabled:enabled]; + } } + (BOOL)isEnabled { - return [[Adjust getInstance] isEnabled]; + @synchronized (self) { + return [[Adjust getInstance] isEnabled]; + } } + (void)appWillOpenUrl:(NSURL *)url { - [[Adjust getInstance] appWillOpenUrl:url]; + @synchronized (self) { + [[Adjust getInstance] appWillOpenUrl:[url copy]]; + } } + (void)setDeviceToken:(NSData *)deviceToken { - [[Adjust getInstance] setDeviceToken:deviceToken]; + @synchronized (self) { + [[Adjust getInstance] setDeviceToken:[deviceToken copy]]; + } } + (void)setPushToken:(NSString *)pushToken { - [[Adjust getInstance] setPushToken:pushToken]; + @synchronized (self) { + [[Adjust getInstance] setPushToken:[pushToken copy]]; + } } + (void)setOfflineMode:(BOOL)enabled { - [[Adjust getInstance] setOfflineMode:enabled]; + @synchronized (self) { + [[Adjust getInstance] setOfflineMode:enabled]; + } } + (void)sendAdWordsRequest { @@ -130,77 +154,120 @@ + (void)sendAdWordsRequest { } + (NSString *)idfa { - return [[Adjust getInstance] idfa]; + @synchronized (self) { + return [[Adjust getInstance] idfa]; + } } + (NSString *)sdkVersion { - return [[Adjust getInstance] sdkVersion]; + @synchronized (self) { + return [[Adjust getInstance] sdkVersion]; + } } + (NSURL *)convertUniversalLink:(NSURL *)url scheme:(NSString *)scheme { - return [[Adjust getInstance] convertUniversalLink:url scheme:scheme]; + @synchronized (self) { + return [[Adjust getInstance] convertUniversalLink:[url copy] scheme:[scheme copy]]; + } } + (void)sendFirstPackages { - [[Adjust getInstance] sendFirstPackages]; + @synchronized (self) { + [[Adjust getInstance] sendFirstPackages]; + } } + (void)addSessionCallbackParameter:(NSString *)key value:(NSString *)value { - [[Adjust getInstance] addSessionCallbackParameter:key value:value]; - + @synchronized (self) { + [[Adjust getInstance] addSessionCallbackParameter:[key copy] value:[value copy]]; + } } + (void)addSessionPartnerParameter:(NSString *)key value:(NSString *)value { - [[Adjust getInstance] addSessionPartnerParameter:key value:value]; + @synchronized (self) { + [[Adjust getInstance] addSessionPartnerParameter:[key copy] value:[value copy]]; + } } - + (void)removeSessionCallbackParameter:(NSString *)key { - [[Adjust getInstance] removeSessionCallbackParameter:key]; + @synchronized (self) { + [[Adjust getInstance] removeSessionCallbackParameter:[key copy]]; + } } + (void)removeSessionPartnerParameter:(NSString *)key { - [[Adjust getInstance] removeSessionPartnerParameter:key]; + @synchronized (self) { + [[Adjust getInstance] removeSessionPartnerParameter:[key copy]]; + } } + (void)resetSessionCallbackParameters { - [[Adjust getInstance] resetSessionCallbackParameters]; + @synchronized (self) { + [[Adjust getInstance] resetSessionCallbackParameters]; + } } + (void)resetSessionPartnerParameters { - [[Adjust getInstance] resetSessionPartnerParameters]; + @synchronized (self) { + [[Adjust getInstance] resetSessionPartnerParameters]; + } } + (void)gdprForgetMe { - [[Adjust getInstance] gdprForgetMe]; + @synchronized (self) { + [[Adjust getInstance] gdprForgetMe]; + } } + (void)trackAdRevenue:(nonnull NSString *)source payload:(nonnull NSData *)payload { - [[Adjust getInstance] trackAdRevenue:source payload:payload]; + @synchronized (self) { + [[Adjust getInstance] trackAdRevenue:[source copy] payload:[payload copy]]; + } } + (void)disableThirdPartySharing { - [[Adjust getInstance] disableThirdPartySharing]; + @synchronized (self) { + [[Adjust getInstance] disableThirdPartySharing]; + } +} + ++ (void)trackSubscription:(nonnull ADJSubscription *)subscription { + @synchronized (self) { + [[Adjust getInstance] trackSubscription:subscription]; + } +} + ++ (void)requestTrackingAuthorizationWithCompletionHandler:(void (^_Nullable)(NSUInteger status))completion +{ + @synchronized (self) { + [[Adjust getInstance] requestTrackingAuthorizationWithCompletionHandler:completion]; + } } + (ADJAttribution *)attribution { - return [[Adjust getInstance] attribution]; + @synchronized (self) { + return [[Adjust getInstance] attribution]; + } } + (NSString *)adid { - return [[Adjust getInstance] adid]; + @synchronized (self) { + return [[Adjust getInstance] adid]; + } } + (void)setTestOptions:(AdjustTestOptions *)testOptions { - if (testOptions.teardown) { - if (defaultInstance != nil) { - [defaultInstance teardown]; + @synchronized (self) { + if (testOptions.teardown) { + if (defaultInstance != nil) { + [defaultInstance teardown]; + } + defaultInstance = nil; + onceToken = 0; + [ADJAdjustFactory teardown:testOptions.deleteState]; } - defaultInstance = nil; - onceToken = 0; - [ADJAdjustFactory teardown:testOptions.deleteState]; + [[Adjust getInstance] setTestOptions:(AdjustTestOptions *)testOptions]; } - [[Adjust getInstance] setTestOptions:(AdjustTestOptions *)testOptions]; } #pragma mark - Public instance methods @@ -211,8 +278,9 @@ - (void)appDidLaunch:(ADJConfig *)adjustConfig { return; } - self.activityHandler = [ADJAdjustFactory activityHandlerWithConfig:adjustConfig - savedPreLaunch:self.savedPreLaunch]; + self.activityHandler = [[ADJActivityHandler alloc] + initWithConfig:adjustConfig + savedPreLaunch:self.savedPreLaunch]; } - (void)trackEvent:(ADJEvent *)event { @@ -430,6 +498,30 @@ - (void)disableThirdPartySharing { [self.activityHandler disableThirdPartySharing]; } +- (void)trackSubscription:(ADJSubscription *)subscription { + if (![self checkActivityHandler]) { + return; + } + + [self.activityHandler trackSubscription:subscription]; +} + +- (void)requestTrackingAuthorizationWithCompletionHandler:(void (^_Nullable)(NSUInteger status))completion +{ + [UIDevice.currentDevice requestTrackingAuthorizationWithCompletionHandler:^(NSUInteger status) + { + if (completion) { + completion(status); + } + + if (![self checkActivityHandler:@"request Tracking Authorization"]) { + return; + } + + [self.activityHandler updateAttStatusFromUserCallback:(int)status]; + }]; +} + - (ADJAttribution *)attribution { if (![self checkActivityHandler]) { return nil; @@ -461,11 +553,8 @@ - (void)teardown { } - (void)setTestOptions:(AdjustTestOptions *)testOptions { - if (testOptions.basePath != nil) { - self.savedPreLaunch.basePath = testOptions.basePath; - } - if (testOptions.gdprPath != nil) { - self.savedPreLaunch.gdprPath = testOptions.gdprPath; + if (testOptions.extraPath != nil) { + self.savedPreLaunch.extraPath = testOptions.extraPath; } if (testOptions.baseUrl != nil) { [ADJAdjustFactory setBaseUrl:testOptions.baseUrl]; @@ -473,6 +562,9 @@ - (void)setTestOptions:(AdjustTestOptions *)testOptions { if (testOptions.gdprUrl != nil) { [ADJAdjustFactory setGdprUrl:testOptions.gdprUrl]; } + if (testOptions.subscriptionUrl != nil) { + [ADJAdjustFactory setSubscriptionUrl:testOptions.subscriptionUrl]; + } if (testOptions.timerIntervalInMilliseconds != nil) { NSTimeInterval timerIntervalInSeconds = [testOptions.timerIntervalInMilliseconds intValue] / 1000.0; [ADJAdjustFactory setTimerInterval:timerIntervalInSeconds]; diff --git a/AdjustBridge/AdjustBridge.m b/AdjustBridge/AdjustBridge.m index fa25baf88..2d43705a1 100644 --- a/AdjustBridge/AdjustBridge.m +++ b/AdjustBridge/AdjustBridge.m @@ -191,6 +191,8 @@ - (void)loadWKWebViewBridge:(WKWebView *)wkWebView NSNumber *delayStart = [data objectForKey:@"delayStart"]; NSString *userAgent = [data objectForKey:@"userAgent"]; NSNumber *isDeviceKnown = [data objectForKey:@"isDeviceKnown"]; + NSNumber *allowiAdInfoReading = [data objectForKey:@"allowiAdInfoReading"]; + NSNumber *allowIdfaReading = [data objectForKey:@"allowIdfaReading"]; NSNumber *secretId = [data objectForKey:@"secretId"]; NSString *info1 = [data objectForKey:@"info1"]; NSString *info2 = [data objectForKey:@"info2"]; @@ -205,6 +207,7 @@ - (void)loadWKWebViewBridge:(WKWebView *)wkWebView NSString *sessionSuccessCallback = [data objectForKey:@"sessionSuccessCallback"]; NSString *sessionFailureCallback = [data objectForKey:@"sessionFailureCallback"]; NSString *deferredDeeplinkCallback = [data objectForKey:@"deferredDeeplinkCallback"]; + NSString *urlStrategy = [data objectForKey:@"urlStrategy"]; ADJConfig *adjustConfig; if ([self isFieldValid:allowSuppressLogLevel]) { @@ -245,6 +248,12 @@ - (void)loadWKWebViewBridge:(WKWebView *)wkWebView if ([self isFieldValid:isDeviceKnown]) { [adjustConfig setIsDeviceKnown:[isDeviceKnown boolValue]]; } + if ([self isFieldValid:allowiAdInfoReading]) { + [adjustConfig setAllowiAdInfoReading:[allowiAdInfoReading boolValue]]; + } + if ([self isFieldValid:allowIdfaReading]) { + [adjustConfig setAllowIdfaReading:[allowIdfaReading boolValue]]; + } BOOL isAppSecretDefined = [self isFieldValid:secretId] && [self isFieldValid:info1] && [self isFieldValid:info2] @@ -300,6 +309,9 @@ - (void)loadWKWebViewBridge:(WKWebView *)wkWebView || self.deferredDeeplinkCallbackName != nil) { [adjustConfig setDelegate:self]; } + if ([self isFieldValid:urlStrategy]) { + [adjustConfig setUrlStrategy:urlStrategy]; + } [Adjust appDidLaunch:adjustConfig]; [Adjust trackSubsessionStart]; @@ -478,8 +490,7 @@ - (void)loadWKWebViewBridge:(WKWebView *)wkWebView [self.bridgeRegister registerHandler:@"adjust_setTestOptions" handler:^(id data, WVJBResponseCallback responseCallback) { NSString *baseUrl = [data objectForKey:@"baseUrl"]; NSString *gdprUrl = [data objectForKey:@"gdprUrl"]; - NSString *basePath = [data objectForKey:@"basePath"]; - NSString *gdprPath = [data objectForKey:@"gdprPath"]; + NSString *extraPath = [data objectForKey:@"extraPath"]; NSNumber *timerIntervalInMilliseconds = [data objectForKey:@"timerIntervalInMilliseconds"]; NSNumber *timerStartInMilliseconds = [data objectForKey:@"timerStartInMilliseconds"]; NSNumber *sessionIntervalInMilliseconds = [data objectForKey:@"sessionIntervalInMilliseconds"]; @@ -497,11 +508,8 @@ - (void)loadWKWebViewBridge:(WKWebView *)wkWebView if ([self isFieldValid:gdprUrl]) { testOptions.gdprUrl = gdprUrl; } - if ([self isFieldValid:basePath]) { - testOptions.basePath = basePath; - } - if ([self isFieldValid:gdprPath]) { - testOptions.gdprPath = gdprPath; + if ([self isFieldValid:extraPath]) { + testOptions.extraPath = extraPath; } if ([self isFieldValid:timerIntervalInMilliseconds]) { testOptions.timerIntervalInMilliseconds = timerIntervalInMilliseconds; diff --git a/AdjustBridge/AdjustBridgeRegister.m b/AdjustBridge/AdjustBridgeRegister.m index 95f43cb68..becd67767 100644 --- a/AdjustBridge/AdjustBridgeRegister.m +++ b/AdjustBridge/AdjustBridgeRegister.m @@ -221,7 +221,7 @@ + (NSString *)adjust_js { if (this.sdkPrefix) { return this.sdkPrefix; } else { - return 'web-bridge4.21.0'; + return 'web-bridge4.23.0'; } }, setTestOptions: function(testOptions) { @@ -290,6 +290,8 @@ + (NSString *)adjust_js { this.delayStart = null; this.userAgent = null; this.isDeviceKnown = null; + this.allowiAdInfoReading = null; + this.allowIdfaReading = null; this.secretId = null; this.info1 = null; this.info2 = null; @@ -304,6 +306,7 @@ + (NSString *)adjust_js { this.sessionSuccessCallback = null; this.sessionFailureCallback = null; this.deferredDeeplinkCallback = null; + this.urlStrategy = null; }; AdjustConfig.EnvironmentSandbox = 'sandbox'; @@ -317,6 +320,9 @@ + (NSString *)adjust_js { AdjustConfig.LogLevelAssert = 'ASSERT'; AdjustConfig.LogLevelSuppress = 'SUPPRESS'; + AdjustConfig.UrlStrategyIndia = 'UrlStrategyIndia'; + AdjustConfig.UrlStrategyChina = 'UrlStrategyChina'; + AdjustConfig.prototype.registerCallbackHandlers = function() { var registerCallbackHandler = function(callbackName) { var callback = this[callbackName]; @@ -364,6 +370,12 @@ + (NSString *)adjust_js { AdjustConfig.prototype.setIsDeviceKnown = function(isDeviceKnown) { this.isDeviceKnown = isDeviceKnown; }; + AdjustConfig.prototype.setAllowiAdInfoReading = function(allowiAdInfoReading) { + this.allowiAdInfoReading = allowiAdInfoReading; + }; + AdjustConfig.prototype.setAllowIdfaReading = function(allowIdfaReading) { + this.allowIdfaReading = allowIdfaReading; + }; AdjustConfig.prototype.setAppSecret = function(secretId, info1, info2, info3, info4) { this.secretId = secretId; this.info1 = info1; @@ -399,6 +411,9 @@ + (NSString *)adjust_js { this.fbPixelMapping.push(fbEventNameKey); this.fbPixelMapping.push(adjEventTokenValue); }; + AdjustConfig.prototype.setUrlStrategy = function(urlStrategy) { + this.urlStrategy = urlStrategy; + }; })();); // END preprocessorJSCode //, augmentedSection]; diff --git a/AdjustSdk/AdjustSdk.h b/AdjustSdk/AdjustSdk.h index 405e288ec..7004b4f6a 100644 --- a/AdjustSdk/AdjustSdk.h +++ b/AdjustSdk/AdjustSdk.h @@ -21,6 +21,7 @@ FOUNDATION_EXPORT const unsigned char AdjustSdkVersionString[]; #import #import #import +#import #import #import #import diff --git a/AdjustSdkIm/AdjustSdkIm.h b/AdjustSdkIm/AdjustSdkIm.h index c0d84c2a3..38b59b571 100644 --- a/AdjustSdkIm/AdjustSdkIm.h +++ b/AdjustSdkIm/AdjustSdkIm.h @@ -21,6 +21,7 @@ FOUNDATION_EXPORT const unsigned char AdjustSdkImVersionString[]; #import #import #import +#import #import #import #import diff --git a/AdjustSdkTv/AdjustSdkTv.h b/AdjustSdkTv/AdjustSdkTv.h index bf083fa5a..31947ac54 100644 --- a/AdjustSdkTv/AdjustSdkTv.h +++ b/AdjustSdkTv/AdjustSdkTv.h @@ -21,6 +21,7 @@ FOUNDATION_EXPORT const unsigned char AdjustSdkTvVersionString[]; #import #import #import +#import #import #import #import diff --git a/AdjustSdkWebBridge/AdjustSdkWebBridge.h b/AdjustSdkWebBridge/AdjustSdkWebBridge.h index ccebc3f81..123b03d18 100644 --- a/AdjustSdkWebBridge/AdjustSdkWebBridge.h +++ b/AdjustSdkWebBridge/AdjustSdkWebBridge.h @@ -22,6 +22,7 @@ FOUNDATION_EXPORT const unsigned char AdjustSdkWebBridgeVersionString[]; #import #import #import +#import #import #import #import diff --git a/AdjustTests/AdjustTestApp/AdjustTestApp.xcodeproj/project.pbxproj b/AdjustTests/AdjustTestApp/AdjustTestApp.xcodeproj/project.pbxproj index fff02e305..1b8218cf1 100644 --- a/AdjustTests/AdjustTestApp/AdjustTestApp.xcodeproj/project.pbxproj +++ b/AdjustTests/AdjustTestApp/AdjustTestApp.xcodeproj/project.pbxproj @@ -61,6 +61,7 @@ 6F3A5EA12018CE3A000AACD0 /* ATLUtilNetworking.m in Sources */ = {isa = PBXBuildFile; fileRef = 6F3A5E9B2018CE3A000AACD0 /* ATLUtilNetworking.m */; }; 6F3A5EA22018CE3A000AACD0 /* ATLTestLibrary.m in Sources */ = {isa = PBXBuildFile; fileRef = 6F3A5E9C2018CE3A000AACD0 /* ATLTestLibrary.m */; }; 6F3A5EA32018CE3A000AACD0 /* ATLBlockingQueue.m in Sources */ = {isa = PBXBuildFile; fileRef = 6F3A5E9D2018CE3A000AACD0 /* ATLBlockingQueue.m */; }; + 6FBEE92024E421B200FEF3F1 /* ADJUrlStrategy.m in Sources */ = {isa = PBXBuildFile; fileRef = 6FBEE91F24E421B200FEF3F1 /* ADJUrlStrategy.m */; }; 6FFCFE5F2007978300467F01 /* ATAAdjustCommandExecutor.m in Sources */ = {isa = PBXBuildFile; fileRef = 6FFCFE5D2007978300467F01 /* ATAAdjustCommandExecutor.m */; }; 6FFCFE6D200797D100467F01 /* ATAAdjustDelegateAttribution.m in Sources */ = {isa = PBXBuildFile; fileRef = 6FFCFE61200797D000467F01 /* ATAAdjustDelegateAttribution.m */; }; 6FFCFE6E200797D100467F01 /* ATAAdjustDelegateEventFailure.m in Sources */ = {isa = PBXBuildFile; fileRef = 6FFCFE63200797D000467F01 /* ATAAdjustDelegateEventFailure.m */; }; @@ -71,6 +72,7 @@ 9D1D8E9E219246E50088E3CF /* iAd.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9D1D8E9D219246E50088E3CF /* iAd.framework */; }; 9D1D8EA0219246EA0088E3CF /* AdSupport.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9D1D8E9F219246EA0088E3CF /* AdSupport.framework */; }; 9D1D8EA2219246EF0088E3CF /* CoreTelephony.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9D1D8EA1219246EF0088E3CF /* CoreTelephony.framework */; }; + 9D2F24082447DDCB00B7CA90 /* ADJSubscription.m in Sources */ = {isa = PBXBuildFile; fileRef = 9D2F24072447DDCA00B7CA90 /* ADJSubscription.m */; }; 9D75AFDB210217FF0079A36C /* ATAAdjustDelegateDeferredDeeplink.m in Sources */ = {isa = PBXBuildFile; fileRef = 9D75AFDA210217FF0079A36C /* ATAAdjustDelegateDeferredDeeplink.m */; }; /* End PBXBuildFile section */ @@ -186,6 +188,8 @@ 6F3A5E9B2018CE3A000AACD0 /* ATLUtilNetworking.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ATLUtilNetworking.m; sourceTree = ""; }; 6F3A5E9C2018CE3A000AACD0 /* ATLTestLibrary.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ATLTestLibrary.m; sourceTree = ""; }; 6F3A5E9D2018CE3A000AACD0 /* ATLBlockingQueue.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ATLBlockingQueue.m; sourceTree = ""; }; + 6FBEE91E24E421B200FEF3F1 /* ADJUrlStrategy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ADJUrlStrategy.h; sourceTree = ""; }; + 6FBEE91F24E421B200FEF3F1 /* ADJUrlStrategy.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ADJUrlStrategy.m; sourceTree = ""; }; 6FFCFE5D2007978300467F01 /* ATAAdjustCommandExecutor.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ATAAdjustCommandExecutor.m; sourceTree = ""; }; 6FFCFE5E2007978300467F01 /* ATAAdjustCommandExecutor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ATAAdjustCommandExecutor.h; sourceTree = ""; }; 6FFCFE61200797D000467F01 /* ATAAdjustDelegateAttribution.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ATAAdjustDelegateAttribution.m; sourceTree = ""; }; @@ -203,6 +207,8 @@ 9D1D8E9D219246E50088E3CF /* iAd.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = iAd.framework; path = System/Library/Frameworks/iAd.framework; sourceTree = SDKROOT; }; 9D1D8E9F219246EA0088E3CF /* AdSupport.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AdSupport.framework; path = System/Library/Frameworks/AdSupport.framework; sourceTree = SDKROOT; }; 9D1D8EA1219246EF0088E3CF /* CoreTelephony.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreTelephony.framework; path = System/Library/Frameworks/CoreTelephony.framework; sourceTree = SDKROOT; }; + 9D2F24062447DDCA00B7CA90 /* ADJSubscription.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ADJSubscription.h; sourceTree = ""; }; + 9D2F24072447DDCA00B7CA90 /* ADJSubscription.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ADJSubscription.m; sourceTree = ""; }; 9D75AFD9210217FF0079A36C /* ATAAdjustDelegateDeferredDeeplink.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ATAAdjustDelegateDeferredDeeplink.h; sourceTree = ""; }; 9D75AFDA210217FF0079A36C /* ATAAdjustDelegateDeferredDeeplink.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ATAAdjustDelegateDeferredDeeplink.m; sourceTree = ""; }; /* End PBXFileReference section */ @@ -324,6 +330,10 @@ 6F3A5E6B2018CE14000AACD0 /* ADJTimerCycle.h */, 6F3A5E6C2018CE14000AACD0 /* ADJActivityHandler.m */, 6F3A5E6D2018CE14000AACD0 /* ADJReachability.m */, + 9D2F24062447DDCA00B7CA90 /* ADJSubscription.h */, + 9D2F24072447DDCA00B7CA90 /* ADJSubscription.m */, + 6FBEE91E24E421B200FEF3F1 /* ADJUrlStrategy.h */, + 6FBEE91F24E421B200FEF3F1 /* ADJUrlStrategy.m */, ); name = Adjust; path = ../../../Adjust; @@ -533,6 +543,7 @@ 6F3A5E842018CE14000AACD0 /* UIDevice+ADJAdditions.m in Sources */, 6F3A5EA12018CE3A000AACD0 /* ATLUtilNetworking.m in Sources */, 6F3A5E782018CE14000AACD0 /* ADJActivityState.m in Sources */, + 6FBEE92024E421B200FEF3F1 /* ADJUrlStrategy.m in Sources */, 6F3A5E8E2018CE14000AACD0 /* ADJActivityHandler.m in Sources */, 6F08422C2007769F00568A31 /* AppDelegate.m in Sources */, 524BACAA221C4EE800624F6C /* PSWebSocketUTF8Decoder.m in Sources */, @@ -542,6 +553,7 @@ 6F3A5E872018CE14000AACD0 /* ADJActivityPackage.m in Sources */, 6FFCFE71200797D100467F01 /* ATAAdjustDelegateEventSuccess.m in Sources */, 6F3A5E6F2018CE14000AACD0 /* ADJTimerOnce.m in Sources */, + 9D2F24082447DDCB00B7CA90 /* ADJSubscription.m in Sources */, 6FFCFE6F200797D100467F01 /* ATAAdjustDelegateSessionFailure.m in Sources */, 6F3A5E7D2018CE14000AACD0 /* ADJBackoffStrategy.m in Sources */, 6F3A5E8F2018CE14000AACD0 /* ADJReachability.m in Sources */, diff --git a/AdjustTests/AdjustTestApp/AdjustTestApp/ATAAdjustCommandExecutor.m b/AdjustTests/AdjustTestApp/AdjustTestApp/ATAAdjustCommandExecutor.m index 3fb6de374..bbacbef8a 100644 --- a/AdjustTests/AdjustTestApp/AdjustTestApp/ATAAdjustCommandExecutor.m +++ b/AdjustTests/AdjustTestApp/AdjustTestApp/ATAAdjustCommandExecutor.m @@ -20,8 +20,7 @@ @interface ATAAdjustCommandExecutor () -@property (nonatomic, copy) NSString *basePath; -@property (nonatomic, copy) NSString *gdprPath; +@property (nonatomic, copy) NSString *extraPath; @property (nonatomic, strong) NSMutableDictionary *savedConfigs; @property (nonatomic, strong) NSMutableDictionary *savedEvents; @property (nonatomic, strong) NSObject *adjustDelegate; @@ -40,8 +39,7 @@ - (id)init { self.savedConfigs = [NSMutableDictionary dictionary]; self.savedEvents = [NSMutableDictionary dictionary]; self.adjustDelegate = nil; - self.basePath = nil; - self.gdprPath = nil; + self.extraPath = nil; return self; } @@ -93,17 +91,19 @@ - (void)executeCommand:(NSString *)className [self trackAdRevenue:parameters]; } else if ([methodName isEqualToString:@"disableThirdPartySharing"]) { [self disableThirdPartySharing:parameters]; - } + } else if ([methodName isEqualToString:@"trackSubscription"]) { + [self trackSubscription:parameters]; + } } - (void)testOptions:(NSDictionary *)parameters { AdjustTestOptions *testOptions = [[AdjustTestOptions alloc] init]; testOptions.baseUrl = baseUrl; testOptions.gdprUrl = gdprUrl; + testOptions.subscriptionUrl = subscriptionUrl; if ([parameters objectForKey:@"basePath"]) { - self.basePath = [parameters objectForKey:@"basePath"][0]; - self.gdprPath = [parameters objectForKey:@"basePath"][0]; + self.extraPath = [parameters objectForKey:@"basePath"][0]; } if ([parameters objectForKey:@"timerInterval"]) { NSString *timerIntervalMilliS = [parameters objectForKey:@"timerInterval"][0]; @@ -155,8 +155,7 @@ - (void)testOptions:(NSDictionary *)parameters { NSString *teardownOption = teardownOptions[i]; if ([teardownOption isEqualToString:@"resetSdk"]) { testOptions.teardown = YES; - testOptions.basePath = self.basePath; - testOptions.gdprPath = self.gdprPath; + testOptions.extraPath = self.extraPath; } if ([teardownOption isEqualToString:@"deleteState"]) { testOptions.deleteState = YES; @@ -172,15 +171,13 @@ - (void)testOptions:(NSDictionary *)parameters { } if ([teardownOption isEqualToString:@"sdk"]) { testOptions.teardown = YES; - testOptions.basePath = nil; - testOptions.gdprPath = nil; + testOptions.extraPath = nil; } if ([teardownOption isEqualToString:@"test"]) { self.savedConfigs = nil; self.savedEvents = nil; self.adjustDelegate = nil; - self.basePath = nil; - self.gdprPath = nil; + self.extraPath = nil; testOptions.timerIntervalInMilliseconds = [NSNumber numberWithInt:-1000]; testOptions.timerStartInMilliseconds = [NSNumber numberWithInt:-1000]; testOptions.sessionIntervalInMilliseconds = [NSNumber numberWithInt:-1000]; @@ -311,40 +308,47 @@ - (void)config:(NSDictionary *)parameters { if ([parameters objectForKey:@"attributionCallbackSendAll"]) { NSLog(@"attributionCallbackSendAll detected"); - self.adjustDelegate = [[ATAAdjustDelegateAttribution alloc] initWithTestLibrary:self.testLibrary - andBasePath:self.basePath]; + self.adjustDelegate = + [[ATAAdjustDelegateAttribution alloc] initWithTestLibrary:self.testLibrary + andExtraPath:self.extraPath]; } if ([parameters objectForKey:@"sessionCallbackSendSuccess"]) { NSLog(@"sessionCallbackSendSuccess detected"); - self.adjustDelegate = [[ATAAdjustDelegateSessionSuccess alloc] initWithTestLibrary:self.testLibrary - andBasePath:self.basePath]; + self.adjustDelegate = + [[ATAAdjustDelegateSessionSuccess alloc] initWithTestLibrary:self.testLibrary + andExtraPath:self.extraPath]; } if ([parameters objectForKey:@"sessionCallbackSendFailure"]) { NSLog(@"sessionCallbackSendFailure detected"); - self.adjustDelegate = [[ATAAdjustDelegateSessionFailure alloc] initWithTestLibrary:self.testLibrary - andBasePath:self.basePath]; + self.adjustDelegate = + [[ATAAdjustDelegateSessionFailure alloc] initWithTestLibrary:self.testLibrary + andExtraPath:self.extraPath]; } if ([parameters objectForKey:@"eventCallbackSendSuccess"]) { NSLog(@"eventCallbackSendSuccess detected"); - self.adjustDelegate = [[ATAAdjustDelegateEventSuccess alloc] initWithTestLibrary:self.testLibrary - andBasePath:self.basePath]; + self.adjustDelegate = + [[ATAAdjustDelegateEventSuccess alloc] initWithTestLibrary:self.testLibrary + andExtraPath:self.extraPath]; } if ([parameters objectForKey:@"eventCallbackSendFailure"]) { NSLog(@"eventCallbackSendFailure detected"); - self.adjustDelegate = [[ATAAdjustDelegateEventFailure alloc] initWithTestLibrary:self.testLibrary - andBasePath:self.basePath]; + self.adjustDelegate = + [[ATAAdjustDelegateEventFailure alloc] initWithTestLibrary:self.testLibrary + andExtraPath:self.extraPath]; } if ([parameters objectForKey:@"deferredDeeplinkCallback"]) { NSLog(@"deferredDeeplinkCallback detected"); NSString *shouldOpenDeeplinkS = [parameters objectForKey:@"deferredDeeplinkCallback"][0]; - self.adjustDelegate = [[ATAAdjustDelegateDeferredDeeplink alloc] initWithTestLibrary:self.testLibrary - basePath:self.basePath - andReturnValue:[shouldOpenDeeplinkS boolValue]]; + self.adjustDelegate = + [[ATAAdjustDelegateDeferredDeeplink alloc] + initWithTestLibrary:self.testLibrary + extraPath:self.extraPath + andReturnValue:[shouldOpenDeeplinkS boolValue]]; } [adjustConfig setDelegate:self.adjustDelegate]; @@ -541,4 +545,60 @@ - (void)disableThirdPartySharing:(NSDictionary *)parameters { [Adjust disableThirdPartySharing]; } +- (void)trackSubscription:(NSDictionary *)parameters { + NSDecimalNumber *price; + NSString *currency; + NSString *transactionId; + NSData *receipt; + NSDate *transactionDate; + NSString *salesRegion; + + if ([parameters objectForKey:@"revenue"]) { + price = [[NSDecimalNumber alloc] initWithDouble:[[parameters objectForKey:@"revenue"][0] doubleValue]]; + } + if ([parameters objectForKey:@"currency"]) { + currency = [parameters objectForKey:@"currency"][0]; + } + if ([parameters objectForKey:@"transactionId"]) { + transactionId = [parameters objectForKey:@"transactionId"][0]; + } + if ([parameters objectForKey:@"receipt"]) { + NSString *receiptString = [parameters objectForKey:@"receipt"][0]; + receipt = [receiptString dataUsingEncoding:NSUTF8StringEncoding]; + } + if ([parameters objectForKey:@"transactionDate"]) { + transactionDate = [NSDate dateWithTimeIntervalSince1970:[[parameters objectForKey:@"transactionDate"][0] doubleValue]]; + } + if ([parameters objectForKey:@"salesRegion"]) { + salesRegion = [parameters objectForKey:@"salesRegion"][0]; + } + + ADJSubscription *subscription = [[ADJSubscription alloc] initWithPrice:price + currency:currency + transactionId:transactionId + andReceipt:receipt]; + [subscription setTransactionDate:transactionDate]; + [subscription setSalesRegion:salesRegion]; + + if ([parameters objectForKey:@"callbackParams"]) { + NSArray *callbackParams = [parameters objectForKey:@"callbackParams"]; + for (int i = 0; i < callbackParams.count; i = i + 2) { + NSString *key = callbackParams[i]; + NSString *value = callbackParams[i + 1]; + [subscription addCallbackParameter:key value:value]; + } + } + + if ([parameters objectForKey:@"partnerParams"]) { + NSArray *partnerParams = [parameters objectForKey:@"partnerParams"]; + for (int i = 0; i < partnerParams.count; i = i + 2) { + NSString *key = partnerParams[i]; + NSString *value = partnerParams[i + 1]; + [subscription addPartnerParameter:key value:value]; + } + } + + [Adjust trackSubscription:subscription]; +} + @end diff --git a/AdjustTests/AdjustTestApp/AdjustTestApp/Delegates/ATAAdjustDelegateAttribution.h b/AdjustTests/AdjustTestApp/AdjustTestApp/Delegates/ATAAdjustDelegateAttribution.h index 0aaf1f8bd..9512b5247 100644 --- a/AdjustTests/AdjustTestApp/AdjustTestApp/Delegates/ATAAdjustDelegateAttribution.h +++ b/AdjustTests/AdjustTestApp/AdjustTestApp/Delegates/ATAAdjustDelegateAttribution.h @@ -12,6 +12,6 @@ @interface ATAAdjustDelegateAttribution : NSObject -- (id)initWithTestLibrary:(ATLTestLibrary *)testLibrary andBasePath:(NSString *)basePath; +- (id)initWithTestLibrary:(ATLTestLibrary *)testLibrary andExtraPath:(NSString *)extraPath; @end diff --git a/AdjustTests/AdjustTestApp/AdjustTestApp/Delegates/ATAAdjustDelegateAttribution.m b/AdjustTests/AdjustTestApp/AdjustTestApp/Delegates/ATAAdjustDelegateAttribution.m index 745a528bb..2a4a24cde 100644 --- a/AdjustTests/AdjustTestApp/AdjustTestApp/Delegates/ATAAdjustDelegateAttribution.m +++ b/AdjustTests/AdjustTestApp/AdjustTestApp/Delegates/ATAAdjustDelegateAttribution.m @@ -11,13 +11,13 @@ @interface ATAAdjustDelegateAttribution () @property (nonatomic, strong) ATLTestLibrary *testLibrary; -@property (nonatomic, copy) NSString *basePath; +@property (nonatomic, copy) NSString *extraPath; @end @implementation ATAAdjustDelegateAttribution -- (id)initWithTestLibrary:(ATLTestLibrary *)testLibrary andBasePath:(NSString *)basePath { +- (id)initWithTestLibrary:(ATLTestLibrary *)testLibrary andExtraPath:(NSString *)extraPath { self = [super init]; if (nil == self) { @@ -25,7 +25,7 @@ - (id)initWithTestLibrary:(ATLTestLibrary *)testLibrary andBasePath:(NSString *) } self.testLibrary = testLibrary; - self.basePath = basePath; + self.extraPath = extraPath; return self; } @@ -43,7 +43,7 @@ - (void)adjustAttributionChanged:(ADJAttribution *)attribution { [self.testLibrary addInfoToSend:@"clickLabel" value:attribution.clickLabel]; [self.testLibrary addInfoToSend:@"adid" value:attribution.adid]; - [self.testLibrary sendInfoToServer:self.basePath]; + [self.testLibrary sendInfoToServer:self.extraPath]; } @end diff --git a/AdjustTests/AdjustTestApp/AdjustTestApp/Delegates/ATAAdjustDelegateDeferredDeeplink.h b/AdjustTests/AdjustTestApp/AdjustTestApp/Delegates/ATAAdjustDelegateDeferredDeeplink.h index 89e3683de..0316700dc 100644 --- a/AdjustTests/AdjustTestApp/AdjustTestApp/Delegates/ATAAdjustDelegateDeferredDeeplink.h +++ b/AdjustTests/AdjustTestApp/AdjustTestApp/Delegates/ATAAdjustDelegateDeferredDeeplink.h @@ -12,6 +12,6 @@ @interface ATAAdjustDelegateDeferredDeeplink : NSObject -- (id)initWithTestLibrary:(ATLTestLibrary *)testLibrary basePath:(NSString *)basePath andReturnValue:(BOOL)returnValue; +- (id)initWithTestLibrary:(ATLTestLibrary *)testLibrary extraPath:(NSString *)extraPath andReturnValue:(BOOL)returnValue; @end diff --git a/AdjustTests/AdjustTestApp/AdjustTestApp/Delegates/ATAAdjustDelegateDeferredDeeplink.m b/AdjustTests/AdjustTestApp/AdjustTestApp/Delegates/ATAAdjustDelegateDeferredDeeplink.m index 6e30364d5..43fc29e5a 100644 --- a/AdjustTests/AdjustTestApp/AdjustTestApp/Delegates/ATAAdjustDelegateDeferredDeeplink.m +++ b/AdjustTests/AdjustTestApp/AdjustTestApp/Delegates/ATAAdjustDelegateDeferredDeeplink.m @@ -11,14 +11,14 @@ @interface ATAAdjustDelegateDeferredDeeplink () @property (nonatomic, strong) ATLTestLibrary *testLibrary; -@property (nonatomic, copy) NSString *basePath; +@property (nonatomic, copy) NSString *extraPath; @property (nonatomic, assign) BOOL returnValue; @end @implementation ATAAdjustDelegateDeferredDeeplink -- (id)initWithTestLibrary:(ATLTestLibrary *)testLibrary basePath:(NSString *)basePath andReturnValue:(BOOL)returnValue { +- (id)initWithTestLibrary:(ATLTestLibrary *)testLibrary extraPath:(NSString *)extraPath andReturnValue:(BOOL)returnValue { self = [super init]; if (nil == self) { @@ -26,7 +26,7 @@ - (id)initWithTestLibrary:(ATLTestLibrary *)testLibrary basePath:(NSString *)bas } self.testLibrary = testLibrary; - self.basePath = basePath; + self.extraPath = extraPath; self.returnValue = returnValue; return self; @@ -37,7 +37,7 @@ - (BOOL)adjustDeeplinkResponse:(nullable NSURL *)deeplink { NSLog(@"Deep link: %@", deeplink); [self.testLibrary addInfoToSend:@"deeplink" value:[deeplink absoluteString]]; - [self.testLibrary sendInfoToServer:self.basePath]; + [self.testLibrary sendInfoToServer:self.extraPath]; return self.returnValue; } diff --git a/AdjustTests/AdjustTestApp/AdjustTestApp/Delegates/ATAAdjustDelegateEventFailure.h b/AdjustTests/AdjustTestApp/AdjustTestApp/Delegates/ATAAdjustDelegateEventFailure.h index 072a88c1a..5e5ee05b5 100644 --- a/AdjustTests/AdjustTestApp/AdjustTestApp/Delegates/ATAAdjustDelegateEventFailure.h +++ b/AdjustTests/AdjustTestApp/AdjustTestApp/Delegates/ATAAdjustDelegateEventFailure.h @@ -12,6 +12,6 @@ @interface ATAAdjustDelegateEventFailure : NSObject -- (id)initWithTestLibrary:(ATLTestLibrary *)testLibrary andBasePath:(NSString *)basePath; +- (id)initWithTestLibrary:(ATLTestLibrary *)testLibrary andExtraPath:(NSString *)extraPath; @end diff --git a/AdjustTests/AdjustTestApp/AdjustTestApp/Delegates/ATAAdjustDelegateEventFailure.m b/AdjustTests/AdjustTestApp/AdjustTestApp/Delegates/ATAAdjustDelegateEventFailure.m index 17ba3479f..313442736 100644 --- a/AdjustTests/AdjustTestApp/AdjustTestApp/Delegates/ATAAdjustDelegateEventFailure.m +++ b/AdjustTests/AdjustTestApp/AdjustTestApp/Delegates/ATAAdjustDelegateEventFailure.m @@ -11,13 +11,13 @@ @interface ATAAdjustDelegateEventFailure () @property (nonatomic, strong) ATLTestLibrary *testLibrary; -@property (nonatomic, copy) NSString *basePath; +@property (nonatomic, copy) NSString *extraPath; @end @implementation ATAAdjustDelegateEventFailure -- (id)initWithTestLibrary:(ATLTestLibrary *)testLibrary andBasePath:(NSString *)basePath { +- (id)initWithTestLibrary:(ATLTestLibrary *)testLibrary andExtraPath:(NSString *)extraPath { self = [super init]; if (nil == self) { @@ -25,7 +25,7 @@ - (id)initWithTestLibrary:(ATLTestLibrary *)testLibrary andBasePath:(NSString *) } self.testLibrary = testLibrary; - self.basePath = basePath; + self.extraPath = extraPath; return self; } @@ -53,7 +53,7 @@ - (void)adjustEventTrackingFailed:(ADJEventFailure *)eventFailureResponseData { [self.testLibrary addInfoToSend:@"jsonResponse" value:jsonString]; } - [self.testLibrary sendInfoToServer:self.basePath]; + [self.testLibrary sendInfoToServer:self.extraPath]; } @end diff --git a/AdjustTests/AdjustTestApp/AdjustTestApp/Delegates/ATAAdjustDelegateEventSuccess.h b/AdjustTests/AdjustTestApp/AdjustTestApp/Delegates/ATAAdjustDelegateEventSuccess.h index 129bbece5..19ab41717 100644 --- a/AdjustTests/AdjustTestApp/AdjustTestApp/Delegates/ATAAdjustDelegateEventSuccess.h +++ b/AdjustTests/AdjustTestApp/AdjustTestApp/Delegates/ATAAdjustDelegateEventSuccess.h @@ -12,6 +12,6 @@ @interface ATAAdjustDelegateEventSuccess : NSObject -- (id)initWithTestLibrary:(ATLTestLibrary *)testLibrary andBasePath:(NSString *)basePath; +- (id)initWithTestLibrary:(ATLTestLibrary *)testLibrary andExtraPath:(NSString *)extraPath; @end diff --git a/AdjustTests/AdjustTestApp/AdjustTestApp/Delegates/ATAAdjustDelegateEventSuccess.m b/AdjustTests/AdjustTestApp/AdjustTestApp/Delegates/ATAAdjustDelegateEventSuccess.m index 573eafce7..d71fadad2 100644 --- a/AdjustTests/AdjustTestApp/AdjustTestApp/Delegates/ATAAdjustDelegateEventSuccess.m +++ b/AdjustTests/AdjustTestApp/AdjustTestApp/Delegates/ATAAdjustDelegateEventSuccess.m @@ -11,13 +11,13 @@ @interface ATAAdjustDelegateEventSuccess () @property (nonatomic, strong) ATLTestLibrary *testLibrary; -@property (nonatomic, copy) NSString *basePath; +@property (nonatomic, copy) NSString *extraPath; @end @implementation ATAAdjustDelegateEventSuccess -- (id)initWithTestLibrary:(ATLTestLibrary *)testLibrary andBasePath:(NSString *)basePath { +- (id)initWithTestLibrary:(ATLTestLibrary *)testLibrary andExtraPath:(NSString *)extraPath { self = [super init]; if (nil == self) { @@ -25,7 +25,7 @@ - (id)initWithTestLibrary:(ATLTestLibrary *)testLibrary andBasePath:(NSString *) } self.testLibrary = testLibrary; - self.basePath = basePath; + self.extraPath = extraPath; return self; } @@ -52,7 +52,7 @@ - (void)adjustEventTrackingSucceeded:(ADJEventSuccess *)eventSuccessResponseData [self.testLibrary addInfoToSend:@"jsonResponse" value:jsonString]; } - [self.testLibrary sendInfoToServer:self.basePath]; + [self.testLibrary sendInfoToServer:self.extraPath]; } @end diff --git a/AdjustTests/AdjustTestApp/AdjustTestApp/Delegates/ATAAdjustDelegateSessionFailure.h b/AdjustTests/AdjustTestApp/AdjustTestApp/Delegates/ATAAdjustDelegateSessionFailure.h index 70f1e939b..a680fd3b2 100644 --- a/AdjustTests/AdjustTestApp/AdjustTestApp/Delegates/ATAAdjustDelegateSessionFailure.h +++ b/AdjustTests/AdjustTestApp/AdjustTestApp/Delegates/ATAAdjustDelegateSessionFailure.h @@ -12,6 +12,6 @@ @interface ATAAdjustDelegateSessionFailure : NSObject -- (id)initWithTestLibrary:(ATLTestLibrary *)testLibrary andBasePath:(NSString *)basePath; +- (id)initWithTestLibrary:(ATLTestLibrary *)testLibrary andExtraPath:(NSString *)extraPath; @end diff --git a/AdjustTests/AdjustTestApp/AdjustTestApp/Delegates/ATAAdjustDelegateSessionFailure.m b/AdjustTests/AdjustTestApp/AdjustTestApp/Delegates/ATAAdjustDelegateSessionFailure.m index e1008cc7e..3b59a2619 100644 --- a/AdjustTests/AdjustTestApp/AdjustTestApp/Delegates/ATAAdjustDelegateSessionFailure.m +++ b/AdjustTests/AdjustTestApp/AdjustTestApp/Delegates/ATAAdjustDelegateSessionFailure.m @@ -11,13 +11,13 @@ @interface ATAAdjustDelegateSessionFailure () @property (nonatomic, strong) ATLTestLibrary *testLibrary; -@property (nonatomic, copy) NSString *basePath; +@property (nonatomic, copy) NSString *extraPath; @end @implementation ATAAdjustDelegateSessionFailure -- (id)initWithTestLibrary:(ATLTestLibrary *)testLibrary andBasePath:(NSString *)basePath { +- (id)initWithTestLibrary:(ATLTestLibrary *)testLibrary andExtraPath:(NSString *)extraPath { self = [super init]; if (nil == self) { @@ -25,7 +25,7 @@ - (id)initWithTestLibrary:(ATLTestLibrary *)testLibrary andBasePath:(NSString *) } self.testLibrary = testLibrary; - self.basePath = basePath; + self.extraPath = extraPath; return self; } @@ -51,7 +51,7 @@ - (void)adjustSessionTrackingFailed:(ADJSessionFailure *)sessionFailureResponseD [self.testLibrary addInfoToSend:@"jsonResponse" value:jsonString]; } - [self.testLibrary sendInfoToServer:self.basePath]; + [self.testLibrary sendInfoToServer:self.extraPath]; } @end diff --git a/AdjustTests/AdjustTestApp/AdjustTestApp/Delegates/ATAAdjustDelegateSessionSuccess.h b/AdjustTests/AdjustTestApp/AdjustTestApp/Delegates/ATAAdjustDelegateSessionSuccess.h index 134d419b4..437650ac8 100644 --- a/AdjustTests/AdjustTestApp/AdjustTestApp/Delegates/ATAAdjustDelegateSessionSuccess.h +++ b/AdjustTests/AdjustTestApp/AdjustTestApp/Delegates/ATAAdjustDelegateSessionSuccess.h @@ -12,6 +12,6 @@ @interface ATAAdjustDelegateSessionSuccess : NSObject -- (id)initWithTestLibrary:(ATLTestLibrary *)testLibrary andBasePath:(NSString *)basePath; +- (id)initWithTestLibrary:(ATLTestLibrary *)testLibrary andExtraPath:(NSString *)extraPath; @end diff --git a/AdjustTests/AdjustTestApp/AdjustTestApp/Delegates/ATAAdjustDelegateSessionSuccess.m b/AdjustTests/AdjustTestApp/AdjustTestApp/Delegates/ATAAdjustDelegateSessionSuccess.m index ef7c717a4..7015a95fb 100644 --- a/AdjustTests/AdjustTestApp/AdjustTestApp/Delegates/ATAAdjustDelegateSessionSuccess.m +++ b/AdjustTests/AdjustTestApp/AdjustTestApp/Delegates/ATAAdjustDelegateSessionSuccess.m @@ -11,13 +11,13 @@ @interface ATAAdjustDelegateSessionSuccess () @property (nonatomic, strong) ATLTestLibrary *testLibrary; -@property (nonatomic, copy) NSString *basePath; +@property (nonatomic, copy) NSString *extraPath; @end @implementation ATAAdjustDelegateSessionSuccess -- (id)initWithTestLibrary:(ATLTestLibrary *)testLibrary andBasePath:(NSString *)basePath { +- (id)initWithTestLibrary:(ATLTestLibrary *)testLibrary andExtraPath:(NSString *)extraPath { self = [super init]; if (nil == self) { @@ -25,7 +25,7 @@ - (id)initWithTestLibrary:(ATLTestLibrary *)testLibrary andBasePath:(NSString *) } self.testLibrary = testLibrary; - self.basePath = basePath; + self.extraPath = extraPath; return self; } @@ -50,7 +50,7 @@ - (void)adjustSessionTrackingSucceeded:(ADJSessionSuccess *)sessionSuccessRespon [self.testLibrary addInfoToSend:@"jsonResponse" value:jsonString]; } - [self.testLibrary sendInfoToServer:self.basePath]; + [self.testLibrary sendInfoToServer:self.extraPath]; } @end diff --git a/AdjustTests/AdjustTestApp/AdjustTestApp/ViewController.h b/AdjustTests/AdjustTestApp/AdjustTestApp/ViewController.h index 08e568f54..8dcedac10 100644 --- a/AdjustTests/AdjustTestApp/AdjustTestApp/ViewController.h +++ b/AdjustTests/AdjustTestApp/AdjustTestApp/ViewController.h @@ -10,6 +10,7 @@ static NSString * baseUrl = @"http://127.0.0.1:8080"; static NSString * gdprUrl = @"http://127.0.0.1:8080"; +static NSString * subscriptionUrl = @"http://127.0.0.1:8080"; static NSString * controlUrl = @"ws://127.0.0.1:1987"; @interface ViewController : UIViewController diff --git a/AdjustTests/AdjustTestApp/AdjustTestApp/ViewController.m b/AdjustTests/AdjustTestApp/AdjustTestApp/ViewController.m index f42dc99cc..6b62c40cb 100644 --- a/AdjustTests/AdjustTestApp/AdjustTestApp/ViewController.m +++ b/AdjustTests/AdjustTestApp/AdjustTestApp/ViewController.m @@ -30,8 +30,8 @@ - (void)viewDidLoad { andCommandDelegate:self.adjustCommandExecutor]; [self.adjustCommandExecutor setTestLibrary:self.testLibrary]; - // [self.testLibrary addTestDirectory:@"current/third-party-sharing"]; - // [self.testLibrary addTest:@"Test_GdprForgetMe_after_install_kill_before_install"]; + //[self.testLibrary addTestDirectory:@"event-callbacks"]; + //[self.testLibrary addTest:@"Test_AdRevenue_ad_revenue"]; // [self.testLibrary doNotExitAfterEnd]; [self startTestSession]; diff --git a/AdjustTests/AdjustUnitTests/ADJPackageFields.m b/AdjustTests/AdjustUnitTests/ADJPackageFields.m index e134d5353..2d8019f28 100644 --- a/AdjustTests/AdjustUnitTests/ADJPackageFields.m +++ b/AdjustTests/AdjustUnitTests/ADJPackageFields.m @@ -16,7 +16,7 @@ - (id) init { // default values self.appToken = @"qwerty123456"; - self.clientSdk = @"ios4.21.0"; + self.clientSdk = @"ios4.23.0"; self.suffix = @""; self.environment = @"sandbox"; diff --git a/AdjustTests/AdjustWebBridgeTestApp/AdjustWebBridgeTestApp.xcodeproj/project.pbxproj b/AdjustTests/AdjustWebBridgeTestApp/AdjustWebBridgeTestApp.xcodeproj/project.pbxproj index 5a6a3867c..b38ff923f 100644 --- a/AdjustTests/AdjustWebBridgeTestApp/AdjustWebBridgeTestApp.xcodeproj/project.pbxproj +++ b/AdjustTests/AdjustWebBridgeTestApp/AdjustWebBridgeTestApp.xcodeproj/project.pbxproj @@ -70,6 +70,7 @@ 6F7AF790211888B500F730B2 /* TestLibraryBridge.m in Sources */ = {isa = PBXBuildFile; fileRef = 6F7AF78F211888B500F730B2 /* TestLibraryBridge.m */; }; 6F7AF7B02118949C00F730B2 /* TestLibraryBridge.js in Resources */ = {isa = PBXBuildFile; fileRef = 6F7AF7AF2118949C00F730B2 /* TestLibraryBridge.js */; }; 6F7AF7BB2118992200F730B2 /* WebKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6F7AF7BA2118992200F730B2 /* WebKit.framework */; }; + 6FBEE92324E421C800FEF3F1 /* ADJUrlStrategy.m in Sources */ = {isa = PBXBuildFile; fileRef = 6FBEE92224E421C800FEF3F1 /* ADJUrlStrategy.m */; }; 6FD0412C211C71D1008D42D0 /* iAd.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6FD0412B211C71D1008D42D0 /* iAd.framework */; }; 6FD0412E211C71D9008D42D0 /* AdSupport.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6FD0412D211C71D9008D42D0 /* AdSupport.framework */; }; 6FD04130211C71E8008D42D0 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6FD0412F211C71E8008D42D0 /* Foundation.framework */; }; @@ -202,6 +203,8 @@ 6F7AF78F211888B500F730B2 /* TestLibraryBridge.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TestLibraryBridge.m; sourceTree = ""; }; 6F7AF7AF2118949C00F730B2 /* TestLibraryBridge.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; path = TestLibraryBridge.js; sourceTree = ""; }; 6F7AF7BA2118992200F730B2 /* WebKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WebKit.framework; path = System/Library/Frameworks/WebKit.framework; sourceTree = SDKROOT; }; + 6FBEE92124E421C800FEF3F1 /* ADJUrlStrategy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ADJUrlStrategy.h; sourceTree = ""; }; + 6FBEE92224E421C800FEF3F1 /* ADJUrlStrategy.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ADJUrlStrategy.m; sourceTree = ""; }; 6FD0412B211C71D1008D42D0 /* iAd.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = iAd.framework; path = System/Library/Frameworks/iAd.framework; sourceTree = SDKROOT; }; 6FD0412D211C71D9008D42D0 /* AdSupport.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AdSupport.framework; path = System/Library/Frameworks/AdSupport.framework; sourceTree = SDKROOT; }; 6FD0412F211C71E8008D42D0 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; @@ -404,6 +407,8 @@ 6F7AF72E21187CFF00F730B2 /* ADJTimerCycle.h */, 6F7AF72F21187CFF00F730B2 /* ADJActivityHandler.m */, 6F7AF73021187CFF00F730B2 /* ADJReachability.m */, + 6FBEE92124E421C800FEF3F1 /* ADJUrlStrategy.h */, + 6FBEE92224E421C800FEF3F1 /* ADJUrlStrategy.m */, ); name = Adjust; path = ../../../Adjust; @@ -546,6 +551,7 @@ 6F7AF639211878BC00F730B2 /* main.m in Sources */, 6F7AF74121187CFF00F730B2 /* Adjust.m in Sources */, 6F6F75A223279D4D00F47E64 /* AdjustBridge.m in Sources */, + 6FBEE92324E421C800FEF3F1 /* ADJUrlStrategy.m in Sources */, 6F6F75D32327C08B00F47E64 /* PSWebSocketBuffer.m in Sources */, 6F7AF74821187CFF00F730B2 /* ADJAttribution.m in Sources */, 6F6F75D72327C08B00F47E64 /* ATLUtilNetworking.m in Sources */, diff --git a/AdjustTests/AdjustWebBridgeTestApp/AdjustWebBridgeTestApp.xcodeproj/xcshareddata/xcschemes/AdjustWebBridgeTestApp.xcscheme b/AdjustTests/AdjustWebBridgeTestApp/AdjustWebBridgeTestApp.xcodeproj/xcshareddata/xcschemes/AdjustWebBridgeTestApp.xcscheme index 5f563c310..23fec8b53 100644 --- a/AdjustTests/AdjustWebBridgeTestApp/AdjustWebBridgeTestApp.xcodeproj/xcshareddata/xcschemes/AdjustWebBridgeTestApp.xcscheme +++ b/AdjustTests/AdjustWebBridgeTestApp/AdjustWebBridgeTestApp.xcodeproj/xcshareddata/xcschemes/AdjustWebBridgeTestApp.xcscheme @@ -1,6 +1,6 @@ 4.21.0' +pod 'Adjust', '~> 4.23.0' ``` or: ```ruby -pod 'Adjust', :git => 'https://github.com/adjust/ios_sdk.git', :tag => 'v4.21.0' +pod 'Adjust', :git => 'https://github.com/adjust/ios_sdk.git', :tag => 'v4.23.0' ``` --- @@ -108,13 +112,13 @@ If you are having `iMessage` app, you can use the Adjust SDK with it as well wit ### Add iOS frameworks -1. Select your project in the Project Navigator -2. In the left-hand side of the main view, select your target -3. In the `Build Phases` tab, expand the `Link Binary with Libraries` group -4. At the bottom of that section, select the `+` button -5. Select the `AdSupport.framework`, then the `Add` button -6. Unless you are using tvOS, repeat the same steps to add the `iAd.framework` and `CoreTelephony.framework` -7. Change the `Status` of the frameworks to `Optional`. +Adjust SDK is able to get additional information in case you link additional iOS frameworks to your app. Please, add following frameworks in case you want to enable Adjust SDK features based on their presence in your app: + +- `AdSupport.framework` - This framework is needed so that SDK can access to IDFA value and (prior to iOS 14) LAT information. +- `iAd.framework` - This framework is needed so that SDK can automatically handle attribution for ASA campaings you might be running. +- `CoreTelephony.framework` - This framework is needed so that SDK can determine current radio access technology. +- `StoreKit.framework` - This framework is needed for access to `SKAdNetwork` framework and for Adjust SDK to handle communication with it automatically in iOS 14 or later. +- `AppTrackingTransparency.framework` - This framework is needed in iOS 14 and later for SDK to be able to wrap user's tracking consent dialog and access to value of the user's consent to be tracked or not. ### Integrate the SDK into your app @@ -278,6 +282,65 @@ Build and run your app. If the build succeeds, you should carefully read the SDK Once you integrate the Adjust SDK into your project, you can take advantage of the following features. +### AppTrackingTransparency framework + +For each package sent, the Adjust backend receives one of the following four (4) states of consent for access to app-related data that can be used for tracking the user or the device: + +- Authorized +- Denied +- Not Determined +- Restricted + +After a device receives an authorization request to approve access to app-related data, which is used for user device tracking, the returned status will either be Authorized or Denied. + +Before a device receives an authorization request for access to app-related data, which is used for tracking the user or device, the returned status will be Not Determined. + +If authorization to use app tracking data is restricted, the returned status will be Restricted. + +The SDK has a built-in mechanism to receive an updated status after a user responds to the pop-up dialog, in case you don't want to customize your displayed dialog pop-up. To conveniently and efficiently communicate the new state of consent to the backend, Adjust SDK offers a wrapper around the app tracking authorization method described in the following chapter, App-tracking authorization wrapper. + +### App-tracking authorisation wrapper + +Adjust SDK offers the possibility to use it for requesting user authorization in accessing their app-related data. Adjust SDK has a wrapper built on top of the [requestTrackingAuthorizationWithCompletionHandler:](https://developer.apple.com/documentation/apptrackingtransparency/attrackingmanager/3547037-requesttrackingauthorizationwith?language=objc) method, where you can as well define the callback method to get information about a user's choice. Also, with the use of this wrapper, as soon as a user responds to the pop-up dialog, it's then communicated back using your callback method. The SDK will also inform the backend of the user's choice. The `NSUInteger` value will be delivered via your callback method with the following meaning: + +- 0: `ATTrackingManagerAuthorizationStatusNotDetermined` +- 1: `ATTrackingManagerAuthorizationStatusRestricted` +- 2: `ATTrackingManagerAuthorizationStatusDenied` +- 3: `ATTrackingManagerAuthorizationStatusAuthorized` + +To use this wrapper, you can call it as such: + +```objc +[Adjust requestTrackingAuthorizationWithCompletionHandler:^(NSUInteger status) { + switch (status) { + case 0: + // ATTrackingManagerAuthorizationStatusNotDetermined case + break; + case 1: + // ATTrackingManagerAuthorizationStatusRestricted case + break; + case 2: + // ATTrackingManagerAuthorizationStatusDenied case + break; + case 3: + // ATTrackingManagerAuthorizationStatusAuthorized case + break; + } +}]; +``` + +### SKAdNetwork framework + +If you have implemented the Adjust iOS SDK v4.23.0 or above and your app is running on iOS 14, the communication with SKAdNetwork will be set on by default, although you can choose to turn it off. When set on, Adjust automatically registers for SKAdNetwork attribution when the SDK is initialized. If events are set up in the Adjust dashboard to receive conversion values, the Adjust backend sends the conversion value data to the SDK. The SDK then sets the conversion value. After Adjust receives the SKAdNetwork callback data, it is then displayed in the dashboard. + +Conversion values can optionally be attached to callback parameters during callbacks. + +In case you don't want the Adjust SDK to automatically communicate with SKAdNetwork, you can disable that by calling the following method on configuration object: + +```objc +[adjustConfig deactivateSKAdNetworkHandling]; +``` + ### Event tracking You can use adjust to track events. Lets say you want to track every tap on a particular button. You would create a new event token in your [dashboard], which has an associated event token - looking something like `abc123`. In your button's `buttonDown` method you would then add the following lines to track the tap: @@ -518,6 +581,57 @@ Currently we support the below `source` parameter values: - `ADJAdRevenueSourceMopub` - representing MoPub mediation platform (for more information, check [integration guide][sdk2sdk-mopub]) +### Subscription tracking + +**Note**: This feature is only available in the native SDK v4.22.0 and above. We recommend using at least version 4.22.1. + +**Important**: The following steps only set up subscription tracking within the SDK. To complete setup, certain app-specific information must be added within Adjust’s internal interface. An Adjust representative must take this action: please contact support@adjust.com or your Technical Account Manager. + +You can track App Store subscriptions and verify their validity with the Adjust SDK. After a subscription has been successfully purchased, make the following call to the Adjust SDK: + +```objc +ADJSubscription *subscription = [[ADJSubscription alloc] initWithPrice:price + currency:currency + transactionId:transactionId + andReceipt:receipt]; +[subscription setTransactionDate:transactionDate]; +[subscription setSalesRegion:salesRegion]; + +[Adjust trackSubscription:subscription]; +``` + +Only do this when the state has changed to `SKPaymentTransactionStatePurchased` or `SKPaymentTransactionStateRestored`. Then make a call to `finishTransaction` in `paymentQueue:updatedTransaction` . + +Subscription tracking parameters: + +- [price](https://developer.apple.com/documentation/storekit/skproduct/1506094-price?language=objc) +- currency (you need to pass [currencyCode](https://developer.apple.com/documentation/foundation/nslocale/1642836-currencycode?language=objc) of the [priceLocale](https://developer.apple.com/documentation/storekit/skproduct/1506145-pricelocale?language=objc) object) +- [transactionId](https://developer.apple.com/documentation/storekit/skpaymenttransaction/1411288-transactionidentifier?language=objc) +- [receipt](https://developer.apple.com/documentation/foundation/nsbundle/1407276-appstorereceipturl) +- [transactionDate](https://developer.apple.com/documentation/storekit/skpaymenttransaction/1411273-transactiondate?language=objc) +- salesRegion (you need to pass [countryCode](https://developer.apple.com/documentation/foundation/nslocale/1643060-countrycode?language=objc) of the [priceLocale](https://developer.apple.com/documentation/storekit/skproduct/1506145-pricelocale?language=objc) object) + +Just like with event tracking, you can attach callback and partner parameters to the subscription object as well: + +```objc +ADJSubscription *subscription = [[ADJSubscription alloc] initWithPrice:price + currency:currency + transactionId:transactionId + andReceipt:receipt]; +[subscription setTransactionDate:transactionDate]; +[subscription setSalesRegion:salesRegion]; + +// add callback parameters +[subscription addCallbackParameter:@"key" value:@"value"]; +[subscription addCallbackParameter:@"foo" value:@"bar"]; + +// add partner parameters +[subscription addPartnerParameter:@"key" value:@"value"]; +[subscription addPartnerParameter:@"foo" value:@"bar"]; + +[Adjust trackSubscription:subscription]; +``` + ### Event and session callbacks You can register a delegate callback to be notified of successful and failed tracked events and/or sessions. The same optional protocol `AdjustDelegate` used for the [attribution callback](#attribution-callback) is used. diff --git a/VERSION b/VERSION index 7c6be3171..58fe35227 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -4.21.0 +4.23.0 diff --git a/doc/chinese/README.md b/doc/chinese/README.md index 2d2ae8d36..92a5903b1 100644 --- a/doc/chinese/README.md +++ b/doc/chinese/README.md @@ -73,13 +73,13 @@ Read this in other languages: [English][en-readme], [中文][zh-readme], [日本 如果您正在使用[CocoaPods][cocoapods],您可以将以下代码行添加至 `Podfile`,然后继续进行[此步骤](#sdk-integrate): ```ruby -pod 'Adjust', '~> 4.21.0' +pod 'Adjust', '~> 4.23.0' ``` 或: ```ruby -pod 'Adjust', :git => 'https://github.com/adjust/ios_sdk.git', :tag => 'v4.21.0' +pod 'Adjust', :git => 'https://github.com/adjust/ios_sdk.git', :tag => 'v4.23.0' ``` --- diff --git a/doc/english/migrate.md b/doc/english/migrate.md index 34307476d..f7d8b442a 100644 --- a/doc/english/migrate.md +++ b/doc/english/migrate.md @@ -1,4 +1,4 @@ -## Migrate your adjust SDK for iOS to v4.21.0 from v3.4.0 +## Migrate your Adjust SDK for iOS to v4.23.0 from v3.4.0 ### Initial setup diff --git a/doc/english/web_views.md b/doc/english/web_views.md index 933b9aab1..a8328bae0 100644 --- a/doc/english/web_views.md +++ b/doc/english/web_views.md @@ -64,7 +64,7 @@ We will describe the steps to integrate the Adjust SDK into your iOS project. We If you're using [CocoaPods][cocoapods], you can add the following line to your `Podfile` and continue from [this step](#sdk-integrate): ```ruby -pod 'Adjust/WebBridge', '~> 4.21.0' +pod 'Adjust/WebBridge', '~> 4.23.0' ``` --- diff --git a/doc/japanese/README.md b/doc/japanese/README.md index 93711ca11..55ab8cf4f 100644 --- a/doc/japanese/README.md +++ b/doc/japanese/README.md @@ -25,13 +25,13 @@ adjust SDKをiOSプロジェクトに連携する手順を説明します。 [こちらの手順](#sdk-integrate)に進んでください。 ```ruby -pod 'Adjust', '~> 4.21.0' +pod 'Adjust', '~> 4.23.0' ``` または ```ruby -pod 'Adjust', :git => 'https://github.com/adjust/ios_sdk.git', :tag => 'v4.21.0' +pod 'Adjust', :git => 'https://github.com/adjust/ios_sdk.git', :tag => 'v4.23.0' ``` --- diff --git a/doc/korean/README.md b/doc/korean/README.md index e68cdc7a8..904b4b801 100644 --- a/doc/korean/README.md +++ b/doc/korean/README.md @@ -73,13 +73,13 @@ iOS 개발용 Xcode를 사용한다는 가정하에 iOS 프로젝트에 Adjust S [CocoaPods][cocoapods]를 사용하는 경우, 다음 내용을 `Podfile`에 추가한 후 [해당 단계](#sdk-integrate)를 완료하세요. ```ruby -pod 'Adjust', '~> 4.21.0' +pod 'Adjust', '~> 4.23.0' ``` 또는: ```ruby -pod 'Adjust', :git => 'https://github.com/adjust/ios_sdk.git', :tag => 'v4.21.0' +pod 'Adjust', :git => 'https://github.com/adjust/ios_sdk.git', :tag => 'v4.23.0' ``` --- diff --git a/doc/korean/web_views.md b/doc/korean/web_views.md index e6654672d..08cb05110 100644 --- a/doc/korean/web_views.md +++ b/doc/korean/web_views.md @@ -64,7 +64,7 @@ iOS 개발용 Xcode를 사용한다는 가정하에 iOS 프로젝트에 Adjust S [CocoaPods][cocoapods]를 사용하는 경우, 다음 내용을 'Podfile'에 추가한 후 [해당 단계](#sdk-integrate)를 완료하세요. ```ruby -pod 'Adjust/WebBridge', '~> 4.21.0' +pod 'Adjust/WebBridge', '~> 4.23.0' ``` --- @@ -109,7 +109,7 @@ Adjust SDK를 정적/동적 프레임 워크 또는 Carthage를 통해 추가 ### AdjustBridge를 앱에 연동하기 -프로젝트 네비게이터에서 소스 파일 View Controller를 엽니 다. 파일 맨 위에`import` 문구를 추가하십시오. 인도네시아 +프로젝트 네비게이터에서 소스 파일 View Controller를 엽니 다. 파일 맨 위에`import` 문구를 추가하십시오. Web View Delegate의`viewDidLoad` 또는`viewWillAppear` 메소드는`AdjustBridge`에 다음 호출을 추가합니다. ```objc diff --git a/doc/migrate.md b/doc/migrate.md index fc3809a80..f7d8b442a 100644 --- a/doc/migrate.md +++ b/doc/migrate.md @@ -1,4 +1,4 @@ -## Migrate your Adjust SDK for iOS to v4.21.0 from v3.4.0 +## Migrate your Adjust SDK for iOS to v4.23.0 from v3.4.0 ### Initial setup diff --git a/examples/AdjustExample-FbPixel/AdjustExample-FbPixel.xcodeproj/project.pbxproj b/examples/AdjustExample-FbPixel/AdjustExample-FbPixel.xcodeproj/project.pbxproj index 18beec1e0..5ab5c372c 100644 --- a/examples/AdjustExample-FbPixel/AdjustExample-FbPixel.xcodeproj/project.pbxproj +++ b/examples/AdjustExample-FbPixel/AdjustExample-FbPixel.xcodeproj/project.pbxproj @@ -7,6 +7,7 @@ objects = { /* Begin PBXBuildFile section */ + 6FBEE91D24E4219E00FEF3F1 /* ADJUrlStrategy.m in Sources */ = {isa = PBXBuildFile; fileRef = 6FBEE91B24E4219D00FEF3F1 /* ADJUrlStrategy.m */; }; 9D0F16A62193F96F00F5140E /* AdjustBridge.m in Sources */ = {isa = PBXBuildFile; fileRef = 9D0F16542193F96F00F5140E /* AdjustBridge.m */; }; 9D0F16A72193F96F00F5140E /* WebViewJavascriptBridgeBase.m in Sources */ = {isa = PBXBuildFile; fileRef = 9D0F16572193F96F00F5140E /* WebViewJavascriptBridgeBase.m */; }; 9D0F16A82193F96F00F5140E /* WKWebViewJavascriptBridge.m in Sources */ = {isa = PBXBuildFile; fileRef = 9D0F16582193F96F00F5140E /* WKWebViewJavascriptBridge.m */; }; @@ -46,6 +47,7 @@ 9D0F16CA2193F96F00F5140E /* ADJUserDefaults.m in Sources */ = {isa = PBXBuildFile; fileRef = 9D0F169E2193F96F00F5140E /* ADJUserDefaults.m */; }; 9D0F16CC2193F96F00F5140E /* ADJActivityHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = 9D0F16A42193F96F00F5140E /* ADJActivityHandler.m */; }; 9D0F16CD2193F96F00F5140E /* ADJReachability.m in Sources */ = {isa = PBXBuildFile; fileRef = 9D0F16A52193F96F00F5140E /* ADJReachability.m */; }; + 9D2F241D2447DE5A00B7CA90 /* ADJSubscription.m in Sources */ = {isa = PBXBuildFile; fileRef = 9D2F241B2447DE5A00B7CA90 /* ADJSubscription.m */; }; 9D9D1533212EB3920081445E /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 9D9D1532212EB3920081445E /* AppDelegate.m */; }; 9D9D1539212EB3920081445E /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 9D9D1537212EB3920081445E /* Main.storyboard */; }; 9D9D153B212EB3940081445E /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 9D9D153A212EB3940081445E /* Assets.xcassets */; }; @@ -60,6 +62,8 @@ /* End PBXBuildFile section */ /* Begin PBXFileReference section */ + 6FBEE91B24E4219D00FEF3F1 /* ADJUrlStrategy.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ADJUrlStrategy.m; path = ../../../Adjust/ADJUrlStrategy.m; sourceTree = ""; }; + 6FBEE91C24E4219E00FEF3F1 /* ADJUrlStrategy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ADJUrlStrategy.h; path = ../../../Adjust/ADJUrlStrategy.h; sourceTree = ""; }; 9D0F16542193F96F00F5140E /* AdjustBridge.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AdjustBridge.m; sourceTree = ""; }; 9D0F16552193F96F00F5140E /* AdjustBridgeRegister.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AdjustBridgeRegister.h; sourceTree = ""; }; 9D0F16572193F96F00F5140E /* WebViewJavascriptBridgeBase.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WebViewJavascriptBridgeBase.m; sourceTree = ""; }; @@ -139,6 +143,8 @@ 9D0F16A32193F96F00F5140E /* ADJTimerCycle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ADJTimerCycle.h; sourceTree = ""; }; 9D0F16A42193F96F00F5140E /* ADJActivityHandler.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ADJActivityHandler.m; sourceTree = ""; }; 9D0F16A52193F96F00F5140E /* ADJReachability.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ADJReachability.m; sourceTree = ""; }; + 9D2F241B2447DE5A00B7CA90 /* ADJSubscription.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ADJSubscription.m; sourceTree = ""; }; + 9D2F241C2447DE5A00B7CA90 /* ADJSubscription.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ADJSubscription.h; sourceTree = ""; }; 9D9D152E212EB3920081445E /* AdjustExample-FbPixel.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "AdjustExample-FbPixel.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 9D9D1531212EB3920081445E /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 9D9D1532212EB3920081445E /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; @@ -273,6 +279,10 @@ 9D0F16A32193F96F00F5140E /* ADJTimerCycle.h */, 9D0F16A42193F96F00F5140E /* ADJActivityHandler.m */, 9D0F16A52193F96F00F5140E /* ADJReachability.m */, + 9D2F241C2447DE5A00B7CA90 /* ADJSubscription.h */, + 9D2F241B2447DE5A00B7CA90 /* ADJSubscription.m */, + 6FBEE91C24E4219E00FEF3F1 /* ADJUrlStrategy.h */, + 6FBEE91B24E4219D00FEF3F1 /* ADJUrlStrategy.m */, ); name = Adjust; path = ../../../../Adjust; @@ -416,6 +426,7 @@ 9D0F16C12193F96F00F5140E /* NSData+ADJAdditions.m in Sources */, 9D0F16AF2193F96F00F5140E /* ADJRequestHandler.m in Sources */, 9D0F16B12193F96F00F5140E /* ADJSdkClickHandler.m in Sources */, + 6FBEE91D24E4219E00FEF3F1 /* ADJUrlStrategy.m in Sources */, 9D0F16C72193F96F00F5140E /* ADJAdjustFactory.m in Sources */, 9D0F16C42193F96F00F5140E /* ADJSystemProfile.m in Sources */, 9D0F16C32193F96F00F5140E /* ADJAttribution.m in Sources */, @@ -441,6 +452,7 @@ 9D0F16BE2193F96F00F5140E /* ADJPackageHandler.m in Sources */, 9D0F16B72193F96F00F5140E /* ADJSessionFailure.m in Sources */, 9D0F16C22193F96F00F5140E /* UIDevice+ADJAdditions.m in Sources */, + 9D2F241D2447DE5A00B7CA90 /* ADJSubscription.m in Sources */, 9D0F16B62193F96F00F5140E /* ADJActivityState.m in Sources */, 9D0F16CC2193F96F00F5140E /* ADJActivityHandler.m in Sources */, 9D0F16A72193F96F00F5140E /* WebViewJavascriptBridgeBase.m in Sources */, diff --git a/examples/AdjustExample-ObjC/AdjustExample-ObjC.xcodeproj/project.pbxproj b/examples/AdjustExample-ObjC/AdjustExample-ObjC.xcodeproj/project.pbxproj index d9f6ccff2..b0a0c0076 100644 --- a/examples/AdjustExample-ObjC/AdjustExample-ObjC.xcodeproj/project.pbxproj +++ b/examples/AdjustExample-ObjC/AdjustExample-ObjC.xcodeproj/project.pbxproj @@ -7,6 +7,7 @@ objects = { /* Begin PBXBuildFile section */ + 6FBEE90B24E420FA00FEF3F1 /* ADJUrlStrategy.m in Sources */ = {isa = PBXBuildFile; fileRef = 6FBEE90924E420FA00FEF3F1 /* ADJUrlStrategy.m */; }; 6FCC850C1F2794AB00D6A0ED /* ADJReachability.m in Sources */ = {isa = PBXBuildFile; fileRef = 6FCC850A1F2794A300D6A0ED /* ADJReachability.m */; }; 963909411BCBFCF300A2E8A4 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 963909401BCBFCF300A2E8A4 /* main.m */; }; 963909441BCBFCF300A2E8A4 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 963909431BCBFCF300A2E8A4 /* AppDelegate.m */; }; @@ -15,6 +16,7 @@ 9639094F1BCBFCF300A2E8A4 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 9639094D1BCBFCF300A2E8A4 /* LaunchScreen.storyboard */; }; 9639095F1BCBFD3B00A2E8A4 /* iAd.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9639095E1BCBFD3B00A2E8A4 /* iAd.framework */; settings = {ATTRIBUTES = (Weak, ); }; }; 963909611BCBFD4200A2E8A4 /* AdSupport.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 963909601BCBFD4200A2E8A4 /* AdSupport.framework */; settings = {ATTRIBUTES = (Weak, ); }; }; + 9D2F240B2447DDE100B7CA90 /* ADJSubscription.m in Sources */ = {isa = PBXBuildFile; fileRef = 9D2F240A2447DDE100B7CA90 /* ADJSubscription.m */; }; 9D449E131E6ED88F00E7E80B /* NSString+ADJAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = 9D449DD21E6ED88F00E7E80B /* NSString+ADJAdditions.m */; }; 9D449E141E6ED88F00E7E80B /* UIDevice+ADJAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = 9D449DD41E6ED88F00E7E80B /* UIDevice+ADJAdditions.m */; }; 9D449E151E6ED88F00E7E80B /* NSData+ADJAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = 9D449DD61E6ED88F00E7E80B /* NSData+ADJAdditions.m */; }; @@ -49,9 +51,12 @@ 9DC95F261C104CEF00138E4B /* ViewControllerObjC.m in Sources */ = {isa = PBXBuildFile; fileRef = 9DC95F251C104CEF00138E4B /* ViewControllerObjC.m */; }; 9DC95F2A1C10515300138E4B /* Constants.m in Sources */ = {isa = PBXBuildFile; fileRef = 9DC95F291C10515300138E4B /* Constants.m */; }; 9DD0E9BE1F457EF800B2A759 /* ADJUserDefaults.m in Sources */ = {isa = PBXBuildFile; fileRef = 9DD0E9BD1F457EF800B2A759 /* ADJUserDefaults.m */; }; + D799022C24C093AA00C7D11C /* AppTrackingTransparency.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D799022B24C093AA00C7D11C /* AppTrackingTransparency.framework */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ + 6FBEE90924E420FA00FEF3F1 /* ADJUrlStrategy.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ADJUrlStrategy.m; sourceTree = ""; }; + 6FBEE90A24E420FA00FEF3F1 /* ADJUrlStrategy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ADJUrlStrategy.h; sourceTree = ""; }; 6FCC850A1F2794A300D6A0ED /* ADJReachability.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ADJReachability.m; sourceTree = ""; }; 6FCC850B1F2794A300D6A0ED /* ADJReachability.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ADJReachability.h; sourceTree = ""; }; 9639093C1BCBFCF300A2E8A4 /* AdjustExample-ObjC.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "AdjustExample-ObjC.app"; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -65,6 +70,8 @@ 9639095E1BCBFD3B00A2E8A4 /* iAd.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = iAd.framework; path = System/Library/Frameworks/iAd.framework; sourceTree = SDKROOT; }; 963909601BCBFD4200A2E8A4 /* AdSupport.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AdSupport.framework; path = System/Library/Frameworks/AdSupport.framework; sourceTree = SDKROOT; }; 964E17FC1D50C6250097770B /* SafariServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SafariServices.framework; path = System/Library/Frameworks/SafariServices.framework; sourceTree = SDKROOT; }; + 9D2F24092447DDE100B7CA90 /* ADJSubscription.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ADJSubscription.h; sourceTree = ""; }; + 9D2F240A2447DDE100B7CA90 /* ADJSubscription.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ADJSubscription.m; sourceTree = ""; }; 9D449DD11E6ED88F00E7E80B /* NSString+ADJAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSString+ADJAdditions.h"; sourceTree = ""; }; 9D449DD21E6ED88F00E7E80B /* NSString+ADJAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSString+ADJAdditions.m"; sourceTree = ""; }; 9D449DD31E6ED88F00E7E80B /* UIDevice+ADJAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIDevice+ADJAdditions.h"; sourceTree = ""; }; @@ -134,6 +141,7 @@ 9DCA5CF01DD5B6BE000296B2 /* AdjustExample-ObjC.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = "AdjustExample-ObjC.entitlements"; sourceTree = ""; }; 9DD0E9BC1F457EF800B2A759 /* ADJUserDefaults.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ADJUserDefaults.h; sourceTree = ""; }; 9DD0E9BD1F457EF800B2A759 /* ADJUserDefaults.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ADJUserDefaults.m; sourceTree = ""; }; + D799022B24C093AA00C7D11C /* AppTrackingTransparency.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppTrackingTransparency.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.16.sdk/System/Library/Frameworks/AppTrackingTransparency.framework; sourceTree = DEVELOPER_DIR; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -141,6 +149,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + D799022C24C093AA00C7D11C /* AppTrackingTransparency.framework in Frameworks */, 9639095F1BCBFD3B00A2E8A4 /* iAd.framework in Frameworks */, 963909611BCBFD4200A2E8A4 /* AdSupport.framework in Frameworks */, ); @@ -154,6 +163,7 @@ children = ( 9639093E1BCBFCF300A2E8A4 /* AdjustExample-ObjC */, 9639093D1BCBFCF300A2E8A4 /* Products */, + D799022A24C093AA00C7D11C /* Frameworks */, ); sourceTree = ""; }; @@ -271,6 +281,10 @@ 6FCC850A1F2794A300D6A0ED /* ADJReachability.m */, 9DD0E9BC1F457EF800B2A759 /* ADJUserDefaults.h */, 9DD0E9BD1F457EF800B2A759 /* ADJUserDefaults.m */, + 9D2F24092447DDE100B7CA90 /* ADJSubscription.h */, + 9D2F240A2447DDE100B7CA90 /* ADJSubscription.m */, + 6FBEE90A24E420FA00FEF3F1 /* ADJUrlStrategy.h */, + 6FBEE90924E420FA00FEF3F1 /* ADJUrlStrategy.m */, ); name = Adjust; path = ../../../Adjust; @@ -286,6 +300,14 @@ name = Frameworks; sourceTree = ""; }; + D799022A24C093AA00C7D11C /* Frameworks */ = { + isa = PBXGroup; + children = ( + D799022B24C093AA00C7D11C /* AppTrackingTransparency.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -369,6 +391,7 @@ 9D449E201E6ED88F00E7E80B /* ADJUtil.m in Sources */, 9D449E241E6ED88F00E7E80B /* ADJAttribution.m in Sources */, 9DC95F2A1C10515300138E4B /* Constants.m in Sources */, + 9D2F240B2447DDE100B7CA90 /* ADJSubscription.m in Sources */, 963909441BCBFCF300A2E8A4 /* AppDelegate.m in Sources */, 9D449E311E6ED88F00E7E80B /* ADJSessionParameters.m in Sources */, 9D449E171E6ED88F00E7E80B /* ADJActivityHandler.m in Sources */, @@ -387,6 +410,7 @@ 9D449E2D1E6ED88F00E7E80B /* ADJSystemProfile.m in Sources */, 9D449E261E6ED88F00E7E80B /* ADJTimerOnce.m in Sources */, 963909411BCBFCF300A2E8A4 /* main.m in Sources */, + 6FBEE90B24E420FA00FEF3F1 /* ADJUrlStrategy.m in Sources */, 9D449E2B1E6ED88F00E7E80B /* ADJEventSuccess.m in Sources */, 9D449E211E6ED88F00E7E80B /* ADJEvent.m in Sources */, 9D449E2E1E6ED88F00E7E80B /* ADJBackoffStrategy.m in Sources */, @@ -545,6 +569,7 @@ PRODUCT_BUNDLE_IDENTIFIER = com.adjust.examples; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; + SUPPORTS_MACCATALYST = YES; }; name = Debug; }; @@ -566,6 +591,7 @@ PRODUCT_BUNDLE_IDENTIFIER = com.adjust.examples; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; + SUPPORTS_MACCATALYST = YES; }; name = Release; }; diff --git a/examples/AdjustExample-ObjC/AdjustExample-ObjC/AdjustExample-ObjC.entitlements b/examples/AdjustExample-ObjC/AdjustExample-ObjC/AdjustExample-ObjC.entitlements index c7476a337..3cd2fd0dc 100644 --- a/examples/AdjustExample-ObjC/AdjustExample-ObjC/AdjustExample-ObjC.entitlements +++ b/examples/AdjustExample-ObjC/AdjustExample-ObjC/AdjustExample-ObjC.entitlements @@ -6,5 +6,9 @@ applinks:f6wc.adj.st + com.apple.security.app-sandbox + + com.apple.security.network.client + diff --git a/examples/AdjustExample-ObjC/AdjustExample-ObjC/AppDelegate.m b/examples/AdjustExample-ObjC/AdjustExample-ObjC/AppDelegate.m index 923bf8483..11b439123 100644 --- a/examples/AdjustExample-ObjC/AdjustExample-ObjC/AppDelegate.m +++ b/examples/AdjustExample-ObjC/AdjustExample-ObjC/AppDelegate.m @@ -23,7 +23,7 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:( // Change the log level. [adjustConfig setLogLevel:ADJLogLevelVerbose]; - +/* // Enable event buffering. // [adjustConfig setEventBufferingEnabled:YES]; @@ -58,7 +58,7 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:( // Remove all session partner parameters. // [Adjust resetSessionPartnerParameters]; - +*/ // Initialise the SDK. [Adjust appDidLaunch:adjustConfig]; diff --git a/examples/AdjustExample-ObjC/AdjustExample-ObjC/Assets.xcassets/AppIcon.appiconset/Contents.json b/examples/AdjustExample-ObjC/AdjustExample-ObjC/Assets.xcassets/AppIcon.appiconset/Contents.json index d8db8d65f..a735bcafe 100644 --- a/examples/AdjustExample-ObjC/AdjustExample-ObjC/Assets.xcassets/AppIcon.appiconset/Contents.json +++ b/examples/AdjustExample-ObjC/AdjustExample-ObjC/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -1,98 +1,116 @@ { "images" : [ { + "filename" : "adjust_blue_40.png", "idiom" : "iphone", - "size" : "20x20", - "scale" : "2x" + "scale" : "2x", + "size" : "20x20" }, { + "filename" : "adjust_blue_60.png", "idiom" : "iphone", - "size" : "20x20", - "scale" : "3x" + "scale" : "3x", + "size" : "20x20" }, { + "filename" : "adjust_blue_58.png", "idiom" : "iphone", - "size" : "29x29", - "scale" : "2x" + "scale" : "2x", + "size" : "29x29" }, { + "filename" : "adjust_blue_87.png", "idiom" : "iphone", - "size" : "29x29", - "scale" : "3x" + "scale" : "3x", + "size" : "29x29" }, { + "filename" : "adjust_blue_80.png", "idiom" : "iphone", - "size" : "40x40", - "scale" : "2x" + "scale" : "2x", + "size" : "40x40" }, { + "filename" : "adjust_blue_120.png", "idiom" : "iphone", - "size" : "40x40", - "scale" : "3x" + "scale" : "3x", + "size" : "40x40" }, { + "filename" : "adjust_blue_120-1.png", "idiom" : "iphone", - "size" : "60x60", - "scale" : "2x" + "scale" : "2x", + "size" : "60x60" }, { + "filename" : "adjust_blue_180.png", "idiom" : "iphone", - "size" : "60x60", - "scale" : "3x" + "scale" : "3x", + "size" : "60x60" }, { + "filename" : "adjust_blue_20.png", "idiom" : "ipad", - "size" : "20x20", - "scale" : "1x" + "scale" : "1x", + "size" : "20x20" }, { + "filename" : "adjust_blue_40-1.png", "idiom" : "ipad", - "size" : "20x20", - "scale" : "2x" + "scale" : "2x", + "size" : "20x20" }, { + "filename" : "adjust_blue_29.png", "idiom" : "ipad", - "size" : "29x29", - "scale" : "1x" + "scale" : "1x", + "size" : "29x29" }, { + "filename" : "adjust_blue_58-1.png", "idiom" : "ipad", - "size" : "29x29", - "scale" : "2x" + "scale" : "2x", + "size" : "29x29" }, { + "filename" : "adjust_blue_40-2.png", "idiom" : "ipad", - "size" : "40x40", - "scale" : "1x" + "scale" : "1x", + "size" : "40x40" }, { + "filename" : "adjust_blue_80-1.png", "idiom" : "ipad", - "size" : "40x40", - "scale" : "2x" + "scale" : "2x", + "size" : "40x40" }, { + "filename" : "adjust_blue_76.png", "idiom" : "ipad", - "size" : "76x76", - "scale" : "1x" + "scale" : "1x", + "size" : "76x76" }, { + "filename" : "adjust_blue_152.png", "idiom" : "ipad", - "size" : "76x76", - "scale" : "2x" + "scale" : "2x", + "size" : "76x76" }, { + "filename" : "adjust_blue_167.png", "idiom" : "ipad", - "size" : "83.5x83.5", - "scale" : "2x" + "scale" : "2x", + "size" : "83.5x83.5" }, { + "filename" : "adjust_blue_1024.png", "idiom" : "ios-marketing", - "size" : "1024x1024", - "scale" : "1x" + "scale" : "1x", + "size" : "1024x1024" } ], "info" : { - "version" : 1, - "author" : "xcode" + "author" : "xcode", + "version" : 1 } -} \ No newline at end of file +} diff --git a/examples/AdjustExample-ObjC/AdjustExample-ObjC/Assets.xcassets/AppIcon.appiconset/adjust_blue_1024.png b/examples/AdjustExample-ObjC/AdjustExample-ObjC/Assets.xcassets/AppIcon.appiconset/adjust_blue_1024.png new file mode 100644 index 000000000..4cb073842 Binary files /dev/null and b/examples/AdjustExample-ObjC/AdjustExample-ObjC/Assets.xcassets/AppIcon.appiconset/adjust_blue_1024.png differ diff --git a/examples/AdjustExample-ObjC/AdjustExample-ObjC/Assets.xcassets/AppIcon.appiconset/adjust_blue_120-1.png b/examples/AdjustExample-ObjC/AdjustExample-ObjC/Assets.xcassets/AppIcon.appiconset/adjust_blue_120-1.png new file mode 100644 index 000000000..bf16b2bf7 Binary files /dev/null and b/examples/AdjustExample-ObjC/AdjustExample-ObjC/Assets.xcassets/AppIcon.appiconset/adjust_blue_120-1.png differ diff --git a/examples/AdjustExample-ObjC/AdjustExample-ObjC/Assets.xcassets/AppIcon.appiconset/adjust_blue_120.png b/examples/AdjustExample-ObjC/AdjustExample-ObjC/Assets.xcassets/AppIcon.appiconset/adjust_blue_120.png new file mode 100644 index 000000000..bf16b2bf7 Binary files /dev/null and b/examples/AdjustExample-ObjC/AdjustExample-ObjC/Assets.xcassets/AppIcon.appiconset/adjust_blue_120.png differ diff --git a/examples/AdjustExample-ObjC/AdjustExample-ObjC/Assets.xcassets/AppIcon.appiconset/adjust_blue_152.png b/examples/AdjustExample-ObjC/AdjustExample-ObjC/Assets.xcassets/AppIcon.appiconset/adjust_blue_152.png new file mode 100644 index 000000000..333a377e4 Binary files /dev/null and b/examples/AdjustExample-ObjC/AdjustExample-ObjC/Assets.xcassets/AppIcon.appiconset/adjust_blue_152.png differ diff --git a/examples/AdjustExample-ObjC/AdjustExample-ObjC/Assets.xcassets/AppIcon.appiconset/adjust_blue_167.png b/examples/AdjustExample-ObjC/AdjustExample-ObjC/Assets.xcassets/AppIcon.appiconset/adjust_blue_167.png new file mode 100644 index 000000000..c61335a10 Binary files /dev/null and b/examples/AdjustExample-ObjC/AdjustExample-ObjC/Assets.xcassets/AppIcon.appiconset/adjust_blue_167.png differ diff --git a/examples/AdjustExample-ObjC/AdjustExample-ObjC/Assets.xcassets/AppIcon.appiconset/adjust_blue_180.png b/examples/AdjustExample-ObjC/AdjustExample-ObjC/Assets.xcassets/AppIcon.appiconset/adjust_blue_180.png new file mode 100644 index 000000000..0fba94604 Binary files /dev/null and b/examples/AdjustExample-ObjC/AdjustExample-ObjC/Assets.xcassets/AppIcon.appiconset/adjust_blue_180.png differ diff --git a/examples/AdjustExample-ObjC/AdjustExample-ObjC/Assets.xcassets/AppIcon.appiconset/adjust_blue_20.png b/examples/AdjustExample-ObjC/AdjustExample-ObjC/Assets.xcassets/AppIcon.appiconset/adjust_blue_20.png new file mode 100644 index 000000000..334019df1 Binary files /dev/null and b/examples/AdjustExample-ObjC/AdjustExample-ObjC/Assets.xcassets/AppIcon.appiconset/adjust_blue_20.png differ diff --git a/examples/AdjustExample-ObjC/AdjustExample-ObjC/Assets.xcassets/AppIcon.appiconset/adjust_blue_29.png b/examples/AdjustExample-ObjC/AdjustExample-ObjC/Assets.xcassets/AppIcon.appiconset/adjust_blue_29.png new file mode 100644 index 000000000..7552055d5 Binary files /dev/null and b/examples/AdjustExample-ObjC/AdjustExample-ObjC/Assets.xcassets/AppIcon.appiconset/adjust_blue_29.png differ diff --git a/examples/AdjustExample-ObjC/AdjustExample-ObjC/Assets.xcassets/AppIcon.appiconset/adjust_blue_40-1.png b/examples/AdjustExample-ObjC/AdjustExample-ObjC/Assets.xcassets/AppIcon.appiconset/adjust_blue_40-1.png new file mode 100644 index 000000000..25d92b5d7 Binary files /dev/null and b/examples/AdjustExample-ObjC/AdjustExample-ObjC/Assets.xcassets/AppIcon.appiconset/adjust_blue_40-1.png differ diff --git a/examples/AdjustExample-ObjC/AdjustExample-ObjC/Assets.xcassets/AppIcon.appiconset/adjust_blue_40-2.png b/examples/AdjustExample-ObjC/AdjustExample-ObjC/Assets.xcassets/AppIcon.appiconset/adjust_blue_40-2.png new file mode 100644 index 000000000..25d92b5d7 Binary files /dev/null and b/examples/AdjustExample-ObjC/AdjustExample-ObjC/Assets.xcassets/AppIcon.appiconset/adjust_blue_40-2.png differ diff --git a/examples/AdjustExample-ObjC/AdjustExample-ObjC/Assets.xcassets/AppIcon.appiconset/adjust_blue_40.png b/examples/AdjustExample-ObjC/AdjustExample-ObjC/Assets.xcassets/AppIcon.appiconset/adjust_blue_40.png new file mode 100644 index 000000000..25d92b5d7 Binary files /dev/null and b/examples/AdjustExample-ObjC/AdjustExample-ObjC/Assets.xcassets/AppIcon.appiconset/adjust_blue_40.png differ diff --git a/examples/AdjustExample-ObjC/AdjustExample-ObjC/Assets.xcassets/AppIcon.appiconset/adjust_blue_58-1.png b/examples/AdjustExample-ObjC/AdjustExample-ObjC/Assets.xcassets/AppIcon.appiconset/adjust_blue_58-1.png new file mode 100644 index 000000000..46812bf7c Binary files /dev/null and b/examples/AdjustExample-ObjC/AdjustExample-ObjC/Assets.xcassets/AppIcon.appiconset/adjust_blue_58-1.png differ diff --git a/examples/AdjustExample-ObjC/AdjustExample-ObjC/Assets.xcassets/AppIcon.appiconset/adjust_blue_58.png b/examples/AdjustExample-ObjC/AdjustExample-ObjC/Assets.xcassets/AppIcon.appiconset/adjust_blue_58.png new file mode 100644 index 000000000..46812bf7c Binary files /dev/null and b/examples/AdjustExample-ObjC/AdjustExample-ObjC/Assets.xcassets/AppIcon.appiconset/adjust_blue_58.png differ diff --git a/examples/AdjustExample-ObjC/AdjustExample-ObjC/Assets.xcassets/AppIcon.appiconset/adjust_blue_60.png b/examples/AdjustExample-ObjC/AdjustExample-ObjC/Assets.xcassets/AppIcon.appiconset/adjust_blue_60.png new file mode 100644 index 000000000..dc584791d Binary files /dev/null and b/examples/AdjustExample-ObjC/AdjustExample-ObjC/Assets.xcassets/AppIcon.appiconset/adjust_blue_60.png differ diff --git a/examples/AdjustExample-ObjC/AdjustExample-ObjC/Assets.xcassets/AppIcon.appiconset/adjust_blue_76.png b/examples/AdjustExample-ObjC/AdjustExample-ObjC/Assets.xcassets/AppIcon.appiconset/adjust_blue_76.png new file mode 100644 index 000000000..321b5bfe6 Binary files /dev/null and b/examples/AdjustExample-ObjC/AdjustExample-ObjC/Assets.xcassets/AppIcon.appiconset/adjust_blue_76.png differ diff --git a/examples/AdjustExample-ObjC/AdjustExample-ObjC/Assets.xcassets/AppIcon.appiconset/adjust_blue_80-1.png b/examples/AdjustExample-ObjC/AdjustExample-ObjC/Assets.xcassets/AppIcon.appiconset/adjust_blue_80-1.png new file mode 100644 index 000000000..2dde40d2b Binary files /dev/null and b/examples/AdjustExample-ObjC/AdjustExample-ObjC/Assets.xcassets/AppIcon.appiconset/adjust_blue_80-1.png differ diff --git a/examples/AdjustExample-ObjC/AdjustExample-ObjC/Assets.xcassets/AppIcon.appiconset/adjust_blue_80.png b/examples/AdjustExample-ObjC/AdjustExample-ObjC/Assets.xcassets/AppIcon.appiconset/adjust_blue_80.png new file mode 100644 index 000000000..2dde40d2b Binary files /dev/null and b/examples/AdjustExample-ObjC/AdjustExample-ObjC/Assets.xcassets/AppIcon.appiconset/adjust_blue_80.png differ diff --git a/examples/AdjustExample-ObjC/AdjustExample-ObjC/Assets.xcassets/AppIcon.appiconset/adjust_blue_87.png b/examples/AdjustExample-ObjC/AdjustExample-ObjC/Assets.xcassets/AppIcon.appiconset/adjust_blue_87.png new file mode 100644 index 000000000..d0a819453 Binary files /dev/null and b/examples/AdjustExample-ObjC/AdjustExample-ObjC/Assets.xcassets/AppIcon.appiconset/adjust_blue_87.png differ diff --git a/examples/AdjustExample-ObjC/AdjustExample-ObjC/ViewControllerObjC.m b/examples/AdjustExample-ObjC/AdjustExample-ObjC/ViewControllerObjC.m index 938f4778f..80d0025ff 100644 --- a/examples/AdjustExample-ObjC/AdjustExample-ObjC/ViewControllerObjC.m +++ b/examples/AdjustExample-ObjC/AdjustExample-ObjC/ViewControllerObjC.m @@ -37,9 +37,6 @@ - (void)didReceiveMemoryWarning { - (IBAction)clickTrackSimpleEvent:(UIButton *)sender { ADJEvent *event = [ADJEvent eventWithEventToken:kEventToken1]; - // Attach callback ID to event. - [event setCallbackId:@"RandomCallbackId"]; - [Adjust trackEvent:event]; } diff --git a/examples/AdjustExample-Swift/AdjustExample-Swift.xcodeproj/project.pbxproj b/examples/AdjustExample-Swift/AdjustExample-Swift.xcodeproj/project.pbxproj index 72daadca3..e457ad226 100644 --- a/examples/AdjustExample-Swift/AdjustExample-Swift.xcodeproj/project.pbxproj +++ b/examples/AdjustExample-Swift/AdjustExample-Swift.xcodeproj/project.pbxproj @@ -7,7 +7,9 @@ objects = { /* Begin PBXBuildFile section */ + 6FBEE90E24E4212600FEF3F1 /* ADJUrlStrategy.m in Sources */ = {isa = PBXBuildFile; fileRef = 6FBEE90D24E4212600FEF3F1 /* ADJUrlStrategy.m */; }; 6FCC850F1F2794C600D6A0ED /* ADJReachability.m in Sources */ = {isa = PBXBuildFile; fileRef = 6FCC850E1F2794BE00D6A0ED /* ADJReachability.m */; }; + 9D2F240E2447DDF600B7CA90 /* ADJSubscription.m in Sources */ = {isa = PBXBuildFile; fileRef = 9D2F240C2447DDF600B7CA90 /* ADJSubscription.m */; }; 9D449E761E6EDC3D00E7E80B /* ADJActivityHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = 9D449E351E6EDC3D00E7E80B /* ADJActivityHandler.m */; }; 9D449E771E6EDC3D00E7E80B /* ADJActivityKind.m in Sources */ = {isa = PBXBuildFile; fileRef = 9D449E371E6EDC3D00E7E80B /* ADJActivityKind.m */; }; 9D449E781E6EDC3D00E7E80B /* ADJActivityPackage.m in Sources */ = {isa = PBXBuildFile; fileRef = 9D449E391E6EDC3D00E7E80B /* ADJActivityPackage.m */; }; @@ -47,11 +49,17 @@ 9DF7A9D01CB4ECA600D3591F /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 9DF7A9CE1CB4ECA600D3591F /* LaunchScreen.storyboard */; }; 9DFB04C21D745B22006D48FC /* iAd.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9DFB04C11D745B22006D48FC /* iAd.framework */; }; 9DFB04C41D745B28006D48FC /* AdSupport.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9DFB04C31D745B28006D48FC /* AdSupport.framework */; }; + D71BFB7024CAD74A00878F3E /* AppTrackingTransparency.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D71BFB6F24CAD74A00878F3E /* AppTrackingTransparency.framework */; }; + D731B41524DAAB5C0036F619 /* LoadProductController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D731B41424DAAB5C0036F619 /* LoadProductController.swift */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ + 6FBEE90C24E4212500FEF3F1 /* ADJUrlStrategy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ADJUrlStrategy.h; sourceTree = ""; }; + 6FBEE90D24E4212600FEF3F1 /* ADJUrlStrategy.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ADJUrlStrategy.m; sourceTree = ""; }; 6FCC850D1F2794BE00D6A0ED /* ADJReachability.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ADJReachability.h; sourceTree = ""; }; 6FCC850E1F2794BE00D6A0ED /* ADJReachability.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ADJReachability.m; sourceTree = ""; }; + 9D2F240C2447DDF600B7CA90 /* ADJSubscription.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ADJSubscription.m; sourceTree = ""; }; + 9D2F240D2447DDF600B7CA90 /* ADJSubscription.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ADJSubscription.h; sourceTree = ""; }; 9D319B9823054502000E28A6 /* AdjustExample-Swift.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = "AdjustExample-Swift.entitlements"; sourceTree = ""; }; 9D449E341E6EDC3D00E7E80B /* ADJActivityHandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ADJActivityHandler.h; sourceTree = ""; }; 9D449E351E6EDC3D00E7E80B /* ADJActivityHandler.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ADJActivityHandler.m; sourceTree = ""; }; @@ -127,6 +135,8 @@ 9DF7A9DF1CB4F01B00D3591F /* AdjustExample-Swift-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "AdjustExample-Swift-Bridging-Header.h"; sourceTree = ""; }; 9DFB04C11D745B22006D48FC /* iAd.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = iAd.framework; path = System/Library/Frameworks/iAd.framework; sourceTree = SDKROOT; }; 9DFB04C31D745B28006D48FC /* AdSupport.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AdSupport.framework; path = System/Library/Frameworks/AdSupport.framework; sourceTree = SDKROOT; }; + D71BFB6F24CAD74A00878F3E /* AppTrackingTransparency.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppTrackingTransparency.framework; path = System/Library/Frameworks/AppTrackingTransparency.framework; sourceTree = SDKROOT; }; + D731B41424DAAB5C0036F619 /* LoadProductController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoadProductController.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -134,6 +144,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + D71BFB7024CAD74A00878F3E /* AppTrackingTransparency.framework in Frameworks */, 9DFB04C21D745B22006D48FC /* iAd.framework in Frameworks */, 9DFB04C41D745B28006D48FC /* AdSupport.framework in Frameworks */, ); @@ -206,6 +217,10 @@ 6FCC850E1F2794BE00D6A0ED /* ADJReachability.m */, 9DD0E9BF1F45879A00B2A759 /* ADJUserDefaults.h */, 9DD0E9C01F45879A00B2A759 /* ADJUserDefaults.m */, + 9D2F240D2447DDF600B7CA90 /* ADJSubscription.h */, + 9D2F240C2447DDF600B7CA90 /* ADJSubscription.m */, + 6FBEE90C24E4212500FEF3F1 /* ADJUrlStrategy.h */, + 6FBEE90D24E4212600FEF3F1 /* ADJUrlStrategy.m */, ); name = Adjust; path = ../../../Adjust; @@ -229,6 +244,7 @@ children = ( 9DF7A9C41CB4ECA600D3591F /* AdjustExample-Swift */, 9DF7A9C31CB4ECA600D3591F /* Products */, + D71BFB6E24CAD74A00878F3E /* Frameworks */, ); sourceTree = ""; }; @@ -253,6 +269,7 @@ 9DF7A9DF1CB4F01B00D3591F /* AdjustExample-Swift-Bridging-Header.h */, 9D449E331E6EDC3D00E7E80B /* Adjust */, 9DFB04C01D745B13006D48FC /* Frameworks */, + D731B41424DAAB5C0036F619 /* LoadProductController.swift */, ); path = "AdjustExample-Swift"; sourceTree = ""; @@ -266,6 +283,14 @@ name = Frameworks; sourceTree = ""; }; + D71BFB6E24CAD74A00878F3E /* Frameworks */ = { + isa = PBXGroup; + children = ( + D71BFB6F24CAD74A00878F3E /* AppTrackingTransparency.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -358,6 +383,7 @@ 9D449E8A1E6EDC3D00E7E80B /* ADJPackageHandler.m in Sources */, 9DF7A9C81CB4ECA600D3591F /* ViewControllerSwift.swift in Sources */, 9D449E7E1E6EDC3D00E7E80B /* ADJAttribution.m in Sources */, + 6FBEE90E24E4212600FEF3F1 /* ADJUrlStrategy.m in Sources */, 9D449E831E6EDC3D00E7E80B /* ADJDeviceInfo.m in Sources */, 9D449E7F1E6EDC3D00E7E80B /* ADJAttributionHandler.m in Sources */, 6FCC850F1F2794C600D6A0ED /* ADJReachability.m in Sources */, @@ -365,6 +391,7 @@ 9D449E841E6EDC3D00E7E80B /* ADJEvent.m in Sources */, 9D449E951E6EDC3D00E7E80B /* ADJUtil.m in Sources */, 9D449E7C1E6EDC3D00E7E80B /* UIDevice+ADJAdditions.m in Sources */, + 9D2F240E2447DDF600B7CA90 /* ADJSubscription.m in Sources */, 9D449E851E6EDC3D00E7E80B /* ADJEventFailure.m in Sources */, 9D449E7B1E6EDC3D00E7E80B /* NSString+ADJAdditions.m in Sources */, 9D449E7D1E6EDC3D00E7E80B /* ADJAdjustFactory.m in Sources */, @@ -377,6 +404,7 @@ 9D449E7A1E6EDC3D00E7E80B /* NSData+ADJAdditions.m in Sources */, 9D449E8D1E6EDC3D00E7E80B /* ADJSdkClickHandler.m in Sources */, 9D449E881E6EDC3D00E7E80B /* ADJLogger.m in Sources */, + D731B41524DAAB5C0036F619 /* LoadProductController.swift in Sources */, 9DF7A9C61CB4ECA600D3591F /* AppDelegate.swift in Sources */, 9D449E931E6EDC3D00E7E80B /* ADJTimerOnce.m in Sources */, 9D449E801E6EDC3D00E7E80B /* ADJBackoffStrategy.m in Sources */, diff --git a/examples/AdjustExample-Swift/AdjustExample-Swift.xcodeproj/xcshareddata/xcschemes/AdjustExample-Swift.xcscheme b/examples/AdjustExample-Swift/AdjustExample-Swift.xcodeproj/xcshareddata/xcschemes/AdjustExample-Swift.xcscheme new file mode 100644 index 000000000..742df7c4c --- /dev/null +++ b/examples/AdjustExample-Swift/AdjustExample-Swift.xcodeproj/xcshareddata/xcschemes/AdjustExample-Swift.xcscheme @@ -0,0 +1,78 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/AdjustExample-Swift/AdjustExample-Swift/Base.lproj/Main.storyboard b/examples/AdjustExample-Swift/AdjustExample-Swift/Base.lproj/Main.storyboard index 8bc65e6fb..6516585a4 100644 --- a/examples/AdjustExample-Swift/AdjustExample-Swift/Base.lproj/Main.storyboard +++ b/examples/AdjustExample-Swift/AdjustExample-Swift/Base.lproj/Main.storyboard @@ -1,12 +1,9 @@ - - - - + + - - + @@ -113,6 +110,27 @@ + + @@ -122,22 +140,26 @@ + + + + @@ -147,11 +169,13 @@ + + diff --git a/examples/AdjustExample-Swift/AdjustExample-Swift/Info.plist b/examples/AdjustExample-Swift/AdjustExample-Swift/Info.plist index 38182b7b5..c723fa9d7 100644 --- a/examples/AdjustExample-Swift/AdjustExample-Swift/Info.plist +++ b/examples/AdjustExample-Swift/AdjustExample-Swift/Info.plist @@ -2,6 +2,15 @@ + SKAdNetworkItems + + + SKAdNetworkIdentifier + qgugw9aumk.skadnetwork + + + NSUserTrackingUsageDescription + We need your permission to retrieve IDFA CFBundleDevelopmentRegion en CFBundleExecutable diff --git a/examples/AdjustExample-Swift/AdjustExample-Swift/LoadProductController.swift b/examples/AdjustExample-Swift/AdjustExample-Swift/LoadProductController.swift new file mode 100644 index 000000000..67b600e82 --- /dev/null +++ b/examples/AdjustExample-Swift/AdjustExample-Swift/LoadProductController.swift @@ -0,0 +1,117 @@ +// +// LoadProductController.swift +// AdjustExample-Swift +// +// Created by Ricardo Carvalho on 05/08/2020. +// Copyright © 2020 adjust GmbH. All rights reserved. +// + +import UIKit +import StoreKit + +struct ProductParameters: Codable { + let adNetworkId: String + let adNetworkVersion: String + let campaignId : String + let id: String + let nonce: String + let signature: String + let sourceAppId: String + let timestamp: String +} + +protocol ProductLoadable { + func loadProduct(from source: UIViewController) +} + +@available(iOS 14.0, *) +class LoadProductController: NSObject, ProductLoadable { + + let version = "2.0" + let store = SKStoreProductViewController() + + func loadProduct(from source: UIViewController) { + + guard var URL = URL(string: "http://10.8.2.155:8000/get-ad-impression") else {return} + let URLParams = [ + "skadnetwork_version": version, + "source_app_id": "com.adjust.examples", + ] + + URL = URL.appendingQueryParameters(URLParams) + var request = URLRequest(url: URL) + request.httpMethod = "GET" + + let semaphore = DispatchSemaphore(value: 0) + var product: ProductParameters! + + let task = URLSession.shared.dataTask(with: request, completionHandler: { (data: Data?, response: URLResponse?, error: Error?) -> Void in + + product = try! JSONDecoder().decode(ProductParameters.self, from: data!) + + semaphore.signal() + }) + task.resume() + + semaphore.wait() + + let parameters: [String: Any] = [SKStoreProductParameterITunesItemIdentifier: NSNumber(integerLiteral: Int(product.id)!), + SKStoreProductParameterAdNetworkIdentifier: product.adNetworkId, + SKStoreProductParameterAdNetworkCampaignIdentifier: NSNumber(integerLiteral: Int(product.campaignId)!), + SKStoreProductParameterAdNetworkTimestamp: NSNumber(value: Int(product.timestamp)!), + SKStoreProductParameterAdNetworkNonce: NSUUID(uuidString: product.nonce), + SKStoreProductParameterAdNetworkSourceAppStoreIdentifier: product.sourceAppId, + SKStoreProductParameterAdNetworkVersion: version, + SKStoreProductParameterAdNetworkAttributionSignature: product.signature] + + + store.loadProduct(withParameters: parameters) { (result, error) in + if let error = error { + print("Error on loading = \(error)") + } else { + print("Loaded with success") + source.present(self.store, animated: true, completion: nil) + } + } + + } + +} + +protocol URLQueryParameterStringConvertible { + var queryParameters: String {get} +} + +extension Dictionary : URLQueryParameterStringConvertible { + /** + This computed property returns a query parameters string from the given NSDictionary. For + example, if the input is @{@"day":@"Tuesday", @"month":@"January"}, the output + string will be @"day=Tuesday&month=January". + @return The computed parameters string. + */ + var queryParameters: String { + var parts: [String] = [] + for (key, value) in self { + let part = String(format: "%@=%@", + String(describing: key).addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)!, + String(describing: value).addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)!) + parts.append(part as String) + } + return parts.joined(separator: "&") + } + +} + +extension URL { + /** + Creates a new URL by adding the given query parameters. + @param parametersDictionary The query parameter dictionary to add. + @return A new URL. + */ + func appendingQueryParameters(_ parametersDictionary : Dictionary) -> URL { + let URLString : String = String(format: "%@?%@", self.absoluteString, parametersDictionary.queryParameters) + return URL(string: URLString)! + } +} + + diff --git a/examples/AdjustExample-Swift/AdjustExample-Swift/ViewControllerSwift.swift b/examples/AdjustExample-Swift/AdjustExample-Swift/ViewControllerSwift.swift index b18db0a52..610a43433 100644 --- a/examples/AdjustExample-Swift/AdjustExample-Swift/ViewControllerSwift.swift +++ b/examples/AdjustExample-Swift/AdjustExample-Swift/ViewControllerSwift.swift @@ -7,6 +7,8 @@ // import UIKit +import AppTrackingTransparency +import AdSupport class ViewControllerSwift: UIViewController { @IBOutlet weak var btnTrackEventSimple: UIButton? @@ -18,6 +20,14 @@ class ViewControllerSwift: UIViewController { @IBOutlet weak var btnEnableSDK: UIButton? @IBOutlet weak var btnDisableSDK: UIButton? @IBOutlet weak var btnIsSDKEnabled: UIButton? + + lazy var loadProductController: ProductLoadable? = { + if #available(iOS 14.0, *) { + return LoadProductController() + } + + return nil + }() override func viewDidLoad() { super.viewDidLoad() @@ -26,6 +36,24 @@ class ViewControllerSwift: UIViewController { override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() } + + @IBAction func btnAskPermission(_sender: UIButton) { + if #available(iOS 14, *) { + print("status notDetermined == \(ATTrackingManager.trackingAuthorizationStatus == .notDetermined)") + print("status authorized == \(ATTrackingManager.trackingAuthorizationStatus == .authorized)") + print("IDFA == \(ASIdentifierManager.shared().advertisingIdentifier)") + ATTrackingManager.requestTrackingAuthorization { (status) in + print("IDFA == \(ASIdentifierManager.shared().advertisingIdentifier)") + print("authorized == \(status == .authorized)") + print("denied == \(status == .denied)") + print("restricted == \(status == .restricted)") + } + } + } + + @IBAction func btnLoadProduct(_sender: UIButton) { + loadProductController?.loadProduct(from: self) + } @IBAction func btnTrackEventSimpleTapped(_sender: UIButton) { let event = ADJEvent(eventToken: "g3mfiw"); diff --git a/examples/AdjustExample-WebView/AdjustExample-WebView.xcodeproj/project.pbxproj b/examples/AdjustExample-WebView/AdjustExample-WebView.xcodeproj/project.pbxproj index ccd8d6ae0..be71a5fa6 100644 --- a/examples/AdjustExample-WebView/AdjustExample-WebView.xcodeproj/project.pbxproj +++ b/examples/AdjustExample-WebView/AdjustExample-WebView.xcodeproj/project.pbxproj @@ -7,6 +7,7 @@ objects = { /* Begin PBXBuildFile section */ + 6FBEE91124E4213900FEF3F1 /* ADJUrlStrategy.m in Sources */ = {isa = PBXBuildFile; fileRef = 6FBEE91024E4213800FEF3F1 /* ADJUrlStrategy.m */; }; 6FCC85121F2794D900D6A0ED /* ADJReachability.m in Sources */ = {isa = PBXBuildFile; fileRef = 6FCC85111F2794D600D6A0ED /* ADJReachability.m */; }; 968595F11D0B2E630011CA2B /* AdjustBridgeRegister.m in Sources */ = {isa = PBXBuildFile; fileRef = 968595F01D0B2E630011CA2B /* AdjustBridgeRegister.m */; }; 9D1082A91CFDAF8E0050568B /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 9D1082A81CFDAF8E0050568B /* main.m */; }; @@ -20,6 +21,7 @@ 9D10833F1CFDDBF50050568B /* Default-568h@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 9D10833E1CFDDBF50050568B /* Default-568h@2x.png */; }; 9D1083411CFDE2470050568B /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9D1083401CFDE2470050568B /* UIKit.framework */; }; 9D1083431CFDE29A0050568B /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9D1083421CFDE29A0050568B /* Foundation.framework */; }; + 9D2F24112447DE0A00B7CA90 /* ADJSubscription.m in Sources */ = {isa = PBXBuildFile; fileRef = 9D2F24102447DE0A00B7CA90 /* ADJSubscription.m */; }; 9D449EDA1E6EDD4100E7E80B /* ADJActivityHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = 9D449E991E6EDD4100E7E80B /* ADJActivityHandler.m */; }; 9D449EDB1E6EDD4100E7E80B /* ADJActivityKind.m in Sources */ = {isa = PBXBuildFile; fileRef = 9D449E9B1E6EDD4100E7E80B /* ADJActivityKind.m */; }; 9D449EDC1E6EDD4100E7E80B /* ADJActivityPackage.m in Sources */ = {isa = PBXBuildFile; fileRef = 9D449E9D1E6EDD4100E7E80B /* ADJActivityPackage.m */; }; @@ -60,6 +62,8 @@ /* End PBXBuildFile section */ /* Begin PBXFileReference section */ + 6FBEE90F24E4213800FEF3F1 /* ADJUrlStrategy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ADJUrlStrategy.h; sourceTree = ""; }; + 6FBEE91024E4213800FEF3F1 /* ADJUrlStrategy.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ADJUrlStrategy.m; sourceTree = ""; }; 6FCC85101F2794D600D6A0ED /* ADJReachability.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ADJReachability.h; sourceTree = ""; }; 6FCC85111F2794D600D6A0ED /* ADJReachability.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ADJReachability.m; sourceTree = ""; }; 968595EF1D0B2E630011CA2B /* AdjustBridgeRegister.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AdjustBridgeRegister.h; sourceTree = ""; }; @@ -78,6 +82,8 @@ 9D10833E1CFDDBF50050568B /* Default-568h@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default-568h@2x.png"; sourceTree = ""; }; 9D1083401CFDE2470050568B /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; 9D1083421CFDE29A0050568B /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; + 9D2F240F2447DE0A00B7CA90 /* ADJSubscription.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ADJSubscription.h; sourceTree = ""; }; + 9D2F24102447DE0A00B7CA90 /* ADJSubscription.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ADJSubscription.m; sourceTree = ""; }; 9D449E981E6EDD4100E7E80B /* ADJActivityHandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ADJActivityHandler.h; sourceTree = ""; }; 9D449E991E6EDD4100E7E80B /* ADJActivityHandler.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ADJActivityHandler.m; sourceTree = ""; }; 9D449E9A1E6EDD4100E7E80B /* ADJActivityKind.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ADJActivityKind.h; sourceTree = ""; }; @@ -293,6 +299,10 @@ 6FCC85111F2794D600D6A0ED /* ADJReachability.m */, 9DD0E9C21F4587C600B2A759 /* ADJUserDefaults.h */, 9DD0E9C31F4587C600B2A759 /* ADJUserDefaults.m */, + 9D2F240F2447DE0A00B7CA90 /* ADJSubscription.h */, + 9D2F24102447DE0A00B7CA90 /* ADJSubscription.m */, + 6FBEE90F24E4213800FEF3F1 /* ADJUrlStrategy.h */, + 6FBEE91024E4213800FEF3F1 /* ADJUrlStrategy.m */, ); name = Adjust; path = ../../../Adjust; @@ -411,6 +421,7 @@ buildActionMask = 2147483647; files = ( 9D449EE31E6EDD4100E7E80B /* ADJAttributionHandler.m in Sources */, + 6FBEE91124E4213900FEF3F1 /* ADJUrlStrategy.m in Sources */, 9D9A99DA1D0B699A0022FFCE /* AppDelegate.m in Sources */, 9D449EE41E6EDD4100E7E80B /* ADJBackoffStrategy.m in Sources */, 9D449EDA1E6EDD4100E7E80B /* ADJActivityHandler.m in Sources */, @@ -448,6 +459,7 @@ 9D449EF01E6EDD4100E7E80B /* ADJResponseData.m in Sources */, 9D1082A91CFDAF8E0050568B /* main.m in Sources */, 9D449EF91E6EDD4100E7E80B /* ADJUtil.m in Sources */, + 9D2F24112447DE0A00B7CA90 /* ADJSubscription.m in Sources */, 9D449EEE1E6EDD4100E7E80B /* ADJPackageHandler.m in Sources */, 9D449EE91E6EDD4100E7E80B /* ADJEventFailure.m in Sources */, 9D449EF41E6EDD4100E7E80B /* ADJSessionSuccess.m in Sources */, diff --git a/examples/AdjustExample-iMessage/AdjustExample-iMessage.xcodeproj/project.pbxproj b/examples/AdjustExample-iMessage/AdjustExample-iMessage.xcodeproj/project.pbxproj index 6c88f2ed5..93ed3069c 100644 --- a/examples/AdjustExample-iMessage/AdjustExample-iMessage.xcodeproj/project.pbxproj +++ b/examples/AdjustExample-iMessage/AdjustExample-iMessage.xcodeproj/project.pbxproj @@ -7,6 +7,7 @@ objects = { /* Begin PBXBuildFile section */ + 6FBEE91A24E4218C00FEF3F1 /* ADJUrlStrategy.m in Sources */ = {isa = PBXBuildFile; fileRef = 6FBEE91824E4218B00FEF3F1 /* ADJUrlStrategy.m */; }; 9D01676920FF812B0029CFFF /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 9D01676820FF812B0029CFFF /* Assets.xcassets */; }; 9D01677020FF812B0029CFFF /* AdjustExample-iMessage MessagesExtension.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 9D01676F20FF812B0029CFFF /* AdjustExample-iMessage MessagesExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; 9D01677520FF812B0029CFFF /* Messages.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9D01677420FF812B0029CFFF /* Messages.framework */; }; @@ -46,6 +47,7 @@ 9D01687420FF88F60029CFFF /* ADJUserDefaults.m in Sources */ = {isa = PBXBuildFile; fileRef = 9D01684E20FF88F60029CFFF /* ADJUserDefaults.m */; }; 9D01687620FF88F60029CFFF /* ADJActivityHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = 9D01685420FF88F60029CFFF /* ADJActivityHandler.m */; }; 9D01687720FF88F60029CFFF /* ADJReachability.m in Sources */ = {isa = PBXBuildFile; fileRef = 9D01685520FF88F60029CFFF /* ADJReachability.m */; }; + 9D2F241A2447DE4700B7CA90 /* ADJSubscription.m in Sources */ = {isa = PBXBuildFile; fileRef = 9D2F24192447DE4700B7CA90 /* ADJSubscription.m */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -73,6 +75,8 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + 6FBEE91824E4218B00FEF3F1 /* ADJUrlStrategy.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ADJUrlStrategy.m; sourceTree = ""; }; + 6FBEE91924E4218B00FEF3F1 /* ADJUrlStrategy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ADJUrlStrategy.h; sourceTree = ""; }; 9D01676520FF81280029CFFF /* AdjustExample-iMessage.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "AdjustExample-iMessage.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 9D01676820FF812B0029CFFF /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 9D01676A20FF812B0029CFFF /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; @@ -149,6 +153,8 @@ 9D01685320FF88F60029CFFF /* ADJTimerCycle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ADJTimerCycle.h; sourceTree = ""; }; 9D01685420FF88F60029CFFF /* ADJActivityHandler.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ADJActivityHandler.m; sourceTree = ""; }; 9D01685520FF88F60029CFFF /* ADJReachability.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ADJReachability.m; sourceTree = ""; }; + 9D2F24182447DE4700B7CA90 /* ADJSubscription.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ADJSubscription.h; sourceTree = ""; }; + 9D2F24192447DE4700B7CA90 /* ADJSubscription.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ADJSubscription.m; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -276,6 +282,10 @@ 9D01685320FF88F60029CFFF /* ADJTimerCycle.h */, 9D01685420FF88F60029CFFF /* ADJActivityHandler.m */, 9D01685520FF88F60029CFFF /* ADJReachability.m */, + 9D2F24182447DE4700B7CA90 /* ADJSubscription.h */, + 9D2F24192447DE4700B7CA90 /* ADJSubscription.m */, + 6FBEE91924E4218B00FEF3F1 /* ADJUrlStrategy.h */, + 6FBEE91824E4218B00FEF3F1 /* ADJUrlStrategy.m */, ); name = Adjust; path = ../../../Adjust; @@ -408,6 +418,7 @@ 9D01686720FF88F60029CFFF /* ADJConfig.m in Sources */, 9D01687720FF88F60029CFFF /* ADJReachability.m in Sources */, 9D01685A20FF88F60029CFFF /* ADJKeychain.m in Sources */, + 6FBEE91A24E4218C00FEF3F1 /* ADJUrlStrategy.m in Sources */, 9D01686A20FF88F60029CFFF /* NSString+ADJAdditions.m in Sources */, 9D01687120FF88F60029CFFF /* ADJAdjustFactory.m in Sources */, 9D01687220FF88F60029CFFF /* ADJResponseData.m in Sources */, @@ -423,6 +434,7 @@ 9D01686B20FF88F60029CFFF /* NSData+ADJAdditions.m in Sources */, 9D01685C20FF88F60029CFFF /* ADJEvent.m in Sources */, 9D01687320FF88F60029CFFF /* ADJPackageBuilder.m in Sources */, + 9D2F241A2447DE4700B7CA90 /* ADJSubscription.m in Sources */, 9D01685620FF88F60029CFFF /* ADJDeviceInfo.m in Sources */, 9D01686620FF88F60029CFFF /* Adjust.m in Sources */, 9D01685D20FF88F60029CFFF /* ADJSessionSuccess.m in Sources */, diff --git a/examples/AdjustExample-iMessage/AdjustExample-iMessage.xcodeproj/xcshareddata/xcschemes/AdjustExample-iMessage MessagesExtension.xcscheme b/examples/AdjustExample-iMessage/AdjustExample-iMessage.xcodeproj/xcshareddata/xcschemes/AdjustExample-iMessage MessagesExtension.xcscheme index cd4c7302b..35e386fd8 100644 --- a/examples/AdjustExample-iMessage/AdjustExample-iMessage.xcodeproj/xcshareddata/xcschemes/AdjustExample-iMessage MessagesExtension.xcscheme +++ b/examples/AdjustExample-iMessage/AdjustExample-iMessage.xcodeproj/xcshareddata/xcschemes/AdjustExample-iMessage MessagesExtension.xcscheme @@ -1,6 +1,6 @@