├── VERSION ├── ios ├── Assets │ └── .gitkeep ├── Classes │ ├── AdjustSdk.h │ └── AdjustSdkDelegate.h └── adjust_sdk.podspec ├── test ├── ios │ ├── Assets │ │ └── .gitkeep │ ├── AdjustTestLibrary.framework │ │ ├── AdjustTestLibrary │ │ ├── Versions │ │ │ ├── A │ │ │ │ ├── AdjustTestLibrary │ │ │ │ └── Headers │ │ │ │ │ ├── ATLBlockingQueue.h │ │ │ │ │ ├── ATLControlWebSocketClient.h │ │ │ │ │ ├── ATLUtil.h │ │ │ │ │ ├── ATLConstants.h │ │ │ │ │ ├── ATLNetworking.h │ │ │ │ │ └── ATLTestLibrary.h │ │ │ └── Current │ │ │ │ ├── AdjustTestLibrary │ │ │ │ └── Headers │ │ │ │ ├── ATLBlockingQueue.h │ │ │ │ ├── ATLControlWebSocketClient.h │ │ │ │ ├── ATLUtil.h │ │ │ │ ├── ATLConstants.h │ │ │ │ ├── ATLNetworking.h │ │ │ │ └── ATLTestLibrary.h │ │ └── Headers │ │ │ ├── ATLBlockingQueue.h │ │ │ ├── ATLControlWebSocketClient.h │ │ │ ├── ATLUtil.h │ │ │ ├── ATLConstants.h │ │ │ ├── ATLNetworking.h │ │ │ └── ATLTestLibrary.h │ ├── Classes │ │ ├── TestLibPlugin.h │ │ ├── AdjustCommandExecutor.h │ │ ├── AdjustCommandExecutor.m │ │ └── TestLibPlugin.m │ └── test_lib.podspec ├── LICENSE ├── android │ ├── gradle.properties │ ├── settings.gradle │ ├── src │ │ └── main │ │ │ ├── AndroidManifest.xml │ │ │ └── java │ │ │ └── com │ │ │ └── adjust │ │ │ └── test │ │ │ └── lib │ │ │ └── TestLibPlugin.java │ ├── libs │ │ ├── adjust-test-library.jar │ │ └── adjust-test-options.jar │ ├── gradle │ │ └── wrapper │ │ │ └── gradle-wrapper.properties │ └── build.gradle ├── CHANGELOG.md ├── app │ ├── ios │ │ ├── Runner │ │ │ ├── Runner-Bridging-Header.h │ │ │ ├── Assets.xcassets │ │ │ │ ├── LaunchImage.imageset │ │ │ │ │ ├── LaunchImage.png │ │ │ │ │ ├── LaunchImage@2x.png │ │ │ │ │ ├── LaunchImage@3x.png │ │ │ │ │ ├── README.md │ │ │ │ │ └── Contents.json │ │ │ │ └── AppIcon.appiconset │ │ │ │ │ ├── Icon-App-20x20@1x.png │ │ │ │ │ ├── Icon-App-20x20@2x.png │ │ │ │ │ ├── Icon-App-20x20@3x.png │ │ │ │ │ ├── Icon-App-29x29@1x.png │ │ │ │ │ ├── Icon-App-29x29@2x.png │ │ │ │ │ ├── Icon-App-29x29@3x.png │ │ │ │ │ ├── Icon-App-40x40@1x.png │ │ │ │ │ ├── Icon-App-40x40@2x.png │ │ │ │ │ ├── Icon-App-40x40@3x.png │ │ │ │ │ ├── Icon-App-60x60@2x.png │ │ │ │ │ ├── Icon-App-60x60@3x.png │ │ │ │ │ ├── Icon-App-76x76@1x.png │ │ │ │ │ ├── Icon-App-76x76@2x.png │ │ │ │ │ ├── Icon-App-1024x1024@1x.png │ │ │ │ │ ├── Icon-App-83.5x83.5@2x.png │ │ │ │ │ └── Contents.json │ │ │ ├── AppDelegate.swift │ │ │ ├── Base.lproj │ │ │ │ ├── Main.storyboard │ │ │ │ └── LaunchScreen.storyboard │ │ │ └── Info.plist │ │ ├── Flutter │ │ │ ├── Debug.xcconfig │ │ │ ├── Release.xcconfig │ │ │ └── AppFrameworkInfo.plist │ │ ├── Runner.xcodeproj │ │ │ ├── project.xcworkspace │ │ │ │ ├── contents.xcworkspacedata │ │ │ │ └── xcshareddata │ │ │ │ │ ├── WorkspaceSettings.xcsettings │ │ │ │ │ └── IDEWorkspaceChecks.plist │ │ │ └── xcshareddata │ │ │ │ └── xcschemes │ │ │ │ └── Runner.xcscheme │ │ ├── Runner.xcworkspace │ │ │ ├── contents.xcworkspacedata │ │ │ └── xcshareddata │ │ │ │ ├── WorkspaceSettings.xcsettings │ │ │ │ └── IDEWorkspaceChecks.plist │ │ └── Podfile │ ├── android │ │ ├── gradle │ │ │ └── wrapper │ │ │ │ ├── gradle-wrapper.jar │ │ │ │ └── gradle-wrapper.properties │ │ ├── app │ │ │ ├── src │ │ │ │ ├── main │ │ │ │ │ ├── res │ │ │ │ │ │ ├── mipmap-hdpi │ │ │ │ │ │ │ └── ic_launcher.png │ │ │ │ │ │ ├── mipmap-mdpi │ │ │ │ │ │ │ └── ic_launcher.png │ │ │ │ │ │ ├── mipmap-xhdpi │ │ │ │ │ │ │ └── ic_launcher.png │ │ │ │ │ │ ├── mipmap-xxhdpi │ │ │ │ │ │ │ └── ic_launcher.png │ │ │ │ │ │ ├── mipmap-xxxhdpi │ │ │ │ │ │ │ └── ic_launcher.png │ │ │ │ │ │ ├── drawable │ │ │ │ │ │ │ └── launch_background.xml │ │ │ │ │ │ └── values │ │ │ │ │ │ │ └── styles.xml │ │ │ │ │ ├── kotlin │ │ │ │ │ │ └── com │ │ │ │ │ │ │ └── adjust │ │ │ │ │ │ │ └── examples │ │ │ │ │ │ │ └── MainActivity.kt │ │ │ │ │ └── AndroidManifest.xml │ │ │ │ ├── debug │ │ │ │ │ └── AndroidManifest.xml │ │ │ │ └── profile │ │ │ │ │ └── AndroidManifest.xml │ │ │ └── build.gradle.kts │ │ ├── gradle.properties │ │ ├── build.gradle.kts │ │ ├── settings.gradle.kts │ │ ├── gradlew.bat │ │ └── gradlew │ ├── pubspec.yaml │ ├── .metadata │ ├── README.md │ └── lib │ │ ├── command.dart │ │ └── main.dart ├── README.md ├── pubspec.yaml └── lib │ └── test_lib.dart ├── android ├── gradle.properties ├── settings.gradle ├── src │ └── main │ │ ├── AndroidManifest.xml │ │ └── java │ │ └── com │ │ └── adjust │ │ └── sdk │ │ └── flutter │ │ └── AdjustUtils.java ├── gradle │ └── wrapper │ │ └── gradle-wrapper.properties └── build.gradle ├── example ├── ios │ ├── Runner │ │ ├── Runner-Bridging-Header.h │ │ ├── Assets.xcassets │ │ │ ├── LaunchImage.imageset │ │ │ │ ├── LaunchImage.png │ │ │ │ ├── LaunchImage@2x.png │ │ │ │ ├── LaunchImage@3x.png │ │ │ │ ├── README.md │ │ │ │ └── Contents.json │ │ │ └── AppIcon.appiconset │ │ │ │ ├── Icon-App-20x20@1x.png │ │ │ │ ├── Icon-App-20x20@2x.png │ │ │ │ ├── Icon-App-20x20@3x.png │ │ │ │ ├── Icon-App-29x29@1x.png │ │ │ │ ├── Icon-App-29x29@2x.png │ │ │ │ ├── Icon-App-29x29@3x.png │ │ │ │ ├── Icon-App-40x40@1x.png │ │ │ │ ├── Icon-App-40x40@2x.png │ │ │ │ ├── Icon-App-40x40@3x.png │ │ │ │ ├── Icon-App-60x60@2x.png │ │ │ │ ├── Icon-App-60x60@3x.png │ │ │ │ ├── Icon-App-76x76@1x.png │ │ │ │ ├── Icon-App-76x76@2x.png │ │ │ │ ├── Icon-App-1024x1024@1x.png │ │ │ │ ├── Icon-App-83.5x83.5@2x.png │ │ │ │ └── Contents.json │ │ ├── AppDelegate.swift │ │ ├── Base.lproj │ │ │ ├── Main.storyboard │ │ │ └── LaunchScreen.storyboard │ │ └── Info.plist │ ├── Flutter │ │ ├── Debug.xcconfig │ │ ├── Release.xcconfig │ │ └── AppFrameworkInfo.plist │ ├── Runner.xcodeproj │ │ ├── project.xcworkspace │ │ │ ├── contents.xcworkspacedata │ │ │ └── xcshareddata │ │ │ │ ├── WorkspaceSettings.xcsettings │ │ │ │ └── IDEWorkspaceChecks.plist │ │ └── xcshareddata │ │ │ └── xcschemes │ │ │ └── Runner.xcscheme │ ├── Runner.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ ├── WorkspaceSettings.xcsettings │ │ │ └── IDEWorkspaceChecks.plist │ └── Podfile ├── android │ ├── gradle │ │ └── wrapper │ │ │ ├── gradle-wrapper.jar │ │ │ └── gradle-wrapper.properties │ ├── app │ │ ├── src │ │ │ ├── main │ │ │ │ ├── res │ │ │ │ │ ├── mipmap-hdpi │ │ │ │ │ │ └── ic_launcher.png │ │ │ │ │ ├── mipmap-mdpi │ │ │ │ │ │ └── ic_launcher.png │ │ │ │ │ ├── mipmap-xhdpi │ │ │ │ │ │ └── ic_launcher.png │ │ │ │ │ ├── mipmap-xxhdpi │ │ │ │ │ │ └── ic_launcher.png │ │ │ │ │ ├── mipmap-xxxhdpi │ │ │ │ │ │ └── ic_launcher.png │ │ │ │ │ ├── drawable │ │ │ │ │ │ └── launch_background.xml │ │ │ │ │ ├── drawable-v21 │ │ │ │ │ │ └── launch_background.xml │ │ │ │ │ ├── values │ │ │ │ │ │ └── styles.xml │ │ │ │ │ └── values-night │ │ │ │ │ │ └── styles.xml │ │ │ │ ├── kotlin │ │ │ │ │ └── com │ │ │ │ │ │ └── adjust │ │ │ │ │ │ └── examples │ │ │ │ │ │ └── MainActivity.kt │ │ │ │ └── AndroidManifest.xml │ │ │ ├── debug │ │ │ │ └── AndroidManifest.xml │ │ │ └── profile │ │ │ │ └── AndroidManifest.xml │ │ └── build.gradle.kts │ ├── gradle.properties │ ├── build.gradle.kts │ ├── settings.gradle.kts │ ├── gradlew.bat │ └── gradlew ├── pubspec.yaml ├── .metadata └── README.md ├── .gitmodules ├── README.md ├── .pubignore ├── pubspec.yaml ├── lib ├── adjust_deeplink.dart ├── adjust_app_store_purchase.dart ├── adjust_play_store_purchase.dart ├── adjust_store_info.dart ├── adjust_session_success.dart ├── adjust_session_failure.dart ├── adjust_event_success.dart ├── adjust_event_failure.dart ├── adjust_third_party_sharing.dart ├── adjust_purchase_verification_result.dart ├── adjust_app_store_subscription.dart ├── adjust_attribution.dart ├── adjust_play_store_subscription.dart ├── adjust_ad_revenue.dart ├── adjust_event.dart └── adjust.dart ├── LICENSE └── .gitignore /VERSION: -------------------------------------------------------------------------------- 1 | 5.5.0 2 | -------------------------------------------------------------------------------- /ios/Assets/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/ios/Assets/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/LICENSE: -------------------------------------------------------------------------------- 1 | TODO: Add your license here. 2 | -------------------------------------------------------------------------------- /android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx1536M 2 | -------------------------------------------------------------------------------- /android/settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'adjust_sdk' 2 | -------------------------------------------------------------------------------- /test/android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx1536M 2 | -------------------------------------------------------------------------------- /test/android/settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'test_lib' 2 | -------------------------------------------------------------------------------- /test/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 0.0.1 2 | 3 | * TODO: Describe initial release. 4 | -------------------------------------------------------------------------------- /example/ios/Runner/Runner-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | #import "GeneratedPluginRegistrant.h" 2 | -------------------------------------------------------------------------------- /test/app/ios/Runner/Runner-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | #import "GeneratedPluginRegistrant.h" 2 | -------------------------------------------------------------------------------- /android/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /test/android/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /test/android/libs/adjust-test-library.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adjust/flutter_sdk/HEAD/test/android/libs/adjust-test-library.jar -------------------------------------------------------------------------------- /test/android/libs/adjust-test-options.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adjust/flutter_sdk/HEAD/test/android/libs/adjust-test-options.jar -------------------------------------------------------------------------------- /example/android/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adjust/flutter_sdk/HEAD/example/android/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /example/ios/Flutter/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /example/ios/Flutter/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /test/app/ios/Flutter/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /test/app/ios/Flutter/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /test/app/android/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adjust/flutter_sdk/HEAD/test/app/android/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /test/ios/AdjustTestLibrary.framework/AdjustTestLibrary: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adjust/flutter_sdk/HEAD/test/ios/AdjustTestLibrary.framework/AdjustTestLibrary -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adjust/flutter_sdk/HEAD/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adjust/flutter_sdk/HEAD/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adjust/flutter_sdk/HEAD/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adjust/flutter_sdk/HEAD/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /test/app/android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adjust/flutter_sdk/HEAD/test/app/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /test/app/android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adjust/flutter_sdk/HEAD/test/app/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /test/app/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adjust/flutter_sdk/HEAD/test/app/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adjust/flutter_sdk/HEAD/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /test/app/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adjust/flutter_sdk/HEAD/test/app/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /test/app/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adjust/flutter_sdk/HEAD/test/app/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /test/ios/AdjustTestLibrary.framework/Versions/A/AdjustTestLibrary: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adjust/flutter_sdk/HEAD/test/ios/AdjustTestLibrary.framework/Versions/A/AdjustTestLibrary -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adjust/flutter_sdk/HEAD/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png -------------------------------------------------------------------------------- /test/app/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adjust/flutter_sdk/HEAD/test/app/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png -------------------------------------------------------------------------------- /test/ios/AdjustTestLibrary.framework/Versions/Current/AdjustTestLibrary: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adjust/flutter_sdk/HEAD/test/ios/AdjustTestLibrary.framework/Versions/Current/AdjustTestLibrary -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adjust/flutter_sdk/HEAD/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adjust/flutter_sdk/HEAD/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png -------------------------------------------------------------------------------- /example/android/app/src/main/kotlin/com/adjust/examples/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.adjust.examples 2 | 3 | import io.flutter.embedding.android.FlutterActivity 4 | 5 | class MainActivity : FlutterActivity() -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adjust/flutter_sdk/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adjust/flutter_sdk/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adjust/flutter_sdk/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adjust/flutter_sdk/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adjust/flutter_sdk/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adjust/flutter_sdk/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adjust/flutter_sdk/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adjust/flutter_sdk/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adjust/flutter_sdk/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adjust/flutter_sdk/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adjust/flutter_sdk/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adjust/flutter_sdk/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adjust/flutter_sdk/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png -------------------------------------------------------------------------------- /test/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adjust/flutter_sdk/HEAD/test/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png -------------------------------------------------------------------------------- /test/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adjust/flutter_sdk/HEAD/test/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png -------------------------------------------------------------------------------- /test/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adjust/flutter_sdk/HEAD/test/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png -------------------------------------------------------------------------------- /test/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adjust/flutter_sdk/HEAD/test/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png -------------------------------------------------------------------------------- /test/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adjust/flutter_sdk/HEAD/test/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png -------------------------------------------------------------------------------- /test/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adjust/flutter_sdk/HEAD/test/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png -------------------------------------------------------------------------------- /test/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adjust/flutter_sdk/HEAD/test/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png -------------------------------------------------------------------------------- /test/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adjust/flutter_sdk/HEAD/test/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png -------------------------------------------------------------------------------- /test/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adjust/flutter_sdk/HEAD/test/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png -------------------------------------------------------------------------------- /test/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adjust/flutter_sdk/HEAD/test/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png -------------------------------------------------------------------------------- /test/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adjust/flutter_sdk/HEAD/test/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png -------------------------------------------------------------------------------- /test/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adjust/flutter_sdk/HEAD/test/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png -------------------------------------------------------------------------------- /test/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adjust/flutter_sdk/HEAD/test/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png -------------------------------------------------------------------------------- /test/app/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adjust/flutter_sdk/HEAD/test/app/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png -------------------------------------------------------------------------------- /test/app/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adjust/flutter_sdk/HEAD/test/app/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png -------------------------------------------------------------------------------- /example/android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx8G -XX:MaxMetaspaceSize=4G -XX:ReservedCodeCacheSize=512m -XX:+HeapDumpOnOutOfMemoryError 2 | android.useAndroidX=true 3 | android.enableJetifier=true 4 | -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adjust/flutter_sdk/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adjust/flutter_sdk/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png -------------------------------------------------------------------------------- /test/app/android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx8G -XX:MaxMetaspaceSize=4G -XX:ReservedCodeCacheSize=512m -XX:+HeapDumpOnOutOfMemoryError 2 | android.useAndroidX=true 3 | android.enableJetifier=true 4 | -------------------------------------------------------------------------------- /test/app/android/app/src/main/kotlin/com/adjust/examples/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.adjust.examples 2 | 3 | import io.flutter.embedding.android.FlutterActivity 4 | 5 | class MainActivity: FlutterActivity() { 6 | } -------------------------------------------------------------------------------- /test/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adjust/flutter_sdk/HEAD/test/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png -------------------------------------------------------------------------------- /test/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adjust/flutter_sdk/HEAD/test/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "ext/android/sdk"] 2 | path = ext/android/sdk 3 | url = https://github.com/adjust/android_sdk.git 4 | [submodule "ext/ios/sdk"] 5 | path = ext/ios/sdk 6 | url = https://github.com/adjust/ios_sdk.git 7 | -------------------------------------------------------------------------------- /example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /test/app/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /example/android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | zipStoreBase=GRADLE_USER_HOME 4 | zipStorePath=wrapper/dists 5 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-all.zip 6 | -------------------------------------------------------------------------------- /test/app/android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | zipStoreBase=GRADLE_USER_HOME 4 | zipStorePath=wrapper/dists 5 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-all.zip 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Adjust SDK for Flutter 2 | 3 | This is the [Adjust](https://adjust.com)™ SDK for Flutter. Documentation is available on our [developer docs](https://dev.adjust.com/en/sdk/flutter/?version=v5). 4 | 5 | ## License 6 | 7 | Distributed under the [`MIT license`](LICENSE). 8 | -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Mon Jan 06 12:48:45 CET 2025 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip 5 | zipStoreBase=GRADLE_USER_HOME 6 | zipStorePath=wrapper/dists 7 | -------------------------------------------------------------------------------- /ios/Classes/AdjustSdk.h: -------------------------------------------------------------------------------- 1 | // 2 | // AdjustSdk.h 3 | // Adjust SDK 4 | // 5 | // Created by Srdjan Tubin (@2beens) on 6th June 2018. 6 | // Copyright © 2018-Present Adjust GmbH. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface AdjustSdk : NSObject 12 | @end 13 | -------------------------------------------------------------------------------- /example/ios/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /test/android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip 4 | networkTimeout=10000 5 | validateDistributionUrl=true 6 | zipStoreBase=GRADLE_USER_HOME 7 | zipStorePath=wrapper/dists 8 | -------------------------------------------------------------------------------- /test/app/ios/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /test/app/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /test/app/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /test/app/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /test/README.md: -------------------------------------------------------------------------------- 1 | # test_lib 2 | 3 | Flutter Plugin for Adjust Testing Library. 4 | 5 | ## Getting Started 6 | 7 | For help getting started with Flutter, view our online 8 | [documentation](https://flutter.io/). 9 | 10 | For help on editing plugin code, view the [documentation](https://flutter.io/developing-packages/#edit-plugin-package). 11 | -------------------------------------------------------------------------------- /test/app/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /test/app/android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /test/app/android/app/src/profile/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /test/ios/Classes/TestLibPlugin.h: -------------------------------------------------------------------------------- 1 | // 2 | // TestLibPlugin.h 3 | // Adjust SDK 4 | // 5 | // Created by Srdjan Tubin (@2beens) on 1st October 2018. 6 | // Copyright (c) 2018-Present Adjust GmbH. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | @interface TestLibPlugin : NSObject 13 | @end 14 | -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md: -------------------------------------------------------------------------------- 1 | # Launch Screen Assets 2 | 3 | You can customize the launch screen with your own desired assets by replacing the image files in this directory. 4 | 5 | You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. -------------------------------------------------------------------------------- /test/app/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md: -------------------------------------------------------------------------------- 1 | # Launch Screen Assets 2 | 3 | You can customize the launch screen with your own desired assets by replacing the image files in this directory. 4 | 5 | You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. -------------------------------------------------------------------------------- /example/android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /example/android/app/src/profile/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /example/ios/Runner/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import Flutter 2 | import UIKit 3 | 4 | @main 5 | @objc class AppDelegate: FlutterAppDelegate { 6 | override func application( 7 | _ application: UIApplication, 8 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? 9 | ) -> Bool { 10 | GeneratedPluginRegistrant.register(with: self) 11 | return super.application(application, didFinishLaunchingWithOptions: launchOptions) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /test/app/ios/Runner/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | import Flutter 3 | 4 | @main 5 | @objc class AppDelegate: FlutterAppDelegate { 6 | override func application( 7 | _ application: UIApplication, 8 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? 9 | ) -> Bool { 10 | GeneratedPluginRegistrant.register(with: self) 11 | return super.application(application, didFinishLaunchingWithOptions: launchOptions) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /.pubignore: -------------------------------------------------------------------------------- 1 | # Exclude test directory from published package 2 | test/ 3 | 4 | # Exclude external SDK submodules and scripts directory 5 | ext/ 6 | scripts/ 7 | 8 | # Exclude build artifacts and development files 9 | **/build/ 10 | **/.dart_tool/ 11 | **/Pods/ 12 | **/.pub-cache/ 13 | **/example/build/ 14 | **/example/ios/build/ 15 | **/example/android/build/ 16 | **/example/.dart_tool/ 17 | **/example/ios/Pods/ 18 | **/example/ios/Podfile.lock 19 | **/example/android/local.properties 20 | **/*.iml 21 | **/.DS_Store -------------------------------------------------------------------------------- /example/android/app/src/main/res/drawable/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /test/app/android/app/src/main/res/drawable/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/drawable-v21/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /example/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: AdjustExample 2 | description: "Adjust Flutter Example App" 3 | publish_to: 'none' 4 | version: 0.0.1 5 | 6 | environment: 7 | sdk: ">=3.9.0 <4.0.0" 8 | 9 | dependencies: 10 | flutter: 11 | sdk: flutter 12 | adjust_sdk: 13 | path: ../ 14 | 15 | dependency_overrides: 16 | characters: ^1.4.1 17 | material_color_utilities: ^0.13.0 18 | meta: ^1.17.0 19 | 20 | dev_dependencies: 21 | flutter_test: 22 | sdk: flutter 23 | flutter_lints: ^6.0.0 24 | 25 | flutter: 26 | uses-material-design: true 27 | -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "LaunchImage.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "LaunchImage@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "LaunchImage@3x.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /test/app/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "LaunchImage.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "LaunchImage@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "LaunchImage@3x.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: adjust_sdk 2 | description: This is the Flutter SDK of Adjust™. You can read more about Adjust™ at adjust.com. 3 | homepage: https://github.com/adjust/flutter_sdk 4 | version: 5.5.0 5 | 6 | environment: 7 | sdk: ">=2.12.0 <4.0.0" 8 | flutter: ">=1.10.0" 9 | 10 | dependencies: 11 | flutter: 12 | sdk: flutter 13 | meta: ">=1.1.6 <2.0.0" 14 | 15 | flutter: 16 | plugin: 17 | platforms: 18 | android: 19 | package: com.adjust.sdk.flutter 20 | pluginClass: AdjustSdk 21 | ios: 22 | pluginClass: AdjustSdk 23 | -------------------------------------------------------------------------------- /test/app/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: test_app 2 | description: "Adjust Flutter Test App" 3 | publish_to: 'none' 4 | version: 1.0.0+1 5 | 6 | environment: 7 | sdk: ">=3.9.0 <4.0.0" 8 | 9 | dependencies: 10 | flutter: 11 | sdk: flutter 12 | adjust_sdk: 13 | path: ../../ 14 | test_lib: 15 | path: ../ 16 | 17 | dependency_overrides: 18 | characters: ^1.4.1 19 | material_color_utilities: ^0.13.0 20 | meta: ^1.17.0 21 | 22 | dev_dependencies: 23 | flutter_test: 24 | sdk: flutter 25 | flutter_lints: ^6.0.0 26 | 27 | flutter: 28 | uses-material-design: true 29 | -------------------------------------------------------------------------------- /test/ios/AdjustTestLibrary.framework/Headers/ATLBlockingQueue.h: -------------------------------------------------------------------------------- 1 | // 2 | // ATLBlockingQueue.h 3 | // AdjustTestLibrary 4 | // 5 | // Created by Pedro on 11.01.18. 6 | // Copyright © 2018 adjust. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "ATLUtil.h" 11 | 12 | @interface ATLBlockingQueue : NSObject 13 | 14 | /** 15 | * Enqueues an object to the queue. 16 | * @param object Object to enqueue 17 | */ 18 | - (void)enqueue:(id)object; 19 | 20 | /** 21 | * Dequeues an object from the queue. This method will block. 22 | */ 23 | - (id)dequeue; 24 | 25 | - (void)teardown; 26 | 27 | @end 28 | -------------------------------------------------------------------------------- /test/ios/AdjustTestLibrary.framework/Versions/A/Headers/ATLBlockingQueue.h: -------------------------------------------------------------------------------- 1 | // 2 | // ATLBlockingQueue.h 3 | // AdjustTestLibrary 4 | // 5 | // Created by Pedro on 11.01.18. 6 | // Copyright © 2018 adjust. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "ATLUtil.h" 11 | 12 | @interface ATLBlockingQueue : NSObject 13 | 14 | /** 15 | * Enqueues an object to the queue. 16 | * @param object Object to enqueue 17 | */ 18 | - (void)enqueue:(id)object; 19 | 20 | /** 21 | * Dequeues an object from the queue. This method will block. 22 | */ 23 | - (id)dequeue; 24 | 25 | - (void)teardown; 26 | 27 | @end 28 | -------------------------------------------------------------------------------- /lib/adjust_deeplink.dart: -------------------------------------------------------------------------------- 1 | // 2 | // adjust_deeplink.dart 3 | // Adjust SDK 4 | // 5 | // Created by Ugljesa Erceg (@uerceg) on 19th August 2024. 6 | // Copyright (c) 2024-Present Adjust GmbH. All rights reserved. 7 | // 8 | 9 | class AdjustDeeplink { 10 | String deeplink; 11 | String? referrer; 12 | 13 | AdjustDeeplink(this.deeplink); 14 | 15 | Map get toMap { 16 | Map deeplinkMap = new Map(); 17 | 18 | deeplinkMap['deeplink'] = deeplink; 19 | if (referrer != null) { 20 | deeplinkMap['referrer'] = referrer; 21 | } 22 | 23 | return deeplinkMap; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /test/ios/AdjustTestLibrary.framework/Versions/Current/Headers/ATLBlockingQueue.h: -------------------------------------------------------------------------------- 1 | // 2 | // ATLBlockingQueue.h 3 | // AdjustTestLibrary 4 | // 5 | // Created by Pedro on 11.01.18. 6 | // Copyright © 2018 adjust. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "ATLUtil.h" 11 | 12 | @interface ATLBlockingQueue : NSObject 13 | 14 | /** 15 | * Enqueues an object to the queue. 16 | * @param object Object to enqueue 17 | */ 18 | - (void)enqueue:(id)object; 19 | 20 | /** 21 | * Dequeues an object from the queue. This method will block. 22 | */ 23 | - (id)dequeue; 24 | 25 | - (void)teardown; 26 | 27 | @end 28 | -------------------------------------------------------------------------------- /test/app/android/build.gradle.kts: -------------------------------------------------------------------------------- 1 | allprojects { 2 | repositories { 3 | google() 4 | mavenCentral() 5 | } 6 | } 7 | 8 | val newBuildDir: Directory = 9 | rootProject.layout.buildDirectory 10 | .dir("../../build") 11 | .get() 12 | rootProject.layout.buildDirectory.value(newBuildDir) 13 | 14 | subprojects { 15 | val newSubprojectBuildDir: Directory = newBuildDir.dir(project.name) 16 | project.layout.buildDirectory.value(newSubprojectBuildDir) 17 | } 18 | subprojects { 19 | project.evaluationDependsOn(":app") 20 | } 21 | 22 | tasks.register("clean") { 23 | delete(rootProject.layout.buildDirectory) 24 | } -------------------------------------------------------------------------------- /example/android/build.gradle.kts: -------------------------------------------------------------------------------- 1 | allprojects { 2 | repositories { 3 | google() 4 | mavenCentral() 5 | } 6 | } 7 | 8 | val newBuildDir: Directory = 9 | rootProject.layout.buildDirectory 10 | .dir("../../build") 11 | .get() 12 | rootProject.layout.buildDirectory.value(newBuildDir) 13 | 14 | subprojects { 15 | val newSubprojectBuildDir: Directory = newBuildDir.dir(project.name) 16 | project.layout.buildDirectory.value(newSubprojectBuildDir) 17 | } 18 | subprojects { 19 | project.evaluationDependsOn(":app") 20 | } 21 | 22 | tasks.register("clean") { 23 | delete(rootProject.layout.buildDirectory) 24 | } 25 | -------------------------------------------------------------------------------- /test/ios/Classes/AdjustCommandExecutor.h: -------------------------------------------------------------------------------- 1 | // 2 | // AdjustCommandExecutor.h 3 | // Adjust SDK 4 | // 5 | // Created by Srdjan Tubin (@2beens) on 1st October 2018. 6 | // Copyright (c) 2018-Present Adjust GmbH. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | #import 12 | 13 | @interface AdjustCommandExecutor : NSObject 14 | 15 | - (id)initWithMethodChannel:(FlutterMethodChannel *)channel; 16 | - (void)executeCommand:(NSString *)className 17 | methodName:(NSString *)methodName 18 | parameters:(NSString *)jsonParameters; 19 | 20 | @end 21 | -------------------------------------------------------------------------------- /lib/adjust_app_store_purchase.dart: -------------------------------------------------------------------------------- 1 | // 2 | // adjust_app_store_purchase.dart 3 | // Adjust SDK 4 | // 5 | // Created by Ugljesa Erceg (@uerceg) on 5th September 2023. 6 | // Copyright (c) 2020-Present Adjust GmbH. All rights reserved. 7 | // 8 | 9 | class AdjustAppStorePurchase { 10 | final String _productId; 11 | final String _transactionId; 12 | 13 | AdjustAppStorePurchase(this._productId, this._transactionId); 14 | 15 | Map get toMap { 16 | Map purchaseMap = new Map(); 17 | 18 | purchaseMap['productId'] = _productId; 19 | purchaseMap['transactionId'] = _transactionId; 20 | 21 | return purchaseMap; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /lib/adjust_play_store_purchase.dart: -------------------------------------------------------------------------------- 1 | // 2 | // adjust_play_store_purchase.dart 3 | // Adjust SDK 4 | // 5 | // Created by Ugljesa Erceg (@uerceg) on 4th September 2023. 6 | // Copyright (c) 2020-Present Adjust GmbH. All rights reserved. 7 | // 8 | 9 | class AdjustPlayStorePurchase { 10 | final String _productId; 11 | final String _purchaseToken; 12 | 13 | AdjustPlayStorePurchase(this._productId, this._purchaseToken); 14 | 15 | Map get toMap { 16 | Map purchaseMap = new Map(); 17 | 18 | purchaseMap['productId'] = _productId; 19 | purchaseMap['purchaseToken'] = _purchaseToken; 20 | 21 | return purchaseMap; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /lib/adjust_store_info.dart: -------------------------------------------------------------------------------- 1 | // 2 | // adjust_deeplink.dart 3 | // Adjust SDK 4 | // 5 | // Created by Mahdi ZTD (@MahdiZTD) on 6th June 2025. 6 | // Copyright (c) 2025-Present Adjust GmbH. All rights reserved. 7 | // 8 | 9 | class AdjustStoreInfo { 10 | String? storeName; 11 | String? storeAppId; 12 | 13 | AdjustStoreInfo(this.storeName); 14 | 15 | Map get toMap { 16 | Map storeInfoMap = new Map(); 17 | 18 | if (storeName != null) { 19 | storeInfoMap['storeName'] = storeName; 20 | } 21 | if (storeAppId != null) { 22 | storeInfoMap['storeAppId'] = storeAppId; 23 | } 24 | 25 | return storeInfoMap; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /test/ios/AdjustTestLibrary.framework/Headers/ATLControlWebSocketClient.h: -------------------------------------------------------------------------------- 1 | // 2 | // ATLControlWebSocketClient.h 3 | // AdjustTestLibrary 4 | // 5 | // Created by Serj on 20.02.19. 6 | // Copyright © 2019 adjust. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "PocketSocket/PSWebSocket.h" 11 | #import "ATLTestLibrary.h" 12 | 13 | NS_ASSUME_NONNULL_BEGIN 14 | 15 | @interface ATLControlWebSocketClient : NSObject 16 | 17 | - (void)initializeWebSocketWithControlUrl:(NSString*)controlUrl 18 | andTestLibrary:(ATLTestLibrary*)testLibrary; 19 | 20 | - (void)reconnectIfNeeded; 21 | 22 | - (void)sendInitTestSessionSignal:(NSString*)testSessionId; 23 | 24 | @end 25 | 26 | NS_ASSUME_NONNULL_END 27 | -------------------------------------------------------------------------------- /ios/adjust_sdk.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = 'adjust_sdk' 3 | s.version = '5.5.0' 4 | s.summary = 'Adjust Flutter SDK for iOS platform' 5 | s.description = <<-DESC 6 | Adjust Flutter SDK for iOS platform. 7 | DESC 8 | s.homepage = 'http://www.adjust.com' 9 | s.license = { :file => '../LICENSE' } 10 | s.author = { 'Adjust' => 'sdk@adjust.com' } 11 | s.source = { :path => '.' } 12 | s.source_files = 'Classes/**/*' 13 | s.public_header_files = 'Classes/**/*.h' 14 | s.ios.deployment_target = '12.0' 15 | 16 | s.dependency 'Flutter' 17 | s.dependency 'Adjust', '5.5.0' 18 | end 19 | -------------------------------------------------------------------------------- /test/ios/AdjustTestLibrary.framework/Versions/A/Headers/ATLControlWebSocketClient.h: -------------------------------------------------------------------------------- 1 | // 2 | // ATLControlWebSocketClient.h 3 | // AdjustTestLibrary 4 | // 5 | // Created by Serj on 20.02.19. 6 | // Copyright © 2019 adjust. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "PocketSocket/PSWebSocket.h" 11 | #import "ATLTestLibrary.h" 12 | 13 | NS_ASSUME_NONNULL_BEGIN 14 | 15 | @interface ATLControlWebSocketClient : NSObject 16 | 17 | - (void)initializeWebSocketWithControlUrl:(NSString*)controlUrl 18 | andTestLibrary:(ATLTestLibrary*)testLibrary; 19 | 20 | - (void)reconnectIfNeeded; 21 | 22 | - (void)sendInitTestSessionSignal:(NSString*)testSessionId; 23 | 24 | @end 25 | 26 | NS_ASSUME_NONNULL_END 27 | -------------------------------------------------------------------------------- /test/ios/AdjustTestLibrary.framework/Versions/Current/Headers/ATLControlWebSocketClient.h: -------------------------------------------------------------------------------- 1 | // 2 | // ATLControlWebSocketClient.h 3 | // AdjustTestLibrary 4 | // 5 | // Created by Serj on 20.02.19. 6 | // Copyright © 2019 adjust. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "PocketSocket/PSWebSocket.h" 11 | #import "ATLTestLibrary.h" 12 | 13 | NS_ASSUME_NONNULL_BEGIN 14 | 15 | @interface ATLControlWebSocketClient : NSObject 16 | 17 | - (void)initializeWebSocketWithControlUrl:(NSString*)controlUrl 18 | andTestLibrary:(ATLTestLibrary*)testLibrary; 19 | 20 | - (void)reconnectIfNeeded; 21 | 22 | - (void)sendInitTestSessionSignal:(NSString*)testSessionId; 23 | 24 | @end 25 | 26 | NS_ASSUME_NONNULL_END 27 | -------------------------------------------------------------------------------- /test/app/android/settings.gradle.kts: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | val flutterSdkPath = 3 | run { 4 | val properties = java.util.Properties() 5 | file("local.properties").inputStream().use { properties.load(it) } 6 | val flutterSdkPath = properties.getProperty("flutter.sdk") 7 | require(flutterSdkPath != null) { "flutter.sdk not set in local.properties" } 8 | flutterSdkPath 9 | } 10 | 11 | includeBuild("$flutterSdkPath/packages/flutter_tools/gradle") 12 | 13 | repositories { 14 | google() 15 | mavenCentral() 16 | gradlePluginPortal() 17 | } 18 | } 19 | 20 | plugins { 21 | id("dev.flutter.flutter-plugin-loader") version "1.0.0" 22 | id("com.android.application") version "8.13.0" apply false 23 | id("org.jetbrains.kotlin.android") version "2.1.0" apply false 24 | } 25 | 26 | include(":app") -------------------------------------------------------------------------------- /example/android/settings.gradle.kts: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | val flutterSdkPath = 3 | run { 4 | val properties = java.util.Properties() 5 | file("local.properties").inputStream().use { properties.load(it) } 6 | val flutterSdkPath = properties.getProperty("flutter.sdk") 7 | require(flutterSdkPath != null) { "flutter.sdk not set in local.properties" } 8 | flutterSdkPath 9 | } 10 | 11 | includeBuild("$flutterSdkPath/packages/flutter_tools/gradle") 12 | 13 | repositories { 14 | google() 15 | mavenCentral() 16 | gradlePluginPortal() 17 | } 18 | } 19 | 20 | plugins { 21 | id("dev.flutter.flutter-plugin-loader") version "1.0.0" 22 | id("com.android.application") version "8.13.0" apply false 23 | id("org.jetbrains.kotlin.android") version "2.1.0" apply false 24 | } 25 | 26 | include(":app") 27 | -------------------------------------------------------------------------------- /example/ios/Flutter/AppFrameworkInfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | App 9 | CFBundleIdentifier 10 | io.flutter.flutter.app 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | App 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1.0 23 | MinimumOSVersion 24 | 13.0 25 | 26 | 27 | -------------------------------------------------------------------------------- /android/src/main/java/com/adjust/sdk/flutter/AdjustUtils.java: -------------------------------------------------------------------------------- 1 | // 2 | // AdjustUtils.java 3 | // Adjust SDK 4 | // 5 | // Created by Srdjan Tubin (@2beens) on 5th May 2018. 6 | // Copyright (c) 2018-Present Adjust GmbH. All rights reserved. 7 | // 8 | 9 | package com.adjust.sdk.flutter; 10 | 11 | import java.text.NumberFormat; 12 | import java.text.ParsePosition; 13 | 14 | public class AdjustUtils { 15 | private static NumberFormat numberFormat = NumberFormat.getInstance(); 16 | 17 | public static boolean isNumber(String numberString) { 18 | if (numberString == null) { 19 | return false; 20 | } 21 | if (numberString.length() == 0) { 22 | return false; 23 | } 24 | 25 | ParsePosition position = new ParsePosition(0); 26 | numberFormat.parse(numberString, position); 27 | return numberString.length() == position.getIndex(); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /test/app/ios/Flutter/AppFrameworkInfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | App 9 | CFBundleIdentifier 10 | io.flutter.flutter.app 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | App 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1.0 23 | MinimumOSVersion 24 | 13.0 25 | 26 | 27 | -------------------------------------------------------------------------------- /test/ios/test_lib.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = 'test_lib' 3 | s.version = '5.5.0' 4 | s.summary = 'Adjust test library for iOS platform' 5 | s.description = <<-DESC 6 | Adjust test library for iOS platform. 7 | DESC 8 | s.homepage = 'http://www.adjust.com' 9 | s.license = { :file => '../LICENSE' } 10 | s.author = { 'Adjust' => 'sdk@adjust.com' } 11 | s.source = { :path => '.' } 12 | s.source_files = 'Classes/**/*' 13 | s.public_header_files = 'Classes/**/*.h' 14 | s.preserve_paths = 'AdjustTestLibrary.framework' 15 | s.xcconfig = { 'OTHER_LDFLAGS' => '-framework AdjustTestLibrary' } 16 | s.vendored_frameworks = 'AdjustTestLibrary.framework' 17 | s.ios.deployment_target = '8.0' 18 | 19 | s.dependency 'Flutter' 20 | end 21 | -------------------------------------------------------------------------------- /lib/adjust_session_success.dart: -------------------------------------------------------------------------------- 1 | // 2 | // adjust_session_success.dart 3 | // Adjust SDK 4 | // 5 | // Created by Srdjan Tubin (@2beens) on 25th April 2018. 6 | // Copyright (c) 2018-Present Adjust GmbH. All rights reserved. 7 | // 8 | 9 | class AdjustSessionSuccess { 10 | final String? message; 11 | final String? timestamp; 12 | final String? adid; 13 | final String? jsonResponse; 14 | 15 | AdjustSessionSuccess({ 16 | this.message, 17 | this.timestamp, 18 | this.adid, 19 | this.jsonResponse, 20 | }); 21 | 22 | factory AdjustSessionSuccess.fromMap(dynamic map) { 23 | try { 24 | return AdjustSessionSuccess( 25 | message: map['message'], 26 | timestamp: map['timestamp'], 27 | adid: map['adid'], 28 | jsonResponse: map['jsonResponse'], 29 | ); 30 | } catch (e) { 31 | throw Exception( 32 | '[AdjustFlutter]: Failed to create AdjustSessionSuccess object from given map object. Details: ' + 33 | e.toString()); 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | group 'com.adjust.sdk.flutter' 2 | version '1.0-SNAPSHOT' 3 | buildscript { 4 | repositories { 5 | google() 6 | mavenCentral() 7 | } 8 | 9 | dependencies { 10 | classpath('com.android.tools.build:gradle:8.13.0') 11 | } 12 | } 13 | rootProject.allprojects { 14 | repositories { 15 | google() 16 | mavenCentral() 17 | } 18 | 19 | gradle.projectsEvaluated { 20 | tasks.withType(JavaCompile) { 21 | options.compilerArgs << "-Xlint:unchecked" << "-Xlint:deprecation" 22 | } 23 | } 24 | } 25 | apply plugin: 'com.android.library' 26 | android { 27 | compileSdkVersion 36 28 | 29 | defaultConfig { 30 | minSdkVersion 16 31 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 32 | } 33 | lintOptions { 34 | disable 'InvalidPackage' 35 | } 36 | namespace 'com.adjust.sdk.flutter' 37 | } 38 | 39 | dependencies { 40 | implementation 'com.adjust.sdk:adjust-android:5.5.0' 41 | } 42 | -------------------------------------------------------------------------------- /test/app/android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /test/app/.metadata: -------------------------------------------------------------------------------- 1 | # This file tracks properties of this Flutter project. 2 | # Used by Flutter tool to assess capabilities and perform upgrades etc. 3 | # 4 | # This file should be version controlled and should not be manually edited. 5 | 6 | version: 7 | revision: "761747bfc538b5af34aa0d3fac380f1bc331ec49" 8 | channel: "stable" 9 | 10 | project_type: app 11 | 12 | # Tracks metadata for the flutter migrate command 13 | migration: 14 | platforms: 15 | - platform: root 16 | create_revision: 761747bfc538b5af34aa0d3fac380f1bc331ec49 17 | base_revision: 761747bfc538b5af34aa0d3fac380f1bc331ec49 18 | - platform: ios 19 | create_revision: 761747bfc538b5af34aa0d3fac380f1bc331ec49 20 | base_revision: 761747bfc538b5af34aa0d3fac380f1bc331ec49 21 | 22 | # User provided section 23 | 24 | # List of Local paths (relative to this file) that should be 25 | # ignored by the migrate tool. 26 | # 27 | # Files that are not part of the templates will be ignored by default. 28 | unmanaged_files: 29 | - 'lib/main.dart' 30 | - 'ios/Runner.xcodeproj/project.pbxproj' 31 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/values-night/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /test/android/build.gradle: -------------------------------------------------------------------------------- 1 | group 'com.adjust.test.lib' 2 | version '1.0-SNAPSHOT' 3 | 4 | buildscript { 5 | ext { 6 | agp_version = '8.2.1' 7 | } 8 | repositories { 9 | google() 10 | mavenCentral() 11 | } 12 | 13 | dependencies { 14 | classpath("com.android.tools.build:gradle:$agp_version") 15 | } 16 | } 17 | 18 | rootProject.allprojects { 19 | repositories { 20 | google() 21 | mavenCentral() 22 | } 23 | } 24 | 25 | apply plugin: 'com.android.library' 26 | 27 | android { 28 | namespace 'com.adjust.test.lib' 29 | compileSdk = 34 30 | 31 | defaultConfig { 32 | minSdkVersion 16 33 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 34 | } 35 | lintOptions { 36 | disable 'InvalidPackage' 37 | } 38 | namespace 'com.adjust.examples' 39 | } 40 | 41 | dependencies { 42 | implementation files('libs/adjust-test-library.jar') 43 | implementation files('libs/adjust-test-options.jar') 44 | implementation 'com.google.code.gson:gson:2.8.6' 45 | implementation 'org.java-websocket:Java-WebSocket:1.4.0' 46 | } -------------------------------------------------------------------------------- /lib/adjust_session_failure.dart: -------------------------------------------------------------------------------- 1 | // 2 | // adjust_session_failure.dart 3 | // Adjust SDK 4 | // 5 | // Created by Srdjan Tubin (@2beens) on 25th April 2018. 6 | // Copyright (c) 2018-Present Adjust GmbH. All rights reserved. 7 | // 8 | 9 | class AdjustSessionFailure { 10 | final String? message; 11 | final String? timestamp; 12 | final String? adid; 13 | final String? jsonResponse; 14 | final bool? willRetry; 15 | 16 | AdjustSessionFailure({ 17 | this.message, 18 | this.timestamp, 19 | this.adid, 20 | this.jsonResponse, 21 | this.willRetry, 22 | }); 23 | 24 | factory AdjustSessionFailure.fromMap(dynamic map) { 25 | try { 26 | return AdjustSessionFailure( 27 | message: map['message'], 28 | timestamp: map['timestamp'], 29 | adid: map['adid'], 30 | jsonResponse: map['jsonResponse'], 31 | willRetry: map['willRetry']?.toString().toLowerCase() == 'true', 32 | ); 33 | } catch (e) { 34 | throw Exception( 35 | '[AdjustFlutter]: Failed to create AdjustSessionFailure object from given map object. Details: ' + 36 | e.toString()); 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2018-Present Adjust GmbH, http://www.adjust.com 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining 6 | a copy of this software and associated documentation files (the 7 | "Software"), to deal in the Software without restriction, including 8 | without limitation the rights to use, copy, modify, merge, publish, 9 | distribute, sublicense, and/or sell copies of the Software, and to 10 | permit persons to whom the Software is furnished to do so, subject to 11 | the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /test/ios/AdjustTestLibrary.framework/Headers/ATLUtil.h: -------------------------------------------------------------------------------- 1 | // 2 | // ATLUtil.h 3 | // AdjustTestLibrary 4 | // 5 | // Created by Pedro on 18.04.17. 6 | // Copyright © 2017 adjust. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | typedef void (^selfInjectedBlock)(id); 12 | typedef void (^operationBlock)(NSBlockOperation *); 13 | 14 | @interface ATLUtil : NSObject 15 | 16 | + (void)debug:(NSString *)format, ...; 17 | + (void)launchInQueue:(dispatch_queue_t)queue 18 | selfInject:(id)selfInject 19 | block:(selfInjectedBlock)block; 20 | + (void)addOperationAfterLast:(NSOperationQueue *)operationQueue 21 | block:(dispatch_block_t)block; 22 | + (void)addOperationAfterLast:(NSOperationQueue *)operationQueue 23 | blockWithOperation:(operationBlock)blockWithOperation; 24 | + (BOOL)isNull:(id)value; 25 | + (NSString *)adjTrim:(NSString *)value; 26 | + (NSString *)formatDate:(NSDate *)value; 27 | + (NSString *)parseDictionaryToJsonString:(NSDictionary *) dictionary; 28 | + (NSString *)appendBasePath:(NSString *)basePath path:(NSString *)path; 29 | + (NSString *)queryString:(NSDictionary *)parameters; 30 | @end 31 | -------------------------------------------------------------------------------- /test/ios/AdjustTestLibrary.framework/Versions/A/Headers/ATLUtil.h: -------------------------------------------------------------------------------- 1 | // 2 | // ATLUtil.h 3 | // AdjustTestLibrary 4 | // 5 | // Created by Pedro on 18.04.17. 6 | // Copyright © 2017 adjust. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | typedef void (^selfInjectedBlock)(id); 12 | typedef void (^operationBlock)(NSBlockOperation *); 13 | 14 | @interface ATLUtil : NSObject 15 | 16 | + (void)debug:(NSString *)format, ...; 17 | + (void)launchInQueue:(dispatch_queue_t)queue 18 | selfInject:(id)selfInject 19 | block:(selfInjectedBlock)block; 20 | + (void)addOperationAfterLast:(NSOperationQueue *)operationQueue 21 | block:(dispatch_block_t)block; 22 | + (void)addOperationAfterLast:(NSOperationQueue *)operationQueue 23 | blockWithOperation:(operationBlock)blockWithOperation; 24 | + (BOOL)isNull:(id)value; 25 | + (NSString *)adjTrim:(NSString *)value; 26 | + (NSString *)formatDate:(NSDate *)value; 27 | + (NSString *)parseDictionaryToJsonString:(NSDictionary *) dictionary; 28 | + (NSString *)appendBasePath:(NSString *)basePath path:(NSString *)path; 29 | + (NSString *)queryString:(NSDictionary *)parameters; 30 | @end 31 | -------------------------------------------------------------------------------- /test/ios/AdjustTestLibrary.framework/Versions/Current/Headers/ATLUtil.h: -------------------------------------------------------------------------------- 1 | // 2 | // ATLUtil.h 3 | // AdjustTestLibrary 4 | // 5 | // Created by Pedro on 18.04.17. 6 | // Copyright © 2017 adjust. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | typedef void (^selfInjectedBlock)(id); 12 | typedef void (^operationBlock)(NSBlockOperation *); 13 | 14 | @interface ATLUtil : NSObject 15 | 16 | + (void)debug:(NSString *)format, ...; 17 | + (void)launchInQueue:(dispatch_queue_t)queue 18 | selfInject:(id)selfInject 19 | block:(selfInjectedBlock)block; 20 | + (void)addOperationAfterLast:(NSOperationQueue *)operationQueue 21 | block:(dispatch_block_t)block; 22 | + (void)addOperationAfterLast:(NSOperationQueue *)operationQueue 23 | blockWithOperation:(operationBlock)blockWithOperation; 24 | + (BOOL)isNull:(id)value; 25 | + (NSString *)adjTrim:(NSString *)value; 26 | + (NSString *)formatDate:(NSDate *)value; 27 | + (NSString *)parseDictionaryToJsonString:(NSDictionary *) dictionary; 28 | + (NSString *)appendBasePath:(NSString *)basePath path:(NSString *)path; 29 | + (NSString *)queryString:(NSDictionary *)parameters; 30 | @end 31 | -------------------------------------------------------------------------------- /lib/adjust_event_success.dart: -------------------------------------------------------------------------------- 1 | // 2 | // adjust_event_success.dart 3 | // Adjust SDK 4 | // 5 | // Created by Srdjan Tubin (@2beens) on 25th April 2018. 6 | // Copyright (c) 2018-Present Adjust GmbH. All rights reserved. 7 | // 8 | 9 | class AdjustEventSuccess { 10 | final String? message; 11 | final String? timestamp; 12 | final String? adid; 13 | final String? eventToken; 14 | final String? callbackId; 15 | final String? jsonResponse; 16 | 17 | AdjustEventSuccess({ 18 | this.message, 19 | this.timestamp, 20 | this.adid, 21 | this.eventToken, 22 | this.callbackId, 23 | this.jsonResponse, 24 | }); 25 | 26 | factory AdjustEventSuccess.fromMap(dynamic map) { 27 | try { 28 | return AdjustEventSuccess( 29 | message: map['message'], 30 | timestamp: map['timestamp'], 31 | adid: map['adid'], 32 | eventToken: map['eventToken'], 33 | callbackId: map['callbackId'], 34 | jsonResponse: map['jsonResponse'], 35 | ); 36 | } catch (e) { 37 | throw Exception( 38 | '[AdjustFlutter]: Failed to create AdjustEventSuccess object from given map object. Details: ' + 39 | e.toString()); 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /test/ios/AdjustTestLibrary.framework/Headers/ATLConstants.h: -------------------------------------------------------------------------------- 1 | // 2 | // ATLConstants.h 3 | // AdjustTestLibrary 4 | // 5 | // Created by Pedro on 20.04.17. 6 | // Copyright © 2017 adjust. All rights reserved. 7 | // 8 | 9 | #ifndef ATLConstants_h 10 | #define ATLConstants_h 11 | 12 | static int const ONE_SECOND = 1000; 13 | static int const ONE_MINUTE = 60 * ONE_SECOND; 14 | 15 | static NSString * const TEST_LIBRARY_CLASSNAME = @"TestLibrary"; 16 | static NSString * const ADJUST_CLASSNAME = @"Adjust"; 17 | static NSString * const WAIT_FOR_CONTROL = @"control"; 18 | static NSString * const WAIT_FOR_SLEEP = @"sleep"; 19 | static NSString * const BASE_PATH_PARAM = @"basePath"; 20 | static NSString * const TEST_NAME_PARAM = @"basePath"; 21 | static NSString * const TEST_SESSION_ID_HEADER = @"Test-Session-Id"; 22 | 23 | // web socket values 24 | static NSString * const SIGNAL_INFO = @"info"; 25 | static NSString * const SIGNAL_INIT_TEST_SESSION = @"init-test-session"; 26 | static NSString * const SIGNAL_END_WAIT = @"end-wait"; 27 | static NSString * const SIGNAL_CANCEL_CURRENT_TEST = @"cancel-current-test"; 28 | static NSString * const SIGNAL_UNKNOWN = @"unknown"; 29 | 30 | #endif /* ATLConstants_h */ 31 | -------------------------------------------------------------------------------- /test/ios/AdjustTestLibrary.framework/Versions/A/Headers/ATLConstants.h: -------------------------------------------------------------------------------- 1 | // 2 | // ATLConstants.h 3 | // AdjustTestLibrary 4 | // 5 | // Created by Pedro on 20.04.17. 6 | // Copyright © 2017 adjust. All rights reserved. 7 | // 8 | 9 | #ifndef ATLConstants_h 10 | #define ATLConstants_h 11 | 12 | static int const ONE_SECOND = 1000; 13 | static int const ONE_MINUTE = 60 * ONE_SECOND; 14 | 15 | static NSString * const TEST_LIBRARY_CLASSNAME = @"TestLibrary"; 16 | static NSString * const ADJUST_CLASSNAME = @"Adjust"; 17 | static NSString * const WAIT_FOR_CONTROL = @"control"; 18 | static NSString * const WAIT_FOR_SLEEP = @"sleep"; 19 | static NSString * const BASE_PATH_PARAM = @"basePath"; 20 | static NSString * const TEST_NAME_PARAM = @"basePath"; 21 | static NSString * const TEST_SESSION_ID_HEADER = @"Test-Session-Id"; 22 | 23 | // web socket values 24 | static NSString * const SIGNAL_INFO = @"info"; 25 | static NSString * const SIGNAL_INIT_TEST_SESSION = @"init-test-session"; 26 | static NSString * const SIGNAL_END_WAIT = @"end-wait"; 27 | static NSString * const SIGNAL_CANCEL_CURRENT_TEST = @"cancel-current-test"; 28 | static NSString * const SIGNAL_UNKNOWN = @"unknown"; 29 | 30 | #endif /* ATLConstants_h */ 31 | -------------------------------------------------------------------------------- /test/ios/AdjustTestLibrary.framework/Versions/Current/Headers/ATLConstants.h: -------------------------------------------------------------------------------- 1 | // 2 | // ATLConstants.h 3 | // AdjustTestLibrary 4 | // 5 | // Created by Pedro on 20.04.17. 6 | // Copyright © 2017 adjust. All rights reserved. 7 | // 8 | 9 | #ifndef ATLConstants_h 10 | #define ATLConstants_h 11 | 12 | static int const ONE_SECOND = 1000; 13 | static int const ONE_MINUTE = 60 * ONE_SECOND; 14 | 15 | static NSString * const TEST_LIBRARY_CLASSNAME = @"TestLibrary"; 16 | static NSString * const ADJUST_CLASSNAME = @"Adjust"; 17 | static NSString * const WAIT_FOR_CONTROL = @"control"; 18 | static NSString * const WAIT_FOR_SLEEP = @"sleep"; 19 | static NSString * const BASE_PATH_PARAM = @"basePath"; 20 | static NSString * const TEST_NAME_PARAM = @"basePath"; 21 | static NSString * const TEST_SESSION_ID_HEADER = @"Test-Session-Id"; 22 | 23 | // web socket values 24 | static NSString * const SIGNAL_INFO = @"info"; 25 | static NSString * const SIGNAL_INIT_TEST_SESSION = @"init-test-session"; 26 | static NSString * const SIGNAL_END_WAIT = @"end-wait"; 27 | static NSString * const SIGNAL_CANCEL_CURRENT_TEST = @"cancel-current-test"; 28 | static NSString * const SIGNAL_UNKNOWN = @"unknown"; 29 | 30 | #endif /* ATLConstants_h */ 31 | -------------------------------------------------------------------------------- /lib/adjust_event_failure.dart: -------------------------------------------------------------------------------- 1 | // 2 | // adjust_event_failure.dart 3 | // Adjust SDK 4 | // 5 | // Created by Srdjan Tubin (@2beens) on 25th April 2018. 6 | // Copyright (c) 2018-Present Adjust GmbH. All rights reserved. 7 | // 8 | 9 | class AdjustEventFailure { 10 | final String? message; 11 | final String? timestamp; 12 | final String? adid; 13 | final String? eventToken; 14 | final String? callbackId; 15 | final String? jsonResponse; 16 | final bool? willRetry; 17 | 18 | AdjustEventFailure({ 19 | this.message, 20 | this.timestamp, 21 | this.adid, 22 | this.eventToken, 23 | this.callbackId, 24 | this.jsonResponse, 25 | this.willRetry, 26 | }); 27 | 28 | factory AdjustEventFailure.fromMap(dynamic map) { 29 | try { 30 | return AdjustEventFailure( 31 | message: map['message'], 32 | timestamp: map['timestamp'], 33 | adid: map['adid'], 34 | eventToken: map['eventToken'], 35 | callbackId: map['callbackId'], 36 | jsonResponse: map['jsonResponse'], 37 | willRetry: map['willRetry']?.toString().toLowerCase() == 'true', 38 | ); 39 | } catch (e) { 40 | throw Exception( 41 | '[AdjustFlutter]: Failed to create AdjustEventFailure object from given map object. Details: ' + 42 | e.toString()); 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /example/android/app/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | id("com.android.application") 3 | id("kotlin-android") 4 | // the Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins 5 | id("dev.flutter.flutter-gradle-plugin") 6 | } 7 | 8 | android { 9 | namespace = "com.adjust.examples" 10 | // compileSdk = flutter.compileSdkVersion 11 | compileSdk = 36 12 | ndkVersion = flutter.ndkVersion 13 | 14 | compileOptions { 15 | sourceCompatibility = JavaVersion.VERSION_11 16 | targetCompatibility = JavaVersion.VERSION_11 17 | } 18 | 19 | kotlinOptions { 20 | jvmTarget = JavaVersion.VERSION_11.toString() 21 | } 22 | 23 | defaultConfig { 24 | applicationId = "com.adjust.examples" 25 | minSdk = flutter.minSdkVersion 26 | // targetSdk = flutter.targetSdkVersion 27 | targetSdk = 36 28 | versionCode = flutter.versionCode 29 | versionName = flutter.versionName 30 | } 31 | 32 | buildTypes { 33 | release { 34 | // signing with debug keys for development convenience 35 | signingConfig = signingConfigs.getByName("debug") 36 | } 37 | } 38 | } 39 | 40 | flutter { 41 | source = "../.." 42 | } 43 | 44 | dependencies { 45 | implementation("com.adjust.sdk:adjust-android-google-lvl:5.5.0") 46 | } 47 | -------------------------------------------------------------------------------- /ios/Classes/AdjustSdkDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AdjustSdkDelegate.h 3 | // Adjust SDK 4 | // 5 | // Created by Srdjan Tubin (2beens) on 22nd November 2018. 6 | // Copyright © 2018-Present Adjust GmbH. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | @interface AdjustSdkDelegate : NSObject 13 | 14 | @property (nonatomic) BOOL shouldLaunchDeferredDeeplink; 15 | @property (nonatomic, weak) FlutterMethodChannel *channel; 16 | 17 | + (id)getInstanceWithSwizzleOfAttributionCallback:(NSString *)swizzleAttributionCallback 18 | sessionSuccessCallback:(NSString *)swizzleSessionSuccessCallback 19 | sessionFailureCallback:(NSString *)swizzleSessionFailureCallback 20 | eventSuccessCallback:(NSString *)swizzleEventSuccessCallback 21 | eventFailureCallback:(NSString *)swizzleEventFailureCallback 22 | deferredDeeplinkCallback:(NSString *)swizzleDeferredDeeplinkCallback 23 | skanUpdatedCallback:(NSString *)swizzleSkanUpdatedCallback 24 | shouldLaunchDeferredDeeplink:(BOOL)shouldLaunchDeferredDeeplink 25 | methodChannel:(FlutterMethodChannel *)channel; 26 | 27 | + (void)teardown; 28 | 29 | @end 30 | -------------------------------------------------------------------------------- /test/ios/AdjustTestLibrary.framework/Headers/ATLNetworking.h: -------------------------------------------------------------------------------- 1 | // 2 | // ATLNetworking.h 3 | // AdjustTestLibrary 4 | // 5 | // Created by Pedro Silva on 24.05.24. 6 | // Copyright © 2024 adjust. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ATLHttpResponse : NSObject 12 | 13 | @property (nonatomic, nullable, strong) NSString * responseString; 14 | @property (nonatomic, nullable, strong) id jsonFoundation; 15 | @property (nonatomic, nullable, strong) NSDictionary *headerFields; 16 | @property (nonatomic, assign) NSInteger statusCode; 17 | 18 | @end 19 | 20 | @interface ATLHttpRequest : NSObject 21 | 22 | @property (nonatomic, nonnull, readonly, strong) NSString *path; 23 | @property (nonatomic, nullable, readonly, strong) NSString *base; 24 | @property (nonatomic, nullable, strong) NSString *bodyString; 25 | @property (nonatomic, nullable, strong) NSDictionary *headerFields; 26 | 27 | - (nonnull id)initWithPath:(nonnull NSString *)path 28 | base:(nullable NSString *)base; 29 | @end 30 | 31 | typedef void (^httpResponseHandler)(ATLHttpResponse *_Nonnull httpResponse); 32 | 33 | @interface ATLNetworking : NSObject 34 | 35 | - (void)sendPostRequestWithData:(nonnull ATLHttpRequest *)requestData 36 | baseUrl:(nonnull NSURL *)baseUrl 37 | responseHandler:(nonnull httpResponseHandler)responseHandler; 38 | 39 | @end 40 | -------------------------------------------------------------------------------- /test/ios/AdjustTestLibrary.framework/Versions/A/Headers/ATLNetworking.h: -------------------------------------------------------------------------------- 1 | // 2 | // ATLNetworking.h 3 | // AdjustTestLibrary 4 | // 5 | // Created by Pedro Silva on 24.05.24. 6 | // Copyright © 2024 adjust. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ATLHttpResponse : NSObject 12 | 13 | @property (nonatomic, nullable, strong) NSString * responseString; 14 | @property (nonatomic, nullable, strong) id jsonFoundation; 15 | @property (nonatomic, nullable, strong) NSDictionary *headerFields; 16 | @property (nonatomic, assign) NSInteger statusCode; 17 | 18 | @end 19 | 20 | @interface ATLHttpRequest : NSObject 21 | 22 | @property (nonatomic, nonnull, readonly, strong) NSString *path; 23 | @property (nonatomic, nullable, readonly, strong) NSString *base; 24 | @property (nonatomic, nullable, strong) NSString *bodyString; 25 | @property (nonatomic, nullable, strong) NSDictionary *headerFields; 26 | 27 | - (nonnull id)initWithPath:(nonnull NSString *)path 28 | base:(nullable NSString *)base; 29 | @end 30 | 31 | typedef void (^httpResponseHandler)(ATLHttpResponse *_Nonnull httpResponse); 32 | 33 | @interface ATLNetworking : NSObject 34 | 35 | - (void)sendPostRequestWithData:(nonnull ATLHttpRequest *)requestData 36 | baseUrl:(nonnull NSURL *)baseUrl 37 | responseHandler:(nonnull httpResponseHandler)responseHandler; 38 | 39 | @end 40 | -------------------------------------------------------------------------------- /test/ios/AdjustTestLibrary.framework/Versions/Current/Headers/ATLNetworking.h: -------------------------------------------------------------------------------- 1 | // 2 | // ATLNetworking.h 3 | // AdjustTestLibrary 4 | // 5 | // Created by Pedro Silva on 24.05.24. 6 | // Copyright © 2024 adjust. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ATLHttpResponse : NSObject 12 | 13 | @property (nonatomic, nullable, strong) NSString * responseString; 14 | @property (nonatomic, nullable, strong) id jsonFoundation; 15 | @property (nonatomic, nullable, strong) NSDictionary *headerFields; 16 | @property (nonatomic, assign) NSInteger statusCode; 17 | 18 | @end 19 | 20 | @interface ATLHttpRequest : NSObject 21 | 22 | @property (nonatomic, nonnull, readonly, strong) NSString *path; 23 | @property (nonatomic, nullable, readonly, strong) NSString *base; 24 | @property (nonatomic, nullable, strong) NSString *bodyString; 25 | @property (nonatomic, nullable, strong) NSDictionary *headerFields; 26 | 27 | - (nonnull id)initWithPath:(nonnull NSString *)path 28 | base:(nullable NSString *)base; 29 | @end 30 | 31 | typedef void (^httpResponseHandler)(ATLHttpResponse *_Nonnull httpResponse); 32 | 33 | @interface ATLNetworking : NSObject 34 | 35 | - (void)sendPostRequestWithData:(nonnull ATLHttpRequest *)requestData 36 | baseUrl:(nonnull NSURL *)baseUrl 37 | responseHandler:(nonnull httpResponseHandler)responseHandler; 38 | 39 | @end 40 | -------------------------------------------------------------------------------- /test/ios/Classes/AdjustCommandExecutor.m: -------------------------------------------------------------------------------- 1 | // 2 | // AdjustCommandExecutor.m 3 | // Adjust SDK 4 | // 5 | // Created by Srdjan Tubin (@2beens) on 1st October 2018. 6 | // Copyright (c) 2018-Present Adjust GmbH. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "AdjustCommandExecutor.h" 11 | 12 | @interface AdjustCommandExecutor () 13 | 14 | @property(nonatomic, weak) FlutterMethodChannel *channel; 15 | 16 | @end 17 | 18 | @implementation AdjustCommandExecutor 19 | - (id)initWithMethodChannel:(FlutterMethodChannel *)channel { 20 | self = [super init]; 21 | if (self == nil) { 22 | return nil; 23 | } 24 | 25 | NSLog(@"Initializing Test Library with Method Channel ..."); 26 | self.channel = channel; 27 | return self; 28 | } 29 | 30 | - (void)executeCommand:(NSString *)className 31 | methodName:(NSString *)methodName 32 | parameters:(NSString *)jsonParameters { 33 | NSLog(@"executeCommand className: %@, methodName: %@, parameters: %@", className, methodName, jsonParameters); 34 | NSMutableDictionary *methodParams = [[NSMutableDictionary alloc] init]; 35 | [methodParams setObject:className forKey:@"className"]; 36 | [methodParams setObject:methodName forKey:@"methodName"]; 37 | [methodParams setObject:jsonParameters forKey:@"jsonParameters"]; 38 | [self.channel invokeMethod:@"adj-test-execute" arguments:methodParams]; 39 | } 40 | 41 | @end 42 | -------------------------------------------------------------------------------- /test/app/ios/Podfile: -------------------------------------------------------------------------------- 1 | # Uncomment this line to define a global platform for your project 2 | # platform :ios, '13.0' 3 | 4 | # CocoaPods analytics sends network stats synchronously affecting flutter build latency. 5 | ENV['COCOAPODS_DISABLE_STATS'] = 'true' 6 | 7 | project 'Runner', { 8 | 'Debug' => :debug, 9 | 'Profile' => :release, 10 | 'Release' => :release, 11 | } 12 | 13 | def flutter_root 14 | generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) 15 | unless File.exist?(generated_xcode_build_settings_path) 16 | raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" 17 | end 18 | 19 | File.foreach(generated_xcode_build_settings_path) do |line| 20 | matches = line.match(/FLUTTER_ROOT\=(.*)/) 21 | return matches[1].strip if matches 22 | end 23 | raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" 24 | end 25 | 26 | require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) 27 | 28 | flutter_ios_podfile_setup 29 | 30 | target 'Runner' do 31 | use_frameworks! 32 | 33 | flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) 34 | end 35 | 36 | post_install do |installer| 37 | installer.pods_project.targets.each do |target| 38 | flutter_additional_ios_build_settings(target) 39 | end 40 | end 41 | -------------------------------------------------------------------------------- /lib/adjust_third_party_sharing.dart: -------------------------------------------------------------------------------- 1 | // 2 | // adjust_third_party_sharing.dart 3 | // Adjust SDK 4 | // 5 | // Created by Ugljesa Erceg (@uerceg) on 18th February 2021. 6 | // Copyright (c) 2021-Present Adjust GmbH. All rights reserved. 7 | // 8 | 9 | class AdjustThirdPartySharing { 10 | final bool? _isEnabled; 11 | late List _granularOptions; 12 | late List _partnerSharingSettings; 13 | 14 | AdjustThirdPartySharing(this._isEnabled) { 15 | _granularOptions = []; 16 | _partnerSharingSettings = []; 17 | } 18 | 19 | void addGranularOption(String partnerName, String key, String value) { 20 | _granularOptions.add(partnerName); 21 | _granularOptions.add(key); 22 | _granularOptions.add(value); 23 | } 24 | 25 | void addPartnerSharingSetting(String partnerName, String key, bool value) { 26 | _partnerSharingSettings.add(partnerName); 27 | _partnerSharingSettings.add(key); 28 | _partnerSharingSettings.add(value.toString()); 29 | } 30 | 31 | Map get toMap { 32 | Map thirdPartySharingMap = {'isEnabled': _isEnabled}; 33 | if (_granularOptions.length > 0) { 34 | thirdPartySharingMap['granularOptions'] = 35 | _granularOptions.join('__ADJ__'); 36 | } 37 | if (_partnerSharingSettings.length > 0) { 38 | thirdPartySharingMap['partnerSharingSettings'] = 39 | _partnerSharingSettings.join('__ADJ__'); 40 | } 41 | 42 | return thirdPartySharingMap; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /lib/adjust_purchase_verification_result.dart: -------------------------------------------------------------------------------- 1 | // 2 | // adjust_purchase_verification_result.dart 3 | // Adjust SDK 4 | // 5 | // Created by Ugljesa Erceg (@uerceg) on 4th September 2020. 6 | // Copyright (c) 2020-Present Adjust GmbH. All rights reserved. 7 | // 8 | 9 | class AdjustPurchaseVerificationResult { 10 | final num code; 11 | final String message; 12 | final String verificationStatus; 13 | 14 | AdjustPurchaseVerificationResult(this.code, this.message, this.verificationStatus); 15 | 16 | factory AdjustPurchaseVerificationResult.fromMap(dynamic map) { 17 | try { 18 | int parsedCode = -1; 19 | try { 20 | if (map['code'] != null) { 21 | parsedCode = int.parse(map['code']); 22 | } 23 | } catch (ex) {} 24 | 25 | return AdjustPurchaseVerificationResult( 26 | parsedCode, 27 | map['message'] ?? '', 28 | map['verificationStatus'] ?? ''); 29 | } catch (e) { 30 | throw Exception( 31 | '[AdjustFlutter]: Failed to create AdjustPurchaseVerificationResult object from given map object. Details: ' + 32 | e.toString()); 33 | } 34 | } 35 | 36 | Map get toMap { 37 | Map verificationInfoMap = new Map(); 38 | 39 | verificationInfoMap['code'] = code.toString(); 40 | verificationInfoMap['message'] = message; 41 | verificationInfoMap['verificationStatus'] = verificationStatus; 42 | 43 | return verificationInfoMap; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /example/ios/Podfile: -------------------------------------------------------------------------------- 1 | # Uncomment this line to define a global platform for your project 2 | # platform :ios, '13.0' 3 | 4 | # CocoaPods analytics sends network stats synchronously affecting flutter build latency. 5 | ENV['COCOAPODS_DISABLE_STATS'] = 'true' 6 | 7 | project 'Runner', { 8 | 'Debug' => :debug, 9 | 'Profile' => :release, 10 | 'Release' => :release, 11 | } 12 | 13 | def flutter_root 14 | generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) 15 | unless File.exist?(generated_xcode_build_settings_path) 16 | raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" 17 | end 18 | 19 | File.foreach(generated_xcode_build_settings_path) do |line| 20 | matches = line.match(/FLUTTER_ROOT\=(.*)/) 21 | return matches[1].strip if matches 22 | end 23 | raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" 24 | end 25 | 26 | require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) 27 | 28 | flutter_ios_podfile_setup 29 | 30 | target 'Runner' do 31 | use_frameworks! 32 | 33 | flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) 34 | target 'RunnerTests' do 35 | inherit! :search_paths 36 | end 37 | end 38 | 39 | post_install do |installer| 40 | installer.pods_project.targets.each do |target| 41 | flutter_additional_ios_build_settings(target) 42 | end 43 | end 44 | -------------------------------------------------------------------------------- /test/app/README.md: -------------------------------------------------------------------------------- 1 | # Adjust Flutter Test App 2 | 3 | A comprehensive test application for the Adjust Flutter SDK, designed to validate SDK functionality through automated testing. 4 | 5 | ## Features 6 | 7 | - **Automated Test Execution**: Connects to test framework for automated SDK testing 8 | - **Modern UI**: Clean, modern interface following Adjust design guidelines 9 | - **Cross-Platform**: Supports both Android and iOS testing scenarios 10 | - **Real-time Command Processing**: Executes test commands in real-time from test server 11 | 12 | ## Getting Started 13 | 14 | 1. **Prerequisites**: Make sure Flutter is installed and configured 15 | 2. **Install Dependencies**: Run `flutter pub get` in this directory 16 | 3. **Configure Test Server**: Update IP addresses in `main.dart` if needed 17 | 4. **Run the App**: Use `flutter run` to start the test application 18 | 19 | ## Test Configuration 20 | 21 | The app connects to a test server for automated command execution: 22 | - **Android**: Uses HTTPS connection on port 8443 23 | - **iOS**: Uses HTTP connection on port 8080 24 | - **WebSocket**: Control connection on port 1987 25 | 26 | ## Architecture 27 | 28 | - `main.dart`: Main app entry point with modern UI 29 | - `command.dart`: Command parsing and representation 30 | - `command_executor.dart`: SDK method execution engine 31 | - Test framework integration via `test_lib` package 32 | 33 | ## Usage 34 | 35 | 1. Launch the app 36 | 2. Tap "Start Test Session" to begin automated testing 37 | 3. The app will connect to the test server and execute commands automatically 38 | 4. Monitor console output for test execution details 39 | -------------------------------------------------------------------------------- /test/app/android/app/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | id("com.android.application") 3 | id("kotlin-android") 4 | // the Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins 5 | id("dev.flutter.flutter-gradle-plugin") 6 | } 7 | 8 | android { 9 | namespace = "com.adjust.examples" 10 | // compileSdk = flutter.compileSdkVersion 11 | compileSdk = 36 12 | ndkVersion = flutter.ndkVersion 13 | 14 | compileOptions { 15 | sourceCompatibility = JavaVersion.VERSION_11 16 | targetCompatibility = JavaVersion.VERSION_11 17 | } 18 | 19 | kotlinOptions { 20 | jvmTarget = JavaVersion.VERSION_11.toString() 21 | } 22 | 23 | defaultConfig { 24 | applicationId = "com.adjust.examples" 25 | minSdk = flutter.minSdkVersion 26 | // targetSdk = flutter.targetSdkVersion 27 | targetSdk = 36 28 | versionCode = flutter.versionCode 29 | versionName = flutter.versionName 30 | } 31 | 32 | buildTypes { 33 | release { 34 | signingConfig = signingConfigs.getByName("debug") 35 | } 36 | } 37 | 38 | lint { 39 | disable.add("InvalidPackage") 40 | } 41 | } 42 | 43 | flutter { 44 | source = "../.." 45 | } 46 | 47 | dependencies { 48 | // google Play Services for analytics 49 | implementation("com.google.android.gms:play-services-analytics:18.0.1") 50 | 51 | // install referrer for attribution 52 | implementation("com.android.installreferrer:installreferrer:2.2") 53 | 54 | // modern logging framework 55 | implementation("org.slf4j:slf4j-simple:2.0.9") 56 | } -------------------------------------------------------------------------------- /test/ios/AdjustTestLibrary.framework/Headers/ATLTestLibrary.h: -------------------------------------------------------------------------------- 1 | // 2 | // AdjustTestLibrary.h 3 | // AdjustTestLibrary 4 | // 5 | // Created by Pedro on 18.04.17. 6 | // Copyright © 2017 adjust. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "ATLNetworking.h" 11 | #import "ATLBlockingQueue.h" 12 | 13 | @protocol AdjustCommandDelegate 14 | @optional 15 | - (void)executeCommand:(NSString *)className 16 | methodName:(NSString *)methodName 17 | parameters:(NSDictionary *)parameters; 18 | 19 | - (void)executeCommand:(NSString *)className 20 | methodName:(NSString *)methodName 21 | jsonParameters:(NSString *)jsonParameters; 22 | 23 | - (void)executeCommandRawJson:(NSString *)json; 24 | @end 25 | 26 | @interface ATLTestLibrary : NSObject 27 | 28 | - (NSString *)currentBasePath; 29 | 30 | - (ATLBlockingQueue *)waitControlQueue; 31 | 32 | - (void)addTest:(NSString *)testName; 33 | 34 | - (void)addTestDirectory:(NSString *)testDirectory; 35 | 36 | - (void)startTestSession:(NSString *)clientSdk; 37 | 38 | - (void)resetTestLibrary; 39 | 40 | - (void)readResponse:(ATLHttpResponse *)httpResponse; 41 | 42 | - (void)addInfoToSend:(NSString *)key 43 | value:(NSString *)value; 44 | 45 | - (void)sendInfoToServer:(NSString *)basePath; 46 | 47 | - (void)signalEndWaitWithReason:(NSString *)reason; 48 | 49 | - (void)cancelTestAndGetNext; 50 | 51 | - (void)doNotExitAfterEnd; 52 | 53 | + (ATLTestLibrary *)testLibraryWithBaseUrl:(NSString *)baseUrl 54 | andControlUrl:(NSString *)controlUrl 55 | andCommandDelegate:(NSObject *)commandDelegate; 56 | @end 57 | -------------------------------------------------------------------------------- /example/ios/Runner/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /test/app/ios/Runner/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /test/ios/AdjustTestLibrary.framework/Versions/A/Headers/ATLTestLibrary.h: -------------------------------------------------------------------------------- 1 | // 2 | // AdjustTestLibrary.h 3 | // AdjustTestLibrary 4 | // 5 | // Created by Pedro on 18.04.17. 6 | // Copyright © 2017 adjust. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "ATLNetworking.h" 11 | #import "ATLBlockingQueue.h" 12 | 13 | @protocol AdjustCommandDelegate 14 | @optional 15 | - (void)executeCommand:(NSString *)className 16 | methodName:(NSString *)methodName 17 | parameters:(NSDictionary *)parameters; 18 | 19 | - (void)executeCommand:(NSString *)className 20 | methodName:(NSString *)methodName 21 | jsonParameters:(NSString *)jsonParameters; 22 | 23 | - (void)executeCommandRawJson:(NSString *)json; 24 | @end 25 | 26 | @interface ATLTestLibrary : NSObject 27 | 28 | - (NSString *)currentBasePath; 29 | 30 | - (ATLBlockingQueue *)waitControlQueue; 31 | 32 | - (void)addTest:(NSString *)testName; 33 | 34 | - (void)addTestDirectory:(NSString *)testDirectory; 35 | 36 | - (void)startTestSession:(NSString *)clientSdk; 37 | 38 | - (void)resetTestLibrary; 39 | 40 | - (void)readResponse:(ATLHttpResponse *)httpResponse; 41 | 42 | - (void)addInfoToSend:(NSString *)key 43 | value:(NSString *)value; 44 | 45 | - (void)sendInfoToServer:(NSString *)basePath; 46 | 47 | - (void)signalEndWaitWithReason:(NSString *)reason; 48 | 49 | - (void)cancelTestAndGetNext; 50 | 51 | - (void)doNotExitAfterEnd; 52 | 53 | + (ATLTestLibrary *)testLibraryWithBaseUrl:(NSString *)baseUrl 54 | andControlUrl:(NSString *)controlUrl 55 | andCommandDelegate:(NSObject *)commandDelegate; 56 | @end 57 | -------------------------------------------------------------------------------- /test/ios/AdjustTestLibrary.framework/Versions/Current/Headers/ATLTestLibrary.h: -------------------------------------------------------------------------------- 1 | // 2 | // AdjustTestLibrary.h 3 | // AdjustTestLibrary 4 | // 5 | // Created by Pedro on 18.04.17. 6 | // Copyright © 2017 adjust. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "ATLNetworking.h" 11 | #import "ATLBlockingQueue.h" 12 | 13 | @protocol AdjustCommandDelegate 14 | @optional 15 | - (void)executeCommand:(NSString *)className 16 | methodName:(NSString *)methodName 17 | parameters:(NSDictionary *)parameters; 18 | 19 | - (void)executeCommand:(NSString *)className 20 | methodName:(NSString *)methodName 21 | jsonParameters:(NSString *)jsonParameters; 22 | 23 | - (void)executeCommandRawJson:(NSString *)json; 24 | @end 25 | 26 | @interface ATLTestLibrary : NSObject 27 | 28 | - (NSString *)currentBasePath; 29 | 30 | - (ATLBlockingQueue *)waitControlQueue; 31 | 32 | - (void)addTest:(NSString *)testName; 33 | 34 | - (void)addTestDirectory:(NSString *)testDirectory; 35 | 36 | - (void)startTestSession:(NSString *)clientSdk; 37 | 38 | - (void)resetTestLibrary; 39 | 40 | - (void)readResponse:(ATLHttpResponse *)httpResponse; 41 | 42 | - (void)addInfoToSend:(NSString *)key 43 | value:(NSString *)value; 44 | 45 | - (void)sendInfoToServer:(NSString *)basePath; 46 | 47 | - (void)signalEndWaitWithReason:(NSString *)reason; 48 | 49 | - (void)cancelTestAndGetNext; 50 | 51 | - (void)doNotExitAfterEnd; 52 | 53 | + (ATLTestLibrary *)testLibraryWithBaseUrl:(NSString *)baseUrl 54 | andControlUrl:(NSString *)controlUrl 55 | andCommandDelegate:(NSObject *)commandDelegate; 56 | @end 57 | -------------------------------------------------------------------------------- /test/app/ios/Runner/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CADisableMinimumFrameDurationOnPhone 6 | 7 | CFBundleDevelopmentRegion 8 | $(DEVELOPMENT_LANGUAGE) 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | app 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | $(FLUTTER_BUILD_NAME) 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | $(FLUTTER_BUILD_NUMBER) 25 | LSRequiresIPhoneOS 26 | 27 | UIApplicationSupportsIndirectInputEvents 28 | 29 | UILaunchStoryboardName 30 | LaunchScreen 31 | UIMainStoryboardFile 32 | Main 33 | UISupportedInterfaceOrientations 34 | 35 | UIInterfaceOrientationPortrait 36 | UIInterfaceOrientationLandscapeLeft 37 | UIInterfaceOrientationLandscapeRight 38 | 39 | UISupportedInterfaceOrientations~ipad 40 | 41 | UIInterfaceOrientationPortrait 42 | UIInterfaceOrientationPortraitUpsideDown 43 | UIInterfaceOrientationLandscapeLeft 44 | UIInterfaceOrientationLandscapeRight 45 | 46 | UIViewControllerBasedStatusBarAppearance 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /example/.metadata: -------------------------------------------------------------------------------- 1 | # This file tracks properties of this Flutter project. 2 | # Used by Flutter tool to assess capabilities and perform upgrades etc. 3 | # 4 | # This file should be version controlled and should not be manually edited. 5 | 6 | version: 7 | revision: "961ce3ec82ab88237be012c24eee24f9b10591dd" 8 | channel: "master" 9 | 10 | project_type: app 11 | 12 | # Tracks metadata for the flutter migrate command 13 | migration: 14 | platforms: 15 | - platform: root 16 | create_revision: 961ce3ec82ab88237be012c24eee24f9b10591dd 17 | base_revision: 961ce3ec82ab88237be012c24eee24f9b10591dd 18 | - platform: android 19 | create_revision: 961ce3ec82ab88237be012c24eee24f9b10591dd 20 | base_revision: 961ce3ec82ab88237be012c24eee24f9b10591dd 21 | - platform: ios 22 | create_revision: 961ce3ec82ab88237be012c24eee24f9b10591dd 23 | base_revision: 961ce3ec82ab88237be012c24eee24f9b10591dd 24 | - platform: linux 25 | create_revision: 961ce3ec82ab88237be012c24eee24f9b10591dd 26 | base_revision: 961ce3ec82ab88237be012c24eee24f9b10591dd 27 | - platform: macos 28 | create_revision: 961ce3ec82ab88237be012c24eee24f9b10591dd 29 | base_revision: 961ce3ec82ab88237be012c24eee24f9b10591dd 30 | - platform: web 31 | create_revision: 961ce3ec82ab88237be012c24eee24f9b10591dd 32 | base_revision: 961ce3ec82ab88237be012c24eee24f9b10591dd 33 | - platform: windows 34 | create_revision: 961ce3ec82ab88237be012c24eee24f9b10591dd 35 | base_revision: 961ce3ec82ab88237be012c24eee24f9b10591dd 36 | 37 | # User provided section 38 | 39 | # List of Local paths (relative to this file) that should be 40 | # ignored by the migrate tool. 41 | # 42 | # Files that are not part of the templates will be ignored by default. 43 | unmanaged_files: 44 | - 'lib/main.dart' 45 | - 'ios/Runner.xcodeproj/project.pbxproj' 46 | -------------------------------------------------------------------------------- /example/ios/Runner/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CADisableMinimumFrameDurationOnPhone 6 | 7 | CFBundleDevelopmentRegion 8 | $(DEVELOPMENT_LANGUAGE) 9 | CFBundleDisplayName 10 | AdjustExample 11 | CFBundleExecutable 12 | $(EXECUTABLE_NAME) 13 | CFBundleIdentifier 14 | $(PRODUCT_BUNDLE_IDENTIFIER) 15 | CFBundleInfoDictionaryVersion 16 | 6.0 17 | CFBundleName 18 | AdjustExample 19 | CFBundlePackageType 20 | APPL 21 | CFBundleShortVersionString 22 | $(FLUTTER_BUILD_NAME) 23 | CFBundleSignature 24 | ???? 25 | CFBundleVersion 26 | $(FLUTTER_BUILD_NUMBER) 27 | LSRequiresIPhoneOS 28 | 29 | NSUserTrackingUsageDescription 30 | This is needed to access IDFA 31 | UIApplicationSupportsIndirectInputEvents 32 | 33 | UILaunchStoryboardName 34 | LaunchScreen 35 | UIMainStoryboardFile 36 | Main 37 | UISupportedInterfaceOrientations 38 | 39 | UIInterfaceOrientationPortrait 40 | UIInterfaceOrientationLandscapeLeft 41 | UIInterfaceOrientationLandscapeRight 42 | 43 | UISupportedInterfaceOrientations~ipad 44 | 45 | UIInterfaceOrientationPortrait 46 | UIInterfaceOrientationPortraitUpsideDown 47 | UIInterfaceOrientationLandscapeLeft 48 | UIInterfaceOrientationLandscapeRight 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /test/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: test_lib 2 | description: Flutter plugin for Adjust Testing Library. Intended exclusively for internal use. 3 | version: 5.4.2 4 | author: Adjust (sdk@adjust.com) 5 | 6 | environment: 7 | sdk: ">=2.12.0 <3.0.0" 8 | 9 | dependencies: 10 | flutter: 11 | sdk: flutter 12 | meta: ">=1.1.6 <2.0.0" 13 | 14 | # For information on the generic Dart part of this file, see the 15 | # following page: https://www.dartlang.org/tools/pub/pubspec 16 | 17 | # The following section is specific to Flutter. 18 | flutter: 19 | plugin: 20 | androidPackage: com.adjust.test.lib 21 | pluginClass: TestLibPlugin 22 | 23 | # we don't want to publish the test lib plugin, used only privately for integration testing 24 | publish_to: 25 | none 26 | 27 | # To add assets to your plugin package, add an assets section, like this: 28 | # assets: 29 | # - images/a_dot_burr.jpeg 30 | # - images/a_dot_ham.jpeg 31 | # 32 | # For details regarding assets in packages, see 33 | # https://flutter.io/assets-and-images/#from-packages 34 | # 35 | # An image asset can refer to one or more resolution-specific "variants", see 36 | # https://flutter.io/assets-and-images/#resolution-aware. 37 | 38 | # To add custom fonts to your plugin package, add a fonts section here, 39 | # in this "flutter" section. Each entry in this list should have a 40 | # "family" key with the font family name, and a "fonts" key with a 41 | # list giving the asset and other descriptors for the font. For 42 | # example: 43 | # fonts: 44 | # - family: Schyler 45 | # fonts: 46 | # - asset: fonts/Schyler-Regular.ttf 47 | # - asset: fonts/Schyler-Italic.ttf 48 | # style: italic 49 | # - family: Trajan Pro 50 | # fonts: 51 | # - asset: fonts/TrajanPro.ttf 52 | # - asset: fonts/TrajanPro_Bold.ttf 53 | # weight: 700 54 | # 55 | # For details regarding fonts in packages, see 56 | # https://flutter.io/custom-fonts/#from-packages 57 | -------------------------------------------------------------------------------- /lib/adjust_app_store_subscription.dart: -------------------------------------------------------------------------------- 1 | // 2 | // adjust_app_store_subscription.dart 3 | // Adjust SDK 4 | // 5 | // Created by Ugljesa Erceg (@uerceg) on 9th June 2020. 6 | // Copyright (c) 2020-Present Adjust GmbH. All rights reserved. 7 | // 8 | 9 | import 'dart:convert'; 10 | 11 | class AdjustAppStoreSubscription { 12 | final String _price; 13 | final String _currency; 14 | final String _transactionId; 15 | String? transactionDate; 16 | String? salesRegion; 17 | String? _billingStore; 18 | Map? _callbackParameters; 19 | Map? _partnerParameters; 20 | 21 | AdjustAppStoreSubscription(this._price, this._currency, this._transactionId) { 22 | _billingStore = "iOS"; 23 | _callbackParameters = new Map(); 24 | _partnerParameters = new Map(); 25 | } 26 | 27 | void addCallbackParameter(String key, String value) { 28 | _callbackParameters![key] = value; 29 | } 30 | 31 | void addPartnerParameter(String key, String value) { 32 | _partnerParameters![key] = value; 33 | } 34 | 35 | Map get toMap { 36 | Map subscriptionMap = new Map(); 37 | 38 | subscriptionMap['price'] = _price; 39 | subscriptionMap['currency'] = _currency; 40 | subscriptionMap['transactionId'] = _transactionId; 41 | if (transactionDate != null) { 42 | subscriptionMap['transactionDate'] = transactionDate; 43 | } 44 | if (salesRegion != null) { 45 | subscriptionMap['salesRegion'] = salesRegion; 46 | } 47 | if (_billingStore != null) { 48 | subscriptionMap['billingStore'] = _billingStore; 49 | } 50 | if (_callbackParameters!.length > 0) { 51 | subscriptionMap['callbackParameters'] = json.encode(_callbackParameters); 52 | } 53 | if (_partnerParameters!.length > 0) { 54 | subscriptionMap['partnerParameters'] = json.encode(_partnerParameters); 55 | } 56 | 57 | return subscriptionMap; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /lib/adjust_attribution.dart: -------------------------------------------------------------------------------- 1 | // 2 | // adjust_attribution.dart 3 | // Adjust SDK 4 | // 5 | // Created by Srdjan Tubin (@2beens) on 25th April 2018. 6 | // Copyright (c) 2018-Present Adjust GmbH. All rights reserved. 7 | // 8 | 9 | class AdjustAttribution { 10 | final String? trackerToken; 11 | final String? trackerName; 12 | final String? network; 13 | final String? campaign; 14 | final String? adgroup; 15 | final String? creative; 16 | final String? clickLabel; 17 | final String? costType; 18 | final num? costAmount; 19 | final String? costCurrency; 20 | final String? jsonResponse; 21 | // android only 22 | final String? fbInstallReferrer; 23 | 24 | AdjustAttribution({ 25 | this.trackerToken, 26 | this.trackerName, 27 | this.network, 28 | this.campaign, 29 | this.adgroup, 30 | this.creative, 31 | this.clickLabel, 32 | this.costType, 33 | this.costAmount, 34 | this.costCurrency, 35 | this.jsonResponse, 36 | this.fbInstallReferrer, 37 | }); 38 | 39 | factory AdjustAttribution.fromMap(dynamic map) { 40 | try { 41 | double parsedCostAmount = -1; 42 | try { 43 | if (map['costAmount'] != null) { 44 | parsedCostAmount = double.parse(map['costAmount']); 45 | } 46 | } catch (ex) {} 47 | 48 | return AdjustAttribution( 49 | trackerToken: map['trackerToken'], 50 | trackerName: map['trackerName'], 51 | network: map['network'], 52 | campaign: map['campaign'], 53 | adgroup: map['adgroup'], 54 | creative: map['creative'], 55 | clickLabel: map['clickLabel'], 56 | costType: map['costType'], 57 | costAmount: parsedCostAmount != -1 ? parsedCostAmount : null, 58 | costCurrency: map['costCurrency'], 59 | jsonResponse: map['jsonResponse'], 60 | fbInstallReferrer: map['fbInstallReferrer'], 61 | ); 62 | } catch (e) { 63 | throw Exception( 64 | '[AdjustFlutter]: Failed to create AdjustAttribution object from given map object. Details: ' + 65 | e.toString()); 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /lib/adjust_play_store_subscription.dart: -------------------------------------------------------------------------------- 1 | // 2 | // adjust_play_store_subscription.dart 3 | // Adjust SDK 4 | // 5 | // Created by Ugljesa Erceg (@uerceg) on 9th June 2020. 6 | // Copyright (c) 2020-Present Adjust GmbH. All rights reserved. 7 | // 8 | 9 | import 'dart:convert'; 10 | 11 | class AdjustPlayStoreSubscription { 12 | final String _price; 13 | final String _currency; 14 | final String _sku; 15 | final String _orderId; 16 | final String _signature; 17 | final String _purchaseToken; 18 | String? _billingStore; 19 | String? purchaseTime; 20 | Map? _callbackParameters; 21 | Map? _partnerParameters; 22 | 23 | AdjustPlayStoreSubscription( 24 | this._price, 25 | this._currency, 26 | this._sku, 27 | this._orderId, 28 | this._signature, 29 | this._purchaseToken) { 30 | _billingStore = "GooglePlay"; 31 | _callbackParameters = new Map(); 32 | _partnerParameters = new Map(); 33 | } 34 | 35 | void addCallbackParameter(String key, String value) { 36 | _callbackParameters![key] = value; 37 | } 38 | 39 | void addPartnerParameter(String key, String value) { 40 | _partnerParameters![key] = value; 41 | } 42 | 43 | Map get toMap { 44 | Map subscriptionMap = new Map(); 45 | 46 | subscriptionMap['price'] = _price; 47 | subscriptionMap['currency'] = _currency; 48 | subscriptionMap['sku'] = _sku; 49 | subscriptionMap['orderId'] = _orderId; 50 | subscriptionMap['signature'] = _signature; 51 | subscriptionMap['purchaseToken'] = _purchaseToken; 52 | if (_billingStore != null) { 53 | subscriptionMap['billingStore'] = _billingStore; 54 | } 55 | if (purchaseTime != null) { 56 | subscriptionMap['purchaseTime'] = purchaseTime; 57 | } 58 | if (_callbackParameters!.length > 0) { 59 | subscriptionMap['callbackParameters'] = json.encode(_callbackParameters); 60 | } 61 | if (_partnerParameters!.length > 0) { 62 | subscriptionMap['partnerParameters'] = json.encode(_partnerParameters); 63 | } 64 | 65 | return subscriptionMap; 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /lib/adjust_ad_revenue.dart: -------------------------------------------------------------------------------- 1 | // 2 | // adjust_ad_revenue.dart 3 | // Adjust SDK 4 | // 5 | // Created by Uglješa Erceg (@uerceg) on 10th June 2021. 6 | // Copyright (c) 2021-Present Adjust GmbH. All rights reserved. 7 | // 8 | 9 | import 'dart:convert'; 10 | 11 | class AdjustAdRevenue { 12 | final String _source; 13 | num? _revenue; 14 | String? _currency; 15 | num? adImpressionsCount; 16 | String? adRevenueNetwork; 17 | String? adRevenueUnit; 18 | String? adRevenuePlacement; 19 | Map? _callbackParameters; 20 | Map? _partnerParameters; 21 | 22 | AdjustAdRevenue(this._source) { 23 | _callbackParameters = new Map(); 24 | _partnerParameters = new Map(); 25 | } 26 | 27 | void setRevenue(num revenue, String currency) { 28 | _revenue = revenue; 29 | _currency = currency; 30 | } 31 | 32 | void addCallbackParameter(String key, String value) { 33 | _callbackParameters![key] = value; 34 | } 35 | 36 | void addPartnerParameter(String key, String value) { 37 | _partnerParameters![key] = value; 38 | } 39 | 40 | Map get toMap { 41 | Map adRevenueMap = {'source': _source}; 42 | 43 | if (_revenue != null) { 44 | adRevenueMap['revenue'] = _revenue.toString(); 45 | } 46 | if (_currency != null) { 47 | adRevenueMap['currency'] = _currency; 48 | } 49 | if (adImpressionsCount != null) { 50 | adRevenueMap['adImpressionsCount'] = adImpressionsCount.toString(); 51 | } 52 | if (adRevenueNetwork != null) { 53 | adRevenueMap['adRevenueNetwork'] = adRevenueNetwork; 54 | } 55 | if (adRevenueUnit != null) { 56 | adRevenueMap['adRevenueUnit'] = adRevenueUnit; 57 | } 58 | if (adRevenuePlacement != null) { 59 | adRevenueMap['adRevenuePlacement'] = adRevenuePlacement; 60 | } 61 | if (_callbackParameters!.length > 0) { 62 | adRevenueMap['callbackParameters'] = json.encode(_callbackParameters); 63 | } 64 | if (_partnerParameters!.length > 0) { 65 | adRevenueMap['partnerParameters'] = json.encode(_partnerParameters); 66 | } 67 | 68 | return adRevenueMap; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /lib/adjust_event.dart: -------------------------------------------------------------------------------- 1 | // 2 | // adjust_event.dart 3 | // Adjust SDK 4 | // 5 | // Created by Srdjan Tubin (@2beens) on 25th April 2018. 6 | // Copyright (c) 2018-Present Adjust GmbH. All rights reserved. 7 | // 8 | 9 | import 'dart:convert'; 10 | 11 | class AdjustEvent { 12 | final String _eventToken; 13 | num? _revenue; 14 | String? _currency; 15 | String? callbackId; 16 | String? deduplicationId; 17 | String? productId; 18 | Map? _callbackParameters; 19 | Map? _partnerParameters; 20 | // ios only 21 | String? transactionId; 22 | // android only 23 | String? purchaseToken; 24 | 25 | AdjustEvent(this._eventToken) { 26 | _callbackParameters = new Map(); 27 | _partnerParameters = new Map(); 28 | } 29 | 30 | void setRevenue(num revenue, String currency) { 31 | _revenue = revenue; 32 | _currency = currency; 33 | } 34 | 35 | void addCallbackParameter(String key, String value) { 36 | _callbackParameters![key] = value; 37 | } 38 | 39 | void addPartnerParameter(String key, String value) { 40 | _partnerParameters![key] = value; 41 | } 42 | 43 | Map get toMap { 44 | Map eventMap = {'eventToken': _eventToken}; 45 | 46 | if (_revenue != null) { 47 | eventMap['revenue'] = _revenue.toString(); 48 | } 49 | if (_currency != null) { 50 | eventMap['currency'] = _currency; 51 | } 52 | if (deduplicationId != null) { 53 | eventMap['deduplicationId'] = deduplicationId; 54 | } 55 | if (transactionId != null) { 56 | eventMap['transactionId'] = transactionId; 57 | } 58 | if (productId != null) { 59 | eventMap['productId'] = productId; 60 | } 61 | if (purchaseToken != null) { 62 | eventMap['purchaseToken'] = purchaseToken; 63 | } 64 | if (callbackId != null) { 65 | eventMap['callbackId'] = callbackId; 66 | } 67 | if (_callbackParameters!.length > 0) { 68 | eventMap['callbackParameters'] = json.encode(_callbackParameters); 69 | } 70 | if (_partnerParameters!.length > 0) { 71 | eventMap['partnerParameters'] = json.encode(_partnerParameters); 72 | } 73 | 74 | return eventMap; 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /example/android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 15 | 19 | 23 | 24 | 25 | 26 | 27 | 28 | 30 | 33 | 34 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /test/app/lib/command.dart: -------------------------------------------------------------------------------- 1 | // 2 | // command.dart 3 | // Adjust SDK 4 | // 5 | // Created by Srdjan Tubin (@2beens) on 25th April 2018. 6 | // Copyright (c) 2018-Present Adjust GmbH. All rights reserved. 7 | // 8 | 9 | import 'dart:convert'; 10 | import 'dart:io'; 11 | 12 | /// represents a test command received from the test library 13 | /// contains class name, method name, and parameters for execution 14 | class Command { 15 | String? _className; 16 | String? _methodName; 17 | String? _jsonParameters; 18 | Map? _parameters; 19 | 20 | /// creates a Command from a dynamic map received from the test framework 21 | Command(dynamic map) { 22 | try { 23 | _className = map['className']; 24 | _methodName = map['methodName']; 25 | 26 | if (Platform.isAndroid) { 27 | // android sends parameters as JSON string 28 | _jsonParameters = map['jsonParameters']; 29 | _parameters = json.decode(_jsonParameters!); 30 | } else { 31 | // iOS sends parameters as map directly 32 | _parameters = map['jsonParameters']; 33 | _jsonParameters = json.encode(_parameters); 34 | } 35 | } catch (e) { 36 | print('[Command]: Failed to parse command from incoming data. Error: $e'); 37 | } 38 | } 39 | 40 | /// the class name to execute the method on 41 | String? get className => _className; 42 | 43 | /// the method name to execute 44 | String? get methodName => _methodName; 45 | 46 | /// gets the first value for a given parameter key 47 | /// returns null if parameter doesn't exist or has no values 48 | String? getFirstParameterValue(String parameterKey) { 49 | final List? parameterValues = _parameters![parameterKey]; 50 | if (parameterValues == null || parameterValues.isEmpty) { 51 | return null; 52 | } 53 | return parameterValues.first; 54 | } 55 | 56 | /// gets all parameter values for a given key 57 | /// fixed typo: was "getParamteters", now "getParameters" 58 | List? getParameters(String parameterKey) { 59 | return _parameters![parameterKey]; 60 | } 61 | 62 | /// checks if the command contains a specific parameter 63 | bool containsParameter(String parameterKey) { 64 | return _parameters?[parameterKey] != null; 65 | } 66 | 67 | /// returns a string representation of the command for debugging 68 | @override 69 | String toString() { 70 | return 'Command[className: $_className, methodName: $_methodName, jsonParameters: $_jsonParameters]'; 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /example/ios/Runner/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /test/app/ios/Runner/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /test/app/android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | 18 | 22 | 26 | 31 | 35 | 36 | 37 | 38 | 39 | 40 | 42 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /example/android/gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /test/app/android/gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /test/lib/test_lib.dart: -------------------------------------------------------------------------------- 1 | // 2 | // test_lib.dart 3 | // Adjust SDK 4 | // 5 | // Created by Srdjan Tubin (@2beens) on 25th April 2018. 6 | // Copyright (c) 2018-Present Adjust GmbH. All rights reserved. 7 | // 8 | 9 | import 'package:flutter/services.dart'; 10 | 11 | typedef void ExecuteCommandHandler(final dynamic callArgs); 12 | 13 | class TestLib { 14 | static const MethodChannel _channel = 15 | const MethodChannel('com.adjust.test.lib/api'); 16 | static ExecuteCommandHandler? _executeCommandHandler; 17 | 18 | static void setExecuteCommandHalder(ExecuteCommandHandler handler) { 19 | _executeCommandHandler = handler; 20 | _channel.setMethodCallHandler((MethodCall call) async { 21 | try { 22 | switch (call.method) { 23 | case 'adj-test-execute': 24 | if (_executeCommandHandler != null) { 25 | _executeCommandHandler!(call.arguments); 26 | } 27 | break; 28 | default: 29 | throw new UnsupportedError( 30 | '[TestLibrary]: Received unknown native method: ${call.method}'); 31 | } 32 | } catch (e) { 33 | print(e.toString()); 34 | } 35 | }); 36 | } 37 | 38 | static void init(String baseUrl, String controlUrl) { 39 | _channel 40 | .invokeMethod('init', {'baseUrl': baseUrl, 'controlUrl': controlUrl}); 41 | } 42 | 43 | static void startTestSession(String clientSdk) { 44 | _channel.invokeMethod('startTestSession', {'clientSdk': clientSdk}); 45 | } 46 | 47 | static void addInfoToSend(String key, String? value) { 48 | if (value == null) { 49 | print( 50 | '[TestLibrary]: Skip adding info to server for key [$key]. Value is null.'); 51 | return; 52 | } 53 | _channel.invokeMethod('addInfoToSend', {'key': key, 'value': value}); 54 | } 55 | 56 | static void sendInfoToServer(String? basePath) { 57 | if (basePath == null) { 58 | print( 59 | '[TestLibrary]: Skip sending info to server with base path set to null.'); 60 | return; 61 | } 62 | _channel.invokeMethod('sendInfoToServer', {'basePath': basePath}); 63 | } 64 | 65 | static void addTest(String? testName) { 66 | if (testName == null) { 67 | print('[TestLibrary]: Skip adding test with null value for the name.'); 68 | return; 69 | } 70 | _channel.invokeMethod('addTest', {'testName': testName}); 71 | } 72 | 73 | static void addTestDirectory(String? testDirectory) { 74 | if (testDirectory == null) { 75 | print( 76 | '[TestLibrary]: Skip adding test directory with null value for the name.'); 77 | return; 78 | } 79 | _channel.invokeMethod('addTestDirectory', {'testDirectory': testDirectory}); 80 | } 81 | 82 | static void doNotExitAfterEnd() { 83 | _channel.invokeMethod('doNotExitAfterEnd'); 84 | } 85 | 86 | static void setTestConnectionOptions() { 87 | _channel.invokeMethod('setTestConnectionOptions'); 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /example/README.md: -------------------------------------------------------------------------------- 1 | # Adjust Flutter Example App 2 | 3 | A comprehensive demonstration application showcasing the full functionality of the Adjust Flutter SDK. This app provides interactive examples of all major SDK features and serves as a reference implementation. 4 | 5 | ## Features 6 | 7 | - **Event Tracking**: Demonstrate simple, revenue, callback, and partner events 8 | - **Device Information**: Access Google AdID, Adjust identifier, IDFA, and attribution data 9 | - **SDK Management**: Toggle SDK state and check enabled status 10 | - **Real-time Callbacks**: Live demonstration of attribution, session, and event callbacks 11 | - **Modern UI**: Beautiful, intuitive interface following Adjust design guidelines 12 | 13 | ## Getting Started 14 | 15 | 1. **Prerequisites**: Ensure Flutter is installed and configured 16 | 2. **Install Dependencies**: Run `flutter pub get` in this directory 17 | 3. **Run the App**: Use `flutter run` to start the example application 18 | 4. **Explore Features**: Tap buttons to test different SDK functionalities 19 | 20 | ## App Structure 21 | 22 | - **Event Tracking Section**: Test different types of events with various parameters 23 | - **Device Information Section**: Retrieve device-specific identifiers and attribution 24 | - **SDK Control Section**: Manage SDK state and verify functionality 25 | 26 | ## SDK Configuration 27 | 28 | The app is configured with: 29 | - **App Token**: `2fm9gkqubvpc` (sandbox environment) 30 | - **Environment**: Sandbox mode for safe testing 31 | - **Log Level**: Verbose logging for detailed insights 32 | - **Callbacks**: Comprehensive callback setup for all event types 33 | 34 | ## Event Tokens 35 | 36 | The following test event tokens are configured: 37 | - **Simple Event**: `g3mfiw` - Basic event tracking 38 | - **Revenue Event**: `a4fd35` - Event with revenue data 39 | - **Callback Event**: `34vgg9` - Event with callback parameters 40 | - **Partner Event**: `w788qs` - Event with partner parameters 41 | 42 | ## Usage Examples 43 | 44 | ### Track a Simple Event 45 | ```dart 46 | final event = AdjustEvent('g3mfiw'); 47 | Adjust.trackEvent(event); 48 | ``` 49 | 50 | ### Track Revenue Event 51 | ```dart 52 | final event = AdjustEvent('a4fd35'); 53 | event.setRevenue(100.0, 'EUR'); 54 | event.transactionId = 'DummyTransactionId'; 55 | Adjust.trackEvent(event); 56 | ``` 57 | 58 | ### Get Attribution Data 59 | ```dart 60 | Adjust.getAttribution().then((attribution) { 61 | // Handle attribution data 62 | }); 63 | ``` 64 | 65 | ## Callbacks 66 | 67 | The app demonstrates all available callback types: 68 | - **Attribution Callback**: Triggered when attribution data changes 69 | - **Session Success/Failure**: Monitor session tracking status 70 | - **Event Success/Failure**: Track event delivery status 71 | - **Deferred Deeplinks**: Handle deferred deeplink scenarios 72 | - **SKAN Updates**: iOS StoreKit Ad Network updates 73 | 74 | ## Testing 75 | 76 | Use this app to: 77 | - Verify SDK integration in your development environment 78 | - Test different event tracking scenarios 79 | - Understand callback behavior and data structure 80 | - Validate attribution and device identifier retrieval 81 | -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "20x20", 5 | "idiom" : "iphone", 6 | "filename" : "Icon-App-20x20@2x.png", 7 | "scale" : "2x" 8 | }, 9 | { 10 | "size" : "20x20", 11 | "idiom" : "iphone", 12 | "filename" : "Icon-App-20x20@3x.png", 13 | "scale" : "3x" 14 | }, 15 | { 16 | "size" : "29x29", 17 | "idiom" : "iphone", 18 | "filename" : "Icon-App-29x29@1x.png", 19 | "scale" : "1x" 20 | }, 21 | { 22 | "size" : "29x29", 23 | "idiom" : "iphone", 24 | "filename" : "Icon-App-29x29@2x.png", 25 | "scale" : "2x" 26 | }, 27 | { 28 | "size" : "29x29", 29 | "idiom" : "iphone", 30 | "filename" : "Icon-App-29x29@3x.png", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "size" : "40x40", 35 | "idiom" : "iphone", 36 | "filename" : "Icon-App-40x40@2x.png", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "size" : "40x40", 41 | "idiom" : "iphone", 42 | "filename" : "Icon-App-40x40@3x.png", 43 | "scale" : "3x" 44 | }, 45 | { 46 | "size" : "60x60", 47 | "idiom" : "iphone", 48 | "filename" : "Icon-App-60x60@2x.png", 49 | "scale" : "2x" 50 | }, 51 | { 52 | "size" : "60x60", 53 | "idiom" : "iphone", 54 | "filename" : "Icon-App-60x60@3x.png", 55 | "scale" : "3x" 56 | }, 57 | { 58 | "size" : "20x20", 59 | "idiom" : "ipad", 60 | "filename" : "Icon-App-20x20@1x.png", 61 | "scale" : "1x" 62 | }, 63 | { 64 | "size" : "20x20", 65 | "idiom" : "ipad", 66 | "filename" : "Icon-App-20x20@2x.png", 67 | "scale" : "2x" 68 | }, 69 | { 70 | "size" : "29x29", 71 | "idiom" : "ipad", 72 | "filename" : "Icon-App-29x29@1x.png", 73 | "scale" : "1x" 74 | }, 75 | { 76 | "size" : "29x29", 77 | "idiom" : "ipad", 78 | "filename" : "Icon-App-29x29@2x.png", 79 | "scale" : "2x" 80 | }, 81 | { 82 | "size" : "40x40", 83 | "idiom" : "ipad", 84 | "filename" : "Icon-App-40x40@1x.png", 85 | "scale" : "1x" 86 | }, 87 | { 88 | "size" : "40x40", 89 | "idiom" : "ipad", 90 | "filename" : "Icon-App-40x40@2x.png", 91 | "scale" : "2x" 92 | }, 93 | { 94 | "size" : "76x76", 95 | "idiom" : "ipad", 96 | "filename" : "Icon-App-76x76@1x.png", 97 | "scale" : "1x" 98 | }, 99 | { 100 | "size" : "76x76", 101 | "idiom" : "ipad", 102 | "filename" : "Icon-App-76x76@2x.png", 103 | "scale" : "2x" 104 | }, 105 | { 106 | "size" : "83.5x83.5", 107 | "idiom" : "ipad", 108 | "filename" : "Icon-App-83.5x83.5@2x.png", 109 | "scale" : "2x" 110 | }, 111 | { 112 | "size" : "1024x1024", 113 | "idiom" : "ios-marketing", 114 | "filename" : "Icon-App-1024x1024@1x.png", 115 | "scale" : "1x" 116 | } 117 | ], 118 | "info" : { 119 | "version" : 1, 120 | "author" : "xcode" 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /test/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "20x20", 5 | "idiom" : "iphone", 6 | "filename" : "Icon-App-20x20@2x.png", 7 | "scale" : "2x" 8 | }, 9 | { 10 | "size" : "20x20", 11 | "idiom" : "iphone", 12 | "filename" : "Icon-App-20x20@3x.png", 13 | "scale" : "3x" 14 | }, 15 | { 16 | "size" : "29x29", 17 | "idiom" : "iphone", 18 | "filename" : "Icon-App-29x29@1x.png", 19 | "scale" : "1x" 20 | }, 21 | { 22 | "size" : "29x29", 23 | "idiom" : "iphone", 24 | "filename" : "Icon-App-29x29@2x.png", 25 | "scale" : "2x" 26 | }, 27 | { 28 | "size" : "29x29", 29 | "idiom" : "iphone", 30 | "filename" : "Icon-App-29x29@3x.png", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "size" : "40x40", 35 | "idiom" : "iphone", 36 | "filename" : "Icon-App-40x40@2x.png", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "size" : "40x40", 41 | "idiom" : "iphone", 42 | "filename" : "Icon-App-40x40@3x.png", 43 | "scale" : "3x" 44 | }, 45 | { 46 | "size" : "60x60", 47 | "idiom" : "iphone", 48 | "filename" : "Icon-App-60x60@2x.png", 49 | "scale" : "2x" 50 | }, 51 | { 52 | "size" : "60x60", 53 | "idiom" : "iphone", 54 | "filename" : "Icon-App-60x60@3x.png", 55 | "scale" : "3x" 56 | }, 57 | { 58 | "size" : "20x20", 59 | "idiom" : "ipad", 60 | "filename" : "Icon-App-20x20@1x.png", 61 | "scale" : "1x" 62 | }, 63 | { 64 | "size" : "20x20", 65 | "idiom" : "ipad", 66 | "filename" : "Icon-App-20x20@2x.png", 67 | "scale" : "2x" 68 | }, 69 | { 70 | "size" : "29x29", 71 | "idiom" : "ipad", 72 | "filename" : "Icon-App-29x29@1x.png", 73 | "scale" : "1x" 74 | }, 75 | { 76 | "size" : "29x29", 77 | "idiom" : "ipad", 78 | "filename" : "Icon-App-29x29@2x.png", 79 | "scale" : "2x" 80 | }, 81 | { 82 | "size" : "40x40", 83 | "idiom" : "ipad", 84 | "filename" : "Icon-App-40x40@1x.png", 85 | "scale" : "1x" 86 | }, 87 | { 88 | "size" : "40x40", 89 | "idiom" : "ipad", 90 | "filename" : "Icon-App-40x40@2x.png", 91 | "scale" : "2x" 92 | }, 93 | { 94 | "size" : "76x76", 95 | "idiom" : "ipad", 96 | "filename" : "Icon-App-76x76@1x.png", 97 | "scale" : "1x" 98 | }, 99 | { 100 | "size" : "76x76", 101 | "idiom" : "ipad", 102 | "filename" : "Icon-App-76x76@2x.png", 103 | "scale" : "2x" 104 | }, 105 | { 106 | "size" : "83.5x83.5", 107 | "idiom" : "ipad", 108 | "filename" : "Icon-App-83.5x83.5@2x.png", 109 | "scale" : "2x" 110 | }, 111 | { 112 | "size" : "1024x1024", 113 | "idiom" : "ios-marketing", 114 | "filename" : "Icon-App-1024x1024@1x.png", 115 | "scale" : "1x" 116 | } 117 | ], 118 | "info" : { 119 | "version" : 1, 120 | "author" : "xcode" 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /test/app/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 31 | 32 | 38 | 39 | 40 | 41 | 42 | 43 | 55 | 57 | 63 | 64 | 65 | 66 | 72 | 74 | 80 | 81 | 82 | 83 | 85 | 86 | 89 | 90 | 91 | -------------------------------------------------------------------------------- /example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 31 | 32 | 38 | 39 | 40 | 41 | 44 | 50 | 51 | 52 | 53 | 54 | 66 | 68 | 74 | 75 | 76 | 77 | 83 | 85 | 91 | 92 | 93 | 94 | 96 | 97 | 100 | 101 | 102 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # ============================================= 2 | # ADJUST FLUTTER SDK - COMPREHENSIVE .GITIGNORE 3 | # ============================================= 4 | # This file handles all ignore patterns for the entire project. 5 | # Organized by category for easy maintenance. 6 | 7 | # ===================== 8 | # SYSTEM & EDITOR FILES 9 | # ===================== 10 | # miscellaneous system files 11 | *.class 12 | *.lock 13 | *.log 14 | *.pyc 15 | *.swp 16 | .DS_Store 17 | .atom/ 18 | .build/ 19 | .buildlog/ 20 | .history 21 | .svn/ 22 | .swiftpm/ 23 | migrate_working_dir/ 24 | 25 | # intellij related 26 | *.iml 27 | *.ipr 28 | *.iws 29 | .idea/ 30 | 31 | # visual studio code related 32 | .classpath 33 | .project 34 | .settings/ 35 | .vscode/ 36 | 37 | # ============== 38 | # FLUTTER & DART 39 | # ============== 40 | # flutter/dart/pub related 41 | **/doc/api/ 42 | **/ios/Flutter/.last_build_id 43 | .dart_tool/ 44 | .flutter-plugins 45 | .flutter-plugins-dependencies 46 | **/generated_plugin_registrant.dart 47 | .packages 48 | .packages.generated 49 | .pub-cache/ 50 | .pub/ 51 | build/ 52 | coverage/ 53 | flutter_*.png 54 | linked_*.ds 55 | unlinked.ds 56 | unlinked_spec.ds 57 | 58 | # ==================== 59 | # ANDROID BUILD SYSTEM 60 | # ==================== 61 | # android build artifacts 62 | **/android/.gradle 63 | **/android/captures/ 64 | **/android/local.properties 65 | **/android/**/GeneratedPluginRegistrant.java 66 | **/android/key.properties 67 | **/android/app/debug 68 | **/android/app/profile 69 | **/android/app/release 70 | *.jks 71 | *.keystore 72 | 73 | # android studio will place build artifacts here 74 | /android/app/debug 75 | /android/app/profile 76 | /android/app/release 77 | 78 | # ================= 79 | # IOS BUILD SYSTEM 80 | # ================= 81 | # ios/xcode related 82 | **/ios/**/*.mode1v3 83 | **/ios/**/*.mode2v3 84 | **/ios/**/*.moved-aside 85 | **/ios/**/*.pbxuser 86 | **/ios/**/*.perspectivev3 87 | **/ios/**/*sync/ 88 | **/ios/**/.sconsign.dblite 89 | **/ios/**/.tags* 90 | **/ios/**/.vagrant/ 91 | **/ios/**/DerivedData/ 92 | **/ios/**/Icon? 93 | **/ios/**/Pods/ 94 | **/ios/**/.symlinks/ 95 | **/ios/Podfile.lock 96 | **/ios/**/profile 97 | **/ios/**/xcuserdata 98 | **/ios/.generated/ 99 | **/ios/Flutter/App.framework 100 | **/ios/Flutter/Flutter.framework 101 | **/ios/Flutter/Flutter.podspec 102 | **/ios/Flutter/Generated.xcconfig 103 | **/ios/Flutter/ephemeral 104 | **/ios/Flutter/app.flx 105 | **/ios/Flutter/app.zip 106 | **/ios/Flutter/flutter_assets/ 107 | **/ios/Flutter/flutter_export_environment.sh 108 | **/ios/ServiceDefinitions.json 109 | **/ios/Runner/GeneratedPluginRegistrant.* 110 | **/ios/**/dgph 111 | 112 | # macos 113 | **/macos/Flutter/GeneratedPluginRegistrant.swift 114 | 115 | # ==================== 116 | # FLUTTER SDK SPECIFIC 117 | # ==================== 118 | # flutter repo-specific (for SDK development) 119 | /bin/cache/ 120 | /bin/internal/bootstrap.bat 121 | /bin/internal/bootstrap.sh 122 | /bin/mingit/ 123 | /dev/benchmarks/mega_gallery/ 124 | /dev/bots/.recipe_deps 125 | /dev/bots/android_tools/ 126 | /dev/devicelab/ABresults*.json 127 | /dev/docs/doc/ 128 | /dev/docs/flutter.docs.zip 129 | /dev/docs/lib/ 130 | /dev/docs/pubspec.yaml 131 | /dev/integration_tests/**/xcuserdata 132 | /dev/integration_tests/**/Pods 133 | /packages/flutter/coverage/ 134 | version 135 | analysis_benchmark.json 136 | 137 | # ========================= 138 | # BUILD ARTIFACTS & SYMBOLS 139 | # ========================= 140 | # symbolication related 141 | app.*.symbols 142 | 143 | # obfuscation related 144 | app.*.map.json 145 | 146 | # ======================================= 147 | # EXCEPTIONS - FILES THAT MUST BE TRACKED 148 | # ======================================= 149 | # these files are essential for building the apps after cloning 150 | 151 | # allow default ios files 152 | !**/ios/**/default.mode1v3 153 | !**/ios/**/default.mode2v3 154 | !**/ios/**/default.pbxuser 155 | !**/ios/**/default.perspectivev3 156 | 157 | # allow essential flutter tools test data 158 | !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages 159 | !/dev/ci/**/Gemfile.lock 160 | 161 | # allow gradle build system files for example and test apps 162 | # these are essential for building without local gradle installation 163 | !example/android/gradlew 164 | !example/android/gradlew.bat 165 | !example/android/gradle/wrapper/gradle-wrapper.jar 166 | !test/app/android/gradlew 167 | !test/app/android/gradlew.bat 168 | !test/app/android/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /example/android/gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # Attempt to set APP_HOME 46 | # Resolve links: $0 may be a link 47 | PRG="$0" 48 | # Need this for relative symlinks. 49 | while [ -h "$PRG" ] ; do 50 | ls=`ls -ld "$PRG"` 51 | link=`expr "$ls" : '.*-> \(.*\)$'` 52 | if expr "$link" : '/.*' > /dev/null; then 53 | PRG="$link" 54 | else 55 | PRG=`dirname "$PRG"`"/$link" 56 | fi 57 | done 58 | SAVED="`pwd`" 59 | cd "`dirname \"$PRG\"`/" >/dev/null 60 | APP_HOME="`pwd -P`" 61 | cd "$SAVED" >/dev/null 62 | 63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 64 | 65 | # Determine the Java command to use to start the JVM. 66 | if [ -n "$JAVA_HOME" ] ; then 67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 68 | # IBM's JDK on AIX uses strange locations for the executables 69 | JAVACMD="$JAVA_HOME/jre/sh/java" 70 | else 71 | JAVACMD="$JAVA_HOME/bin/java" 72 | fi 73 | if [ ! -x "$JAVACMD" ] ; then 74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 75 | 76 | Please set the JAVA_HOME variable in your environment to match the 77 | location of your Java installation." 78 | fi 79 | else 80 | JAVACMD="java" 81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 82 | 83 | Please set the JAVA_HOME variable in your environment to match the 84 | location of your Java installation." 85 | fi 86 | 87 | # Increase the maximum file descriptors if we can. 88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 89 | MAX_FD_LIMIT=`ulimit -H -n` 90 | if [ $? -eq 0 ] ; then 91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 92 | MAX_FD="$MAX_FD_LIMIT" 93 | fi 94 | ulimit -n $MAX_FD 95 | if [ $? -ne 0 ] ; then 96 | warn "Could not set maximum file descriptor limit: $MAX_FD" 97 | fi 98 | else 99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 100 | fi 101 | fi 102 | 103 | # For Darwin, add options to specify how the application appears in the dock 104 | if $darwin; then 105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 106 | fi 107 | 108 | # For Cygwin, switch paths to Windows format before running java 109 | if $cygwin ; then 110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 112 | JAVACMD=`cygpath --unix "$JAVACMD"` 113 | 114 | # We build the pattern for arguments to be converted via cygpath 115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 116 | SEP="" 117 | for dir in $ROOTDIRSRAW ; do 118 | ROOTDIRS="$ROOTDIRS$SEP$dir" 119 | SEP="|" 120 | done 121 | OURCYGPATTERN="(^($ROOTDIRS))" 122 | # Add a user-defined pattern to the cygpath arguments 123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 125 | fi 126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 127 | i=0 128 | for arg in "$@" ; do 129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 131 | 132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 134 | else 135 | eval `echo args$i`="\"$arg\"" 136 | fi 137 | i=$((i+1)) 138 | done 139 | case $i in 140 | (0) set -- ;; 141 | (1) set -- "$args0" ;; 142 | (2) set -- "$args0" "$args1" ;; 143 | (3) set -- "$args0" "$args1" "$args2" ;; 144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 150 | esac 151 | fi 152 | 153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 154 | function splitJvmOpts() { 155 | JVM_OPTS=("$@") 156 | } 157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 159 | 160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 161 | -------------------------------------------------------------------------------- /test/app/android/gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # Attempt to set APP_HOME 46 | # Resolve links: $0 may be a link 47 | PRG="$0" 48 | # Need this for relative symlinks. 49 | while [ -h "$PRG" ] ; do 50 | ls=`ls -ld "$PRG"` 51 | link=`expr "$ls" : '.*-> \(.*\)$'` 52 | if expr "$link" : '/.*' > /dev/null; then 53 | PRG="$link" 54 | else 55 | PRG=`dirname "$PRG"`"/$link" 56 | fi 57 | done 58 | SAVED="`pwd`" 59 | cd "`dirname \"$PRG\"`/" >/dev/null 60 | APP_HOME="`pwd -P`" 61 | cd "$SAVED" >/dev/null 62 | 63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 64 | 65 | # Determine the Java command to use to start the JVM. 66 | if [ -n "$JAVA_HOME" ] ; then 67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 68 | # IBM's JDK on AIX uses strange locations for the executables 69 | JAVACMD="$JAVA_HOME/jre/sh/java" 70 | else 71 | JAVACMD="$JAVA_HOME/bin/java" 72 | fi 73 | if [ ! -x "$JAVACMD" ] ; then 74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 75 | 76 | Please set the JAVA_HOME variable in your environment to match the 77 | location of your Java installation." 78 | fi 79 | else 80 | JAVACMD="java" 81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 82 | 83 | Please set the JAVA_HOME variable in your environment to match the 84 | location of your Java installation." 85 | fi 86 | 87 | # Increase the maximum file descriptors if we can. 88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 89 | MAX_FD_LIMIT=`ulimit -H -n` 90 | if [ $? -eq 0 ] ; then 91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 92 | MAX_FD="$MAX_FD_LIMIT" 93 | fi 94 | ulimit -n $MAX_FD 95 | if [ $? -ne 0 ] ; then 96 | warn "Could not set maximum file descriptor limit: $MAX_FD" 97 | fi 98 | else 99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 100 | fi 101 | fi 102 | 103 | # For Darwin, add options to specify how the application appears in the dock 104 | if $darwin; then 105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 106 | fi 107 | 108 | # For Cygwin, switch paths to Windows format before running java 109 | if $cygwin ; then 110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 112 | JAVACMD=`cygpath --unix "$JAVACMD"` 113 | 114 | # We build the pattern for arguments to be converted via cygpath 115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 116 | SEP="" 117 | for dir in $ROOTDIRSRAW ; do 118 | ROOTDIRS="$ROOTDIRS$SEP$dir" 119 | SEP="|" 120 | done 121 | OURCYGPATTERN="(^($ROOTDIRS))" 122 | # Add a user-defined pattern to the cygpath arguments 123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 125 | fi 126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 127 | i=0 128 | for arg in "$@" ; do 129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 131 | 132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 134 | else 135 | eval `echo args$i`="\"$arg\"" 136 | fi 137 | i=$((i+1)) 138 | done 139 | case $i in 140 | (0) set -- ;; 141 | (1) set -- "$args0" ;; 142 | (2) set -- "$args0" "$args1" ;; 143 | (3) set -- "$args0" "$args1" "$args2" ;; 144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 150 | esac 151 | fi 152 | 153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 154 | function splitJvmOpts() { 155 | JVM_OPTS=("$@") 156 | } 157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 159 | 160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 161 | -------------------------------------------------------------------------------- /test/ios/Classes/TestLibPlugin.m: -------------------------------------------------------------------------------- 1 | // 2 | // TestLibPlugin.m 3 | // Adjust SDK 4 | // 5 | // Created by Srdjan Tubin (@2beens) on 1st October 2018. 6 | // Copyright (c) 2018-Present Adjust GmbH. All rights reserved. 7 | // 8 | 9 | #import "TestLibPlugin.h" 10 | #import "AdjustCommandExecutor.h" 11 | 12 | @interface TestLibPlugin () 13 | 14 | @property(nonatomic, retain) FlutterMethodChannel *channel; 15 | @property(nonatomic, strong) ATLTestLibrary *testLibrary; 16 | @property(nonatomic, strong) AdjustCommandExecutor *adjustCommandExecutor; 17 | 18 | @end 19 | 20 | @implementation TestLibPlugin 21 | 22 | + (void)registerWithRegistrar:(NSObject *)registrar { 23 | FlutterMethodChannel *channel = [FlutterMethodChannel methodChannelWithName:@"com.adjust.test.lib/api" 24 | binaryMessenger:[registrar messenger]]; 25 | TestLibPlugin *instance = [[TestLibPlugin alloc] init]; 26 | instance.channel = channel; 27 | [registrar addMethodCallDelegate:instance channel:channel]; 28 | } 29 | 30 | // TODO: check if needed 31 | - (void)dealloc { 32 | [self.channel setMethodCallHandler:nil]; 33 | self.channel = nil; 34 | } 35 | 36 | - (void)handleMethodCall:(FlutterMethodCall *)call result:(FlutterResult)result { 37 | if ([@"init" isEqualToString:call.method]) { 38 | [self init:call withResult:result]; 39 | } else if ([@"startTestSession" isEqualToString:call.method]) { 40 | [self startTestSession:call withResult:result]; 41 | } else if ([@"addInfoToSend" isEqualToString:call.method]) { 42 | [self addInfoToSend:call withResult:result]; 43 | } else if ([@"sendInfoToServer" isEqualToString:call.method]) { 44 | [self sendInfoToServer:call withResult:result]; 45 | } else if ([@"addTest" isEqualToString:call.method]) { 46 | [self addTest:call withResult:result]; 47 | } else if ([@"addTestDirectory" isEqualToString:call.method]) { 48 | [self addTestDirectory:call withResult:result]; 49 | } else if ([@"doNotExitAfterEnd" isEqualToString:call.method]) { 50 | [self doNotExitAfterEnd:call withResult:result]; 51 | } else if ([@"setTestConnectionOptions" isEqualToString:call.method]) { 52 | // do nothing, Android specific method 53 | } else { 54 | result(FlutterMethodNotImplemented); 55 | } 56 | } 57 | 58 | - (void)init:(FlutterMethodCall *)call withResult:(FlutterResult)result { 59 | NSLog(@"Initializing test lib bridge ..."); 60 | NSString *baseUrl = call.arguments[@"baseUrl"]; 61 | NSString *controlUrl = call.arguments[@"controlUrl"]; 62 | if (![self isFieldValid:baseUrl] || ![self isFieldValid:controlUrl]) { 63 | result([FlutterError errorWithCode:@"WRONG-ARGS" 64 | message:@"Arguments null or wrong (missing argument >baseUrl< or >controlUrl<)" 65 | details:nil]); 66 | return; 67 | } 68 | 69 | self.adjustCommandExecutor = [[AdjustCommandExecutor alloc]initWithMethodChannel:self.channel]; 70 | self.testLibrary = [ATLTestLibrary testLibraryWithBaseUrl:baseUrl andControlUrl:controlUrl andCommandDelegate:self.adjustCommandExecutor]; 71 | NSLog(@"TestLib bridge initialized."); 72 | } 73 | 74 | - (void)startTestSession:(FlutterMethodCall *)call withResult:(FlutterResult)result { 75 | if ([self testLibOk:result] == NO) { 76 | NSLog(@"Error. Cannot start test session. Test lib bridge not initialized."); 77 | return; 78 | } 79 | 80 | NSString *clientSdk = call.arguments[@"clientSdk"]; 81 | if (![self isFieldValid:clientSdk]) { 82 | result([FlutterError errorWithCode:@"WRONG-CLIENT-SDK" 83 | message:@"Arguments null or wrong (missing argument >clientSdk<" 84 | details:nil]); 85 | return; 86 | } 87 | 88 | NSLog(@"Starting test session. Client SDK %@", clientSdk); 89 | [self.testLibrary startTestSession:clientSdk]; 90 | } 91 | 92 | - (void)addInfoToSend:(FlutterMethodCall *)call withResult:(FlutterResult)result { 93 | if ([self testLibOk:result] == NO) { 94 | return; 95 | } 96 | NSString *key = call.arguments[@"key"]; 97 | NSString *value = call.arguments[@"value"]; 98 | [self.testLibrary addInfoToSend:key value:value]; 99 | } 100 | 101 | - (void)sendInfoToServer:(FlutterMethodCall *)call withResult:(FlutterResult)result { 102 | if ([self testLibOk:result] == NO) { 103 | return; 104 | } 105 | NSString *basePath = call.arguments[@"basePath"]; 106 | [self.testLibrary sendInfoToServer:basePath]; 107 | } 108 | 109 | - (void)addTest:(FlutterMethodCall *)call withResult:(FlutterResult)result { 110 | if ([self testLibOk:result] == NO) { 111 | return; 112 | } 113 | NSString *testName = call.arguments[@"testName"]; 114 | [self.testLibrary addTest:testName]; 115 | } 116 | 117 | - (void)addTestDirectory:(FlutterMethodCall *)call withResult:(FlutterResult)result { 118 | if ([self testLibOk:result] == NO) { 119 | return; 120 | } 121 | NSString *testDirectory = call.arguments[@"testDirectory"]; 122 | [self.testLibrary addTestDirectory:testDirectory]; 123 | } 124 | 125 | - (void)doNotExitAfterEnd:(FlutterMethodCall *)call withResult:(FlutterResult)result { 126 | if ([self testLibOk:result] == NO) { 127 | return; 128 | } 129 | [self.testLibrary doNotExitAfterEnd]; 130 | } 131 | 132 | // Helper methods 133 | 134 | - (BOOL)testLibOk:(FlutterResult)result { 135 | if (self.testLibrary == nil) { 136 | result([FlutterError errorWithCode:@"TEST-LIB-NIL" 137 | message:@"Test Library not initialized. Call >init< first." 138 | details:nil]); 139 | return NO; 140 | } 141 | return YES; 142 | } 143 | 144 | - (BOOL)isFieldValid:(NSObject *)field { 145 | if (field == nil) { 146 | return NO; 147 | } 148 | 149 | // Check if its an instance of the singleton NSNull 150 | if ([field isKindOfClass:[NSNull class]]) { 151 | return NO; 152 | } 153 | 154 | // If field can be converted to a string, check if it has any content. 155 | NSString *str = [NSString stringWithFormat:@"%@", field]; 156 | if (str != nil) { 157 | if ([str length] == 0) { 158 | return NO; 159 | } 160 | } 161 | 162 | return YES; 163 | } 164 | 165 | @end 166 | -------------------------------------------------------------------------------- /test/android/src/main/java/com/adjust/test/lib/TestLibPlugin.java: -------------------------------------------------------------------------------- 1 | // 2 | // TestLibPlugin.java 3 | // Adjust SDK 4 | // 5 | // Created by Srdjan Tubin (@2beens) on 1st October 2018. 6 | // Copyright (c) 2018-Present Adjust GmbH. All rights reserved. 7 | // 8 | 9 | package com.adjust.test.lib; 10 | 11 | import android.content.Context; 12 | import android.os.Handler; 13 | import android.os.Looper; 14 | import android.util.Log; 15 | 16 | import androidx.annotation.NonNull; 17 | 18 | import io.flutter.embedding.engine.plugins.FlutterPlugin; 19 | import io.flutter.plugin.common.MethodCall; 20 | import io.flutter.plugin.common.MethodChannel; 21 | import io.flutter.plugin.common.MethodChannel.MethodCallHandler; 22 | import io.flutter.plugin.common.MethodChannel.Result; 23 | 24 | import com.adjust.test.ICommandJsonListener; 25 | import com.adjust.test.TestLibrary; 26 | import com.adjust.test_options.TestConnectionOptions; 27 | 28 | import java.util.HashMap; 29 | import java.util.Map; 30 | 31 | public class TestLibPlugin implements FlutterPlugin, MethodCallHandler { 32 | private static String TAG = "TestLibPlugin"; 33 | private TestLibrary testLibrary = null; 34 | private MethodChannel channel; 35 | private Context applicationContext; 36 | 37 | public TestLibPlugin() {} 38 | 39 | @Override 40 | public void onAttachedToEngine(@NonNull FlutterPluginBinding binding) { 41 | applicationContext = binding.getApplicationContext(); 42 | channel = new MethodChannel(binding.getBinaryMessenger(), "com.adjust.test.lib/api"); 43 | channel.setMethodCallHandler(this); 44 | } 45 | 46 | @Override 47 | public void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) { 48 | applicationContext = null; 49 | if (channel != null) { 50 | channel.setMethodCallHandler(null); 51 | } 52 | channel = null; 53 | } 54 | 55 | @Override 56 | public void onMethodCall(MethodCall call, Result result) { 57 | switch (call.method) { 58 | case "init": 59 | init(call, result); 60 | break; 61 | case "startTestSession": 62 | startTestSession(call, result); 63 | break; 64 | case "addInfoToSend": 65 | addInfoToSend(call, result); 66 | break; 67 | case "sendInfoToServer": 68 | sendInfoToServer(call, result); 69 | break; 70 | case "addTest": 71 | addTest(call, result); 72 | break; 73 | case "addTestDirectory": 74 | addTestDirectory(call, result); 75 | break; 76 | case "doNotExitAfterEnd": 77 | doNotExitAfterEnd(result); 78 | break; 79 | case "setTestConnectionOptions": 80 | setTestConnectionOptions(result); 81 | break; 82 | default: 83 | error("Not implemented method: " + call.method); 84 | result.notImplemented(); 85 | break; 86 | } 87 | } 88 | 89 | private void init(final MethodCall call, final Result result) { 90 | Map paramsMap = (Map)call.arguments; 91 | if (!paramsMap.containsKey("baseUrl") || !paramsMap.containsKey("controlUrl")) { 92 | result.error("0", "Arguments null or wrong (missing 'baseUrl' or 'controlUrl')", null); 93 | return; 94 | } 95 | 96 | String baseUrl = (String) paramsMap.get("baseUrl"); 97 | String controlUrl = (String) paramsMap.get("controlUrl"); 98 | final String dartMethodName = "adj-test-execute"; 99 | testLibrary = new TestLibrary(baseUrl, controlUrl, applicationContext, new ICommandJsonListener() { 100 | @Override 101 | public void executeCommand(String className, String methodName, String jsonParameters) { 102 | final HashMap methodParams = new HashMap(); 103 | methodParams.put("className", className); 104 | methodParams.put("methodName", methodName); 105 | methodParams.put("jsonParameters", jsonParameters); 106 | 107 | log("Trying to call a method 'adj-test-execute' with: " + className + "." + methodName); 108 | Handler mainHandler = new Handler(Looper.getMainLooper()); 109 | Runnable myRunnable = new Runnable() { 110 | @Override 111 | public void run() { 112 | channel.invokeMethod(dartMethodName, methodParams); 113 | } 114 | }; 115 | mainHandler.post(myRunnable); 116 | } 117 | }); 118 | result.success(null); 119 | } 120 | 121 | private void startTestSession(final MethodCall call, final Result result) { 122 | if (testLibrary == null) { 123 | result.error("0", "Test Library not initialized. Call 'init' method first.", null); 124 | return; 125 | } 126 | 127 | Map paramsMap = (Map)call.arguments; 128 | if (!paramsMap.containsKey("clientSdk")) { 129 | result.error("0", "Arguments null or wrong (missing argument 'clientSdk'", null); 130 | return; 131 | } 132 | 133 | String clientSdk = (String) paramsMap.get("clientSdk"); 134 | testLibrary.startTestSession(clientSdk); 135 | result.success(null); 136 | } 137 | 138 | private void addInfoToSend(final MethodCall call, final Result result) { 139 | if (testLibrary == null) { 140 | result.error("0", "Test Library not initialized. Call 'init' method first.", null); 141 | return; 142 | } 143 | 144 | Map paramsMap = (Map)call.arguments; 145 | String key = (String) paramsMap.get("key"); 146 | String value = (String) paramsMap.get("value"); 147 | testLibrary.addInfoToSend(key, value); 148 | result.success(null); 149 | } 150 | 151 | private void sendInfoToServer(final MethodCall call, final Result result) { 152 | if (testLibrary == null) { 153 | result.error("0", "Test Library not initialized. Call 'init' method first.", null); 154 | return; 155 | } 156 | 157 | Map paramsMap = (Map)call.arguments; 158 | String basePath = (String) paramsMap.get("basePath"); 159 | testLibrary.sendInfoToServer(basePath); 160 | result.success(null); 161 | } 162 | 163 | private void addTest(final MethodCall call, final Result result) { 164 | if (testLibrary == null) { 165 | result.error("0", "Test Library not initialized. Call 'init' method first.", null); 166 | return; 167 | } 168 | 169 | Map paramsMap = (Map)call.arguments; 170 | String testName = (String) paramsMap.get("testName"); 171 | assert testName != null; 172 | testLibrary.addTest(testName); 173 | result.success(null); 174 | } 175 | 176 | private void addTestDirectory(final MethodCall call, final Result result) { 177 | if (testLibrary == null) { 178 | result.error("0", "Test Library not initialized. Call 'init' method first.", null); 179 | return; 180 | } 181 | 182 | Map paramsMap = (Map)call.arguments; 183 | String testDirectory = (String) paramsMap.get("testDirectory"); 184 | assert testDirectory != null; 185 | testLibrary.addTestDirectory(testDirectory); 186 | result.success(null); 187 | } 188 | 189 | private void doNotExitAfterEnd(final Result result) { 190 | if (testLibrary == null) { 191 | result.error("0", "Test Library not initialized. Call 'init' method first.", null); 192 | return; 193 | } 194 | 195 | testLibrary.doNotExitAfterEnd(); 196 | result.success(null); 197 | } 198 | 199 | private void setTestConnectionOptions(final Result result) { 200 | if (testLibrary == null) { 201 | result.error("0", "Test Library not initialized. Call 'init' method first.", null); 202 | return; 203 | } 204 | 205 | TestConnectionOptions.setTestConnectionOptions(); 206 | result.success(null); 207 | } 208 | 209 | private void log(String message) { 210 | Log.d(TAG, message); 211 | } 212 | 213 | private void error(String message) { 214 | Log.e(TAG, message); 215 | } 216 | } 217 | -------------------------------------------------------------------------------- /test/app/lib/main.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:adjust_sdk/adjust.dart'; 4 | import 'package:flutter/material.dart'; 5 | import 'package:test_app/command.dart'; 6 | import 'package:test_app/command_executor.dart'; 7 | import 'package:test_lib/test_lib.dart'; 8 | 9 | void main() { 10 | runApp(const AdjustTestApp()); 11 | } 12 | 13 | /// main application widget for Adjust Flutter Test App 14 | class AdjustTestApp extends StatelessWidget { 15 | const AdjustTestApp({super.key}); 16 | 17 | @override 18 | Widget build(BuildContext context) { 19 | return MaterialApp( 20 | title: 'Adjust Test App', 21 | debugShowCheckedModeBanner: false, 22 | theme: ThemeData( 23 | primarySwatch: Colors.blue, 24 | visualDensity: VisualDensity.adaptivePlatformDensity, 25 | useMaterial3: true, 26 | ), 27 | home: const TestHomePage(), 28 | ); 29 | } 30 | } 31 | 32 | /// home page containing the test session controls 33 | class TestHomePage extends StatefulWidget { 34 | const TestHomePage({super.key}); 35 | 36 | @override 37 | State createState() => _TestHomePageState(); 38 | } 39 | 40 | class _TestHomePageState extends State { 41 | // configuration constants 42 | static const String _defaultAddress = '192.168.86.241'; 43 | static const String _androidProtocol = 'https'; 44 | static const String _androidPort = '8443'; 45 | static const String _iosProtocol = 'http'; 46 | static const String _iosPort = '8080'; 47 | static const String _wsPort = '1987'; 48 | 49 | // adjust brand colors 50 | static const Color _adjustNavy = Color(0xFF1B2951); 51 | static const Color _adjustNavyLight = Color(0xFF2A3A5C); 52 | 53 | String? _overwriteUrl; 54 | late String _controlUrl; 55 | late CommandExecutor _commandExecutor; 56 | 57 | @override 58 | void initState() { 59 | super.initState(); 60 | _initializeTestEnvironment(); 61 | } 62 | 63 | /// initialize the test environment with platform-specific URLs 64 | void _initializeTestEnvironment() { 65 | if (Platform.isAndroid) { 66 | _overwriteUrl = '$_androidProtocol://$_defaultAddress:$_androidPort'; 67 | } else { 68 | _overwriteUrl = '$_iosProtocol://$_defaultAddress:$_iosPort'; 69 | } 70 | _controlUrl = 'ws://$_defaultAddress:$_wsPort'; 71 | 72 | // initialize command executor 73 | _commandExecutor = CommandExecutor(_overwriteUrl); 74 | 75 | // initialize test library with command handler 76 | TestLib.setExecuteCommandHalder(_handleTestCommand); 77 | TestLib.init(_overwriteUrl!, _controlUrl); 78 | } 79 | 80 | /// handle incoming test commands 81 | void _handleTestCommand(dynamic callArgs) { 82 | print('[AdjustTestApp]: Command handler triggered'); 83 | final command = Command(callArgs); 84 | print('[AdjustTestApp]: Executing ${command.className}.${command.methodName}'); 85 | _commandExecutor.executeCommand(command); 86 | } 87 | 88 | /// start a new test session 89 | void _startTestSession() { 90 | Adjust.getSdkVersion().then((sdkVersion) { 91 | print('[AdjustTestApp]: Starting test session with SDK version: $sdkVersion'); 92 | // TestLib.addTestDirectory("getters"); 93 | TestLib.startTestSession(sdkVersion); 94 | }); 95 | } 96 | 97 | @override 98 | Widget build(BuildContext context) { 99 | return Scaffold( 100 | appBar: AppBar( 101 | title: const Text( 102 | 'Adjust Test App', 103 | style: TextStyle( 104 | fontWeight: FontWeight.w600, 105 | color: Colors.white, 106 | ), 107 | ), 108 | centerTitle: true, 109 | backgroundColor: _adjustNavy, 110 | elevation: 0, 111 | ), 112 | body: Container( 113 | width: double.infinity, 114 | height: double.infinity, 115 | decoration: const BoxDecoration( 116 | gradient: LinearGradient( 117 | begin: Alignment.topCenter, 118 | end: Alignment.bottomCenter, 119 | colors: [_adjustNavy, _adjustNavyLight], 120 | ), 121 | ), 122 | child: SafeArea( 123 | child: Padding( 124 | padding: const EdgeInsets.all(24.0), 125 | child: Column( 126 | mainAxisAlignment: MainAxisAlignment.center, 127 | children: [ 128 | // app icon or logo space 129 | Container( 130 | width: 80, 131 | height: 80, 132 | decoration: BoxDecoration( 133 | color: Colors.white.withOpacity(0.1), 134 | borderRadius: BorderRadius.circular(16), 135 | ), 136 | child: const Icon( 137 | Icons.science_outlined, 138 | size: 40, 139 | color: Colors.white, 140 | ), 141 | ), 142 | const SizedBox(height: 32), 143 | 144 | // title and description 145 | const Text( 146 | 'Test Session', 147 | style: TextStyle( 148 | fontSize: 28, 149 | fontWeight: FontWeight.bold, 150 | color: Colors.white, 151 | ), 152 | ), 153 | const SizedBox(height: 8), 154 | Text( 155 | 'Tap the button below to start testing\nthe Adjust SDK functionality', 156 | textAlign: TextAlign.center, 157 | style: TextStyle( 158 | fontSize: 16, 159 | color: Colors.white.withOpacity(0.8), 160 | height: 1.4, 161 | ), 162 | ), 163 | const SizedBox(height: 48), 164 | 165 | // main action button 166 | _buildStartButton(), 167 | 168 | const SizedBox(height: 24), 169 | 170 | // connection info 171 | _buildConnectionInfo(), 172 | ], 173 | ), 174 | ), 175 | ), 176 | ), 177 | ); 178 | } 179 | 180 | /// build the main start test session button 181 | Widget _buildStartButton() { 182 | return SizedBox( 183 | width: double.infinity, 184 | height: 56, 185 | child: ElevatedButton( 186 | onPressed: _startTestSession, 187 | style: ElevatedButton.styleFrom( 188 | backgroundColor: Colors.white, 189 | foregroundColor: _adjustNavy, 190 | shape: RoundedRectangleBorder( 191 | borderRadius: BorderRadius.circular(28), 192 | ), 193 | elevation: 8, 194 | shadowColor: Colors.black.withOpacity(0.3), 195 | ), 196 | child: const Row( 197 | mainAxisAlignment: MainAxisAlignment.center, 198 | children: [ 199 | Icon(Icons.play_arrow_rounded, size: 24), 200 | SizedBox(width: 8), 201 | Text( 202 | 'Start Test Session', 203 | style: TextStyle( 204 | fontSize: 18, 205 | fontWeight: FontWeight.w600, 206 | ), 207 | ), 208 | ], 209 | ), 210 | ), 211 | ); 212 | } 213 | 214 | /// build connection information display 215 | Widget _buildConnectionInfo() { 216 | return Container( 217 | padding: const EdgeInsets.all(16), 218 | decoration: BoxDecoration( 219 | color: Colors.white.withOpacity(0.1), 220 | borderRadius: BorderRadius.circular(12), 221 | border: Border.all( 222 | color: Colors.white.withOpacity(0.2), 223 | width: 1, 224 | ), 225 | ), 226 | child: Column( 227 | crossAxisAlignment: CrossAxisAlignment.start, 228 | children: [ 229 | Row( 230 | children: [ 231 | Icon( 232 | Icons.info_outline, 233 | size: 16, 234 | color: Colors.white.withOpacity(0.7), 235 | ), 236 | const SizedBox(width: 8), 237 | Text( 238 | 'Connection Info', 239 | style: TextStyle( 240 | fontSize: 14, 241 | fontWeight: FontWeight.w600, 242 | color: Colors.white.withOpacity(0.9), 243 | ), 244 | ), 245 | ], 246 | ), 247 | const SizedBox(height: 8), 248 | _buildInfoRow('Platform', Platform.isAndroid ? 'Android' : 'iOS'), 249 | _buildInfoRow('Test URL', _overwriteUrl ?? 'Not set'), 250 | _buildInfoRow('Control URL', _controlUrl), 251 | ], 252 | ), 253 | ); 254 | } 255 | 256 | /// build an information row 257 | Widget _buildInfoRow(String label, String value) { 258 | return Padding( 259 | padding: const EdgeInsets.symmetric(vertical: 2), 260 | child: Row( 261 | crossAxisAlignment: CrossAxisAlignment.start, 262 | children: [ 263 | SizedBox( 264 | width: 80, 265 | child: Text( 266 | '$label:', 267 | style: TextStyle( 268 | fontSize: 12, 269 | color: Colors.white.withOpacity(0.6), 270 | ), 271 | ), 272 | ), 273 | Expanded( 274 | child: Text( 275 | value, 276 | style: TextStyle( 277 | fontSize: 12, 278 | color: Colors.white.withOpacity(0.8), 279 | fontFamily: 'monospace', 280 | ), 281 | ), 282 | ), 283 | ], 284 | ), 285 | ); 286 | } 287 | } 288 | -------------------------------------------------------------------------------- /lib/adjust.dart: -------------------------------------------------------------------------------- 1 | // 2 | // adjust_sdk.dart 3 | // Adjust SDK 4 | // 5 | // Created by Srdjan Tubin (@2beens) on 25th April 2018. 6 | // Copyright (c) 2018-Present Adjust GmbH. All rights reserved. 7 | // 8 | 9 | import 'dart:async'; 10 | 11 | import 'package:adjust_sdk/adjust_ad_revenue.dart'; 12 | import 'package:adjust_sdk/adjust_app_store_subscription.dart'; 13 | import 'package:adjust_sdk/adjust_app_store_purchase.dart'; 14 | import 'package:adjust_sdk/adjust_attribution.dart'; 15 | import 'package:adjust_sdk/adjust_config.dart'; 16 | import 'package:adjust_sdk/adjust_event.dart'; 17 | import 'package:adjust_sdk/adjust_play_store_purchase.dart'; 18 | import 'package:adjust_sdk/adjust_play_store_subscription.dart'; 19 | import 'package:adjust_sdk/adjust_purchase_verification_result.dart'; 20 | import 'package:adjust_sdk/adjust_third_party_sharing.dart'; 21 | import 'package:adjust_sdk/adjust_deeplink.dart'; 22 | 23 | import 'package:flutter/services.dart'; 24 | import 'package:meta/meta.dart'; 25 | 26 | class Adjust { 27 | static const String _sdkPrefix = 'flutter5.5.0'; 28 | static const MethodChannel _channel = 29 | const MethodChannel('com.adjust.sdk/api'); 30 | 31 | // common 32 | 33 | static void initSdk(AdjustConfig config) { 34 | config.sdkPrefix = _sdkPrefix; 35 | _channel.invokeMethod('initSdk', config.toMap); 36 | } 37 | 38 | static void trackEvent(AdjustEvent event) { 39 | _channel.invokeMethod('trackEvent', event.toMap); 40 | } 41 | 42 | static void trackAdRevenue(AdjustAdRevenue adRevenue) { 43 | _channel.invokeMethod('trackAdRevenue', adRevenue.toMap); 44 | } 45 | 46 | static void trackThirdPartySharing( 47 | AdjustThirdPartySharing thirdPartySharing) { 48 | _channel.invokeMethod('trackThirdPartySharing', thirdPartySharing.toMap); 49 | } 50 | 51 | static void trackMeasurementConsent(bool measurementConsent) { 52 | _channel.invokeMethod( 53 | 'trackMeasurementConsent', {'measurementConsent': measurementConsent}); 54 | } 55 | 56 | static void processDeeplink(AdjustDeeplink deeplink) { 57 | _channel.invokeMethod('processDeeplink', deeplink.toMap); 58 | } 59 | 60 | static Future processAndResolveDeeplink(AdjustDeeplink deeplink) async { 61 | final resolvedLink = 62 | await _channel.invokeMethod('processAndResolveDeeplink', deeplink.toMap); 63 | return resolvedLink; 64 | } 65 | 66 | static void setPushToken(String token) { 67 | _channel.invokeMethod('setPushToken', {'pushToken': token}); 68 | } 69 | 70 | static void gdprForgetMe() { 71 | _channel.invokeMethod('gdprForgetMe'); 72 | } 73 | 74 | static void enable() { 75 | _channel.invokeMethod('enable'); 76 | } 77 | 78 | static void disable() { 79 | _channel.invokeMethod('disable'); 80 | } 81 | 82 | static void switchToOfflineMode() { 83 | _channel.invokeMethod('switchToOfflineMode'); 84 | } 85 | 86 | static void switchBackToOnlineMode() { 87 | _channel.invokeMethod('switchBackToOnlineMode'); 88 | } 89 | 90 | static void addGlobalCallbackParameter(String key, String value) { 91 | _channel.invokeMethod( 92 | 'addGlobalCallbackParameter', {'key': key, 'value': value}); 93 | } 94 | 95 | static void addGlobalPartnerParameter(String key, String value) { 96 | _channel.invokeMethod( 97 | 'addGlobalPartnerParameter', {'key': key, 'value': value}); 98 | } 99 | 100 | static void removeGlobalCallbackParameter(String key) { 101 | _channel.invokeMethod('removeGlobalCallbackParameter', {'key': key}); 102 | } 103 | 104 | static void removeGlobalPartnerParameter(String key) { 105 | _channel.invokeMethod('removeGlobalPartnerParameter', {'key': key}); 106 | } 107 | 108 | static void removeGlobalCallbackParameters() { 109 | _channel.invokeMethod('removeGlobalCallbackParameters'); 110 | } 111 | 112 | static void removeGlobalPartnerParameters() { 113 | _channel.invokeMethod('removeGlobalPartnerParameters'); 114 | } 115 | 116 | static void endFirstSessionDelay() { 117 | _channel.invokeMethod('endFirstSessionDelay'); 118 | } 119 | 120 | static void enableCoppaComplianceInDelay() { 121 | _channel.invokeMethod('enableCoppaComplianceInDelay'); 122 | } 123 | 124 | static void disableCoppaComplianceInDelay() { 125 | _channel.invokeMethod('disableCoppaComplianceInDelay'); 126 | } 127 | 128 | static void setExternalDeviceIdInDelay(String externalDeviceId) { 129 | _channel.invokeMethod('setExternalDeviceIdInDelay',{'externalDeviceId': externalDeviceId}); 130 | } 131 | 132 | static Future isEnabled() async { 133 | final bool isEnabled = await _channel.invokeMethod('isEnabled'); 134 | return isEnabled; 135 | } 136 | 137 | static Future getAdid() async { 138 | final String? adid = await _channel.invokeMethod('getAdid'); 139 | return adid; 140 | } 141 | 142 | static Future getAdidWithTimeout(int timeoutInMilliseconds) async { 143 | final String? adid = await _channel.invokeMethod('getAdidWithTimeout', {'timeoutInMilliseconds': timeoutInMilliseconds}); 144 | return adid; 145 | } 146 | 147 | static Future getAttribution() async { 148 | final dynamic attributionMap = 149 | await _channel.invokeMethod('getAttribution'); 150 | return AdjustAttribution.fromMap(attributionMap); 151 | } 152 | 153 | static Future getAttributionWithTimeout(int timeoutInMilliseconds) async { 154 | final dynamic attributionMap = 155 | await _channel.invokeMethod('getAttributionWithTimeout', {'timeoutInMilliseconds': timeoutInMilliseconds}); 156 | if (attributionMap == null) { 157 | return null; 158 | } 159 | return AdjustAttribution.fromMap(attributionMap); 160 | } 161 | 162 | static Future getLastDeeplink() async { 163 | final String? deeplink = await _channel.invokeMethod('getLastDeeplink'); 164 | return deeplink; 165 | } 166 | 167 | static Future getSdkVersion() async { 168 | final String sdkVersion = await _channel.invokeMethod('getSdkVersion'); 169 | return _sdkPrefix + '@' + sdkVersion; 170 | } 171 | 172 | // ios only 173 | 174 | static void trackAppStoreSubscription( 175 | AdjustAppStoreSubscription subscription) { 176 | _channel.invokeMethod('trackAppStoreSubscription', subscription.toMap); 177 | } 178 | 179 | static Future verifyAppStorePurchase( 180 | AdjustAppStorePurchase purchase) async { 181 | final dynamic appStorePurchaseMap = 182 | await _channel.invokeMethod('verifyAppStorePurchase', purchase.toMap); 183 | return AdjustPurchaseVerificationResult.fromMap(appStorePurchaseMap); 184 | } 185 | 186 | static Future verifyAndTrackAppStorePurchase( 187 | AdjustEvent event) async { 188 | final dynamic appStorePurchaseMap = 189 | await _channel.invokeMethod('verifyAndTrackAppStorePurchase', event.toMap); 190 | return AdjustPurchaseVerificationResult.fromMap(appStorePurchaseMap); 191 | } 192 | 193 | static Future requestAppTrackingAuthorization() async { 194 | final num status = await _channel 195 | .invokeMethod('requestAppTrackingAuthorization'); 196 | return status; 197 | } 198 | 199 | static Future updateSkanConversionValue(int conversionValue, String coarseValue, bool lockWindow) async { 200 | final String? error = await _channel.invokeMethod('updateSkanConversionValue', { 201 | 'conversionValue': conversionValue, 202 | 'coarseValue': coarseValue, 203 | 'lockWindow': lockWindow 204 | }); 205 | return error; 206 | } 207 | 208 | static Future getIdfa() async { 209 | final String? idfa = await _channel.invokeMethod('getIdfa'); 210 | return idfa; 211 | } 212 | 213 | static Future getIdfv() async { 214 | final String? idfv = await _channel.invokeMethod('getIdfv'); 215 | return idfv; 216 | } 217 | 218 | static Future getAppTrackingAuthorizationStatus() async { 219 | final int authorizationStatus = 220 | await _channel.invokeMethod('getAppTrackingAuthorizationStatus'); 221 | return authorizationStatus; 222 | } 223 | 224 | // android only 225 | 226 | static void trackPlayStoreSubscription( 227 | AdjustPlayStoreSubscription subscription) { 228 | _channel.invokeMethod('trackPlayStoreSubscription', subscription.toMap); 229 | } 230 | 231 | static Future verifyPlayStorePurchase( 232 | AdjustPlayStorePurchase purchase) async { 233 | final dynamic playStorePurchaseMap = 234 | await _channel.invokeMethod('verifyPlayStorePurchase', purchase.toMap); 235 | return AdjustPurchaseVerificationResult.fromMap(playStorePurchaseMap); 236 | } 237 | 238 | static Future verifyAndTrackPlayStorePurchase( 239 | AdjustEvent event) async { 240 | final dynamic playStorePurchaseMap = 241 | await _channel.invokeMethod('verifyAndTrackPlayStorePurchase', event.toMap); 242 | return AdjustPurchaseVerificationResult.fromMap(playStorePurchaseMap); 243 | } 244 | 245 | static void enablePlayStoreKidsComplianceInDelay() { 246 | _channel.invokeMethod('enablePlayStoreKidsComplianceInDelay'); 247 | } 248 | 249 | static void disablePlayStoreKidsComplianceInDelay() { 250 | _channel.invokeMethod('disablePlayStoreKidsComplianceInDelay'); 251 | } 252 | 253 | static Future getAmazonAdId() async { 254 | final String? amazonAdId = await _channel.invokeMethod('getAmazonAdId'); 255 | return amazonAdId; 256 | } 257 | 258 | static Future getGoogleAdId() async { 259 | final String? googleAdId = await _channel.invokeMethod('getGoogleAdId'); 260 | return googleAdId; 261 | } 262 | 263 | // for testing purposes only, do not use in production! 264 | 265 | @visibleForTesting 266 | static void onResume() { 267 | _channel.invokeMethod('onResume'); 268 | } 269 | 270 | @visibleForTesting 271 | static void onPause() { 272 | _channel.invokeMethod('onPause'); 273 | } 274 | 275 | @visibleForTesting 276 | static void setTestOptions(final dynamic testOptions) { 277 | _channel.invokeMethod('setTestOptions', testOptions); 278 | } 279 | } 280 | --------------------------------------------------------------------------------