Skip to content
Merged
Show file tree
Hide file tree
Changes from 81 commits
Commits
Show all changes
99 commits
Select commit Hold shift + click to select a range
3de7299
[DELIVERY-125863] Migrate Flutter plugin to AppsFlyer SDK 7 RPC archi…
af-dudka Jul 29, 2026
d2af13c
[DELIVERY-125863] Fix SDK 7 install-referrer docs and dart format.
af-dudka Jul 29, 2026
effc2d8
[DELIVERY-125863] Align plugin release version with SDK 7.0.1.
af-dudka Jul 29, 2026
51b2141
[DELIVERY-125863] Migrate Flutter plugin to AppsFlyer SDK 7 RPC archi…
af-dudka Aug 10, 2026
69886e8
[DELIVERY-125863] Align internal-docs with SDK 7 RPC implementation a…
af-dudka Aug 10, 2026
78dcf05
[DELIVERY-125863] Apply dart format to CI-failing files
af-dudka Aug 10, 2026
c5f84c2
[DELIVERY-125863] Migrate native plugin implementations to Swift and …
af-dudka Aug 10, 2026
8d4df77
[DELIVERY-125863] Fix Android native events lost after engine teardown
af-dudka Aug 11, 2026
4ddcfa7
[DELIVERY-125863] Harden Android RPC dispatch, lifecycle teardown, an…
af-dudka Aug 11, 2026
655d1bc
[DELIVERY-125863] Bound the iOS pending-event buffer
af-dudka Aug 11, 2026
2820349
[DELIVERY-125863] Replace iOS Objective-C shim with main-actor-checke…
af-dudka Aug 12, 2026
bd8f144
[DELIVERY-125863] Guard iOS event-handler and Purchase Connector tear…
af-dudka Aug 12, 2026
b152ef8
[DELIVERY-125863] Remove pendingLaunchOptions and main-thread RPC com…
af-dudka Aug 12, 2026
a7a6c6d
[DELIVERY-125863] Return RPC data map from unwrapValue default instea…
af-dudka Aug 12, 2026
1d46d56
[DELIVERY-125863] Always enqueue af-events delivery on the main queue…
af-dudka Aug 12, 2026
bb3c54d
[DELIVERY-125863] Guard iOS RPC completions and markBridgeReady after…
af-dudka Aug 12, 2026
84292aa
[DELIVERY-125863] Serialize AppsFlyerAttribution queue state on the m…
af-dudka Aug 12, 2026
d6a4ba5
[DELIVERY-125863] Log AppsFlyerAttribution RPC failures and reset que…
af-dudka Aug 12, 2026
a72cf9d
[DELIVERY-125863] Document ephemeral FlutterFramework SPM dependency …
af-dudka Aug 12, 2026
63c3686
[DELIVERY-125863] Fix iOS plugin version bump in release workflows af…
af-dudka Aug 12, 2026
58bc115
[DELIVERY-125863] Throw AppsFlyerException when generateInviteLink re…
af-dudka Aug 12, 2026
cbb55f1
[DELIVERY-125863] Throw AppsFlyerException when getSdkVersion returns…
af-dudka Aug 12, 2026
6d3b19c
[DELIVERY-125863] Throw AppsFlyerException on unexpected RPC result t…
af-dudka Aug 12, 2026
a9954cf
[DELIVERY-125863] Scope the Android RPC handler to the process so eng…
af-dudka Aug 12, 2026
522afb3
[DELIVERY-125863] Fail fast on missing or non-string af-events event …
af-dudka Aug 12, 2026
ab5883b
[DELIVERY-125863] Test every AFMediationNetwork logAdRevenue RPC mapping
af-dudka Aug 12, 2026
502b2bd
[DELIVERY-125863] Test pluginVersion returns the compiled PLUGIN_VERS…
af-dudka Aug 12, 2026
f61a729
[DELIVERY-125863] Forward init parameters to native RPC without Dart-…
af-dudka Aug 12, 2026
6c9a0d2
[DELIVERY-125863] Route symmetric platform-only getters and setters t…
af-dudka Aug 12, 2026
33d49d0
[DELIVERY-125863] Split RPC helpers and enforce non-null native replies
af-dudka Aug 12, 2026
790f3df
[DELIVERY-125863] Forward setSharingFilterForPartners clear requests …
af-dudka Aug 12, 2026
cc3b053
[DELIVERY-125863] Forward setConsentData payloads to native RPC witho…
af-dudka Aug 12, 2026
2037d31
[DELIVERY-125863] Format appsflyer_sdk_test.dart for CI
af-dudka Aug 12, 2026
177cd43
[DELIVERY-125863] Replace event streams with callback-based register*…
af-dudka Aug 13, 2026
1905fd7
[DELIVERY-125863] Bump Gradle wrapper to 8.14 for Flutter minimum
af-dudka Aug 13, 2026
70dbd6b
[DELIVERY-125863] Bump Android Gradle Plugin to 8.11.1 for Flutter mi…
af-dudka Aug 13, 2026
7f6917e
[DELIVERY-125863] Bump example Android Gradle, AGP, and Kotlin for Fl…
af-dudka Aug 13, 2026
bb5c3ef
[DELIVERY-125863] Fix iOS CI: bump example deployment target to 15 an…
af-dudka Aug 13, 2026
d2e60ed
[DELIVERY-125863] Hold replayed af-events until their listener registers
af-dudka Aug 13, 2026
ebbabdc
[DELIVERY-125863] Serialize iOS engine-detach teardown on the main queue
af-dudka Aug 13, 2026
ba62ba4
[DELIVERY-125863] ci: run Android native unit tests in the PR gate
af-dudka Aug 13, 2026
460885a
fix(dart): remove platform gates so the RPC contract decides method s…
af-dudka Aug 13, 2026
50153e5
[DELIVERY-125863] Add explicit RpcEnvelope parser with fail-fast cont…
af-dudka Aug 13, 2026
1667a07
[DELIVERY-125863] Drop awaited RPC results after engine detach
af-dudka Aug 13, 2026
c2773b1
[DELIVERY-125863] Remove unused androidx.appcompat dependency
af-dudka Aug 13, 2026
5983751
[DELIVERY-125863] Remove public markBridgeReady that skipped ownershi…
af-dudka Aug 13, 2026
dc80410
[DELIVERY-125863] Document multi-engine single-listener limitation
af-dudka Aug 13, 2026
d606578
[DELIVERY-125863] Document non-finite eventValues; keep iOS serializa…
af-dudka Aug 13, 2026
22ebb8b
[DELIVERY-125863] Clean up low-severity review findings
af-dudka Aug 13, 2026
7257844
[DELIVERY-125863] Fix dart format and document removed Obj-C headers
af-dudka Aug 13, 2026
4864248
[DELIVERY-125863] Fix exclude-connector typo and remove empty iOS tes…
af-dudka Aug 13, 2026
d3fcdcc
[DELIVERY-125863] Drop refused af-events instead of blocking Android …
af-dudka Aug 17, 2026
820e217
[DELIVERY-125863] Buffer af-events during engine detach instead of si…
af-dudka Aug 17, 2026
082ae09
[DELIVERY-125863] Run Android init RPC off the platform thread via bl…
af-dudka Aug 17, 2026
8b34410
[DELIVERY-125863] Fix stale streams wording in Android bridge KDoc
af-dudka Aug 17, 2026
2d455cd
[DELIVERY-125863] Cover getHostName/getHostPrefix null RPC replies in…
af-dudka Aug 17, 2026
007f4c4
[DELIVERY-125863] Stop treating all af-events sink failures as DROP o…
af-dudka Aug 18, 2026
d305e95
[DELIVERY-125863] Log af-events buffer overflow on Android and iOS
af-dudka Aug 18, 2026
0cae36f
[DELIVERY-125863] Clarify AppsFlyerEventBus threading contract in KDoc
af-dudka Aug 18, 2026
f71455c
[DELIVERY-125863] Return PLUGIN_DETACHED for post-detach executeRpc o…
af-dudka Aug 18, 2026
4bfdb5a
[DELIVERY-125863] Dispose stale Purchase Connector attachment outside…
af-dudka Aug 18, 2026
4972ca2
[DELIVERY-125863] Roll back Dart listener slots when register*Listene…
af-dudka Aug 18, 2026
e3104da
[DELIVERY-125863] Isolate throwing listener callbacks in AppsFlyerLis…
af-dudka Aug 18, 2026
00bbc52
[DELIVERY-125863] Log handleLaunchOptions RPC failures on iOS
af-dudka Aug 18, 2026
33b48ee
[DELIVERY-125863] Rename AppsFlyerRpcExecutor to RpcRequestRunner on …
af-dudka Aug 18, 2026
8fa6233
[DELIVERY-125863] Keep Dart listener slots when unregister*Listener R…
af-dudka Aug 18, 2026
c6b70fe
[DELIVERY-125863] Align Android bridge with RPC 7.0.12 and fix Activi…
af-dudka Aug 19, 2026
5529692
[DELIVERY-125863] dart format
af-dudka Aug 19, 2026
a47e419
[DELIVERY-125863] Require all four bool fields in setConsentData
af-dudka Aug 20, 2026
05c98cb
[DELIVERY-125863] Align plugin with RPC 7.0.12/7.0.13 and finalize SD…
af-dudka Aug 25, 2026
4c6368b
[DELIVERY-125863] Restore working listeners when re-registration RPC …
af-dudka Aug 25, 2026
c17c73c
[DELIVERY-125863] Fix Purchase Connector silent drops on partial Play…
af-dudka Aug 25, 2026
ab1e603
[DELIVERY-125863] Raise Flutter floor to 3.35, fix Purchase Connector…
af-dudka Aug 25, 2026
48b5955
[DELIVERY-125863] Remove internal channel names from public docs, dro…
af-dudka Aug 25, 2026
87d7455
[DELIVERY-125863] Redact event payloads from plugin logs
af-dudka Aug 25, 2026
8d1c6d0
[DELIVERY-125863] Analyze the example app in CI and make infos fatal
af-dudka Aug 25, 2026
72cb95e
[DELIVERY-125863] Remove dead Android build config and the empty pods…
af-dudka Aug 25, 2026
4fc8bea
[DELIVERY-125863] Clear the three Swift compiler warnings in the iOS …
af-dudka Aug 25, 2026
69bf5dd
[DELIVERY-125863] Create dummy example/.env before CI analyze step
af-dudka Aug 25, 2026
9f02b1e
[DELIVERY-125863] Reject background-isolate calls across the SDK and …
af-dudka Aug 25, 2026
93a33eb
[DELIVERY-125863] Silence plugin logs in release unless enableDebug i…
af-dudka Aug 25, 2026
c90e8d0
[DELIVERY-125863] Roll back enableDebug on failure, clarify logging d…
af-dudka Aug 26, 2026
75ee0aa
[DELIVERY-125863] Release stale iOS Purchase Connector registration a…
af-dudka Aug 26, 2026
fec7fb8
[DELIVERY-125863] Recover the af-events subscription on end of stream…
af-dudka Aug 26, 2026
44f53dd
[DELIVERY-125863] Call handleLaunchOptions on the SDK directly, drop …
af-dudka Aug 26, 2026
bc0690f
[DELIVERY-125863] Forward iOS deep-link lifecycle callbacks straight …
af-dudka Aug 26, 2026
7e3aef7
[DELIVERY-125863] Fix inaccurate timeout, isolate, and version claims…
af-dudka Aug 26, 2026
f8f0852
[DELIVERY-125863] Correct stale plugin-logging and dependency claims …
af-dudka Aug 26, 2026
44abcb4
[DELIVERY-125863] Bump the plugin version from 7.0.1 to 7.0.2
af-dudka Aug 26, 2026
8f9c832
[DELIVERY-125863] Badge
af-dudka Aug 26, 2026
c6915a8
[DELIVERY-125863] Guard iOS Purchase Connector payload serialization
af-dudka Aug 26, 2026
bb50324
AppsFlyer Flutter Plugin 7.0.2 Release
af-dudka Aug 27, 2026
6e6a817
[DELIVERY-125863] Fix Android E2E startSDK timeout on slow emulator c…
af-dudka Aug 27, 2026
147479f
[DELIVERY-125863] Stop adb from draining stdin and skipping scenario …
af-dudka Aug 27, 2026
1413532
[DELIVERY-125863] Cover cold deep links and stop iOS phases validatin…
af-dudka Aug 27, 2026
cd1616c
[DELIVERY-125863] Correct iOS isDeferred docs and F-039 UIScene regis…
af-dudka Aug 27, 2026
5610652
[DELIVERY-125863] Point example App/Universal Links at af-flutter-plu…
af-dudka Aug 27, 2026
2b48f87
[DELIVERY-125863] Add Android E2E phase_8 for OneLink https cold App …
af-dudka Aug 27, 2026
1ae7d57
[DELIVERY-125863] Stop iOS delivering deep links twice on the UIScene…
af-dudka Aug 27, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .claude/skills/alice-pm/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -322,7 +322,7 @@ Automated via GitHub Actions: `.github/workflows/rc-release.yml`, `rc-smoke.yml`

## Domain-Specific Notes

- Cross-platform parity: any new public Dart API must map to matching method names/behavior in both `AppsflyerSdkPlugin.java` (Android) and `AppsflyerSdkPlugin.m` (iOS) — flag any PRD that only specifies one platform.
- Cross-platform parity: any new public Dart API must map to matching method names/behavior in both `AppsflyerSdkPlugin.kt` (Android) and `AppsflyerSdkPlugin.swift` (iOS) — flag any PRD that only specifies one platform.
- This is a published pub.dev package (`appsflyer_sdk`) consumed by third-party apps — breaking changes to the public Dart API require a major version bump and migration notes in `CHANGELOG.md`.
- Purchase Connector is optional/self-contained (`lib/src/purchase_connector/`, `ios/PurchaseConnector/`, Android Kotlin) — changes there should not affect core SDK consumers who don't opt in.
- Release goes through the RC pipeline (see Release Process above) — any feature landing near a release cut should account for RC-SMOKE validation.
4 changes: 2 additions & 2 deletions .claude/skills/dave-flutter-engineer/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ description: Use when working on AppsFlyer Flutter Plugin code — writing, revi

## Persona

Senior engineer with deep knowledge of AppsFlyer Flutter Plugin. Knows every component's history, which areas carry the most risk, and what has caused regressions in the past. Tech stack: Dart/Flutter plugin (SDK >=2.17.0 <4.0.0, Flutter >=1.10.0) bridging native AppsFlyer SDKs via MethodChannel/EventChannel — Objective-C on iOS (`ios/Classes/`), Java/Kotlin on Android (`android/src/main/java` + `android/src/main/kotlin` for the Purchase Connector). JSON models via `json_annotation`/`json_serializable` + `build_runner`. Testing via `mockito` + `flutter_lints`..
Senior engineer with deep knowledge of AppsFlyer Flutter Plugin. Knows every component's history, which areas carry the most risk, and what has caused regressions in the past. Tech stack: Dart/Flutter plugin (SDK >=2.17.0 <4.0.0, Flutter >=1.10.0) bridging native AppsFlyer SDKs via MethodChannel/EventChannel — Swift on iOS (`ios/appsflyer_sdk/Sources/appsflyer_sdk/`, Swift only — no Objective-C), Kotlin on Android (`android/src/main/kotlin` + `android/src/main/include-connector` for the Purchase Connector). JSON models via `json_annotation`/`json_serializable` + `build_runner`. Testing via `mockito` + `flutter_lints`..

## PRD Gate — BLOCKING REQUIREMENT

Expand Down Expand Up @@ -165,7 +165,7 @@ BLOCKING REQUIREMENT: Include a `Skill('dave-flutter-engineer')` tool call in th
## Domain-Specific Notes

- Keep `AppsflyerSdk` as a singleton — do not change the instantiation pattern.
- New SDK method: add Dart method in `lib/src/appsflyer_sdk.dart` (invoke via `_channel.invokeMethod`), implement in `AppsflyerSdkPlugin.java` (Android) and `AppsflyerSdkPlugin.m` (iOS). Keep the method name string identical across all three files.
- New SDK method: add Dart method in `lib/src/appsflyer_sdk.dart` (invoke via `_channel.invokeMethod`), implement in `AppsflyerSdkPlugin.kt` (Android) and `AppsflyerSdkPlugin.swift` (iOS). Keep the method name string identical across all three files.
- Callbacks from native → Dart flow through EventChannels defined in `lib/src/callbacks.dart`.
- Deep linking (UDL) logic is isolated in `lib/src/udl/` — do not mix with core SDK channel calls.
- Purchase Connector is self-contained in `lib/src/purchase_connector/` (Dart models) and `ios/PurchaseConnector/` / `android/.../kotlin/` (native) — keep it that way.
Expand Down
2 changes: 1 addition & 1 deletion .claude/skills/erin-flutter-analyst/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,5 +95,5 @@ After Erin presents any analysis findings, `alice-pm` is invoked automatically.

- Field maps live at the MethodChannel/EventChannel boundary — arguments passed as `Map<String, dynamic>` between Dart and native.
- JSON-serializable Dart models: `lib/src/purchase_connector/` (in-app purchase validation payloads) — regenerate `.g.dart` via `build_runner` after any field change.
- Attribution/conversion data payloads flow through `lib/src/callbacks.dart` — check both the Dart model and the native (Java/ObjC) side that populates the EventChannel data.
- Attribution/conversion data payloads flow through `lib/src/callbacks.dart` — check both the Dart model and the native (Kotlin/Swift) side that populates the EventChannel data.
- When mapping fields, verify parity between what Android and iOS native code send — historically a source of drift.
4 changes: 4 additions & 0 deletions .github/workflows/ios-e2e.yml
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,10 @@ jobs:
working-directory: example
run: flutter pub get

- name: Regenerate iOS project configuration
working-directory: example
run: flutter build ios --config-only

- name: Install CocoaPods
working-directory: example/ios
run: pod install
Expand Down
191 changes: 169 additions & 22 deletions .github/workflows/lint-test-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,16 @@
#
# What it does:
# 1. Lints + format-checks + runs Dart/Flutter unit tests with coverage.
# 2. Builds Android example app (release App Bundle).
# 3. Builds iOS example app (no-codesign release IPA).
# 2. Runs the Android native (JVM) unit tests, then builds the Android example
# app (release App Bundle).
# 3. Builds the iOS example app (no-codesign release IPA).
# 4. Caches dependencies for faster subsequent runs.
#
# Note on native tests: the Android JVM tests live in the Android job rather
# than the Dart `test` job because they need that job's toolchain (Android SDK
# plus JDK for Gradle), so running them there reuses a setup the job already
# pays for. The iOS XCTest suite is not run in CI — see the Job 3 header.
#
# Note on debug builds: debug-mode Android APK and iOS simulator builds used
# to live here, but they duplicate exactly what ios-e2e.yml / android-e2e.yml
# do before running scenarios. Release-mode builds remain here because E2E
Expand Down Expand Up @@ -117,12 +123,33 @@ jobs:
# This installs all packages defined in pubspec.yaml
- name: Install plugin dependencies
run: flutter pub get

# Step 4a: Create dummy example/.env for analyze
# example/pubspec.yaml lists .env as an asset; the file is gitignored and
# integrators create it locally. Without it, flutter analyze reports
# asset_does_not_exist when validating example assets from the plugin root.
- name: Create dummy example/.env for analyze
working-directory: example
run: |
echo "DEV_KEY=dummy_dev_key" > .env
echo "APP_ID=dummy_app_id" >> .env

# Step 5: Analyze code for issues
# Checks for code quality issues, unused imports, etc.
# Only fails on actual errors, not info-level warnings
- name: Analyze code
run: flutter analyze --no-fatal-infos --no-fatal-warnings
# Step 5: Analyze the plugin
# Infos and warnings are fatal: both packages are clean at this level, so
# anything new is a regression rather than pre-existing debt.
- name: Analyze plugin
run: flutter analyze --fatal-infos

# Step 5a: Analyze the example app
# Separate package context; also the only code in the repo that exercises
# the public API the way an integrator does.
- name: Install example dependencies
run: flutter pub get
working-directory: example

- name: Analyze example app
run: flutter analyze --fatal-infos
working-directory: example

# Step 6: Format check
# Ensures code follows Dart formatting standards. On failure, prints
Expand Down Expand Up @@ -166,9 +193,10 @@ jobs:
fail_ci_if_error: false # Don't fail CI if coverage upload fails

# ===========================================================================
# Job 2: Build Android Example App
# Job 2: Android Native Tests + Build Example App
# ===========================================================================
# Builds the example app for Android to ensure plugin integration works
# Runs the plugin's Android JVM unit tests, then builds the example app to
# ensure plugin integration works
# Uses: Ubuntu runner with Java 17
# ===========================================================================

Expand Down Expand Up @@ -226,7 +254,39 @@ jobs:
echo "DEV_KEY=dummy_dev_key" > .env
echo "APP_ID=dummy_app_id" >> .env

# Step 8: Build Android App Bundle (release mode, no signing)
# Step 8: Materialize the Gradle wrapper
# `example/android/gradlew` and `gradle-wrapper.jar` are gitignored (the
# standard `flutter create` .gitignore), so a fresh checkout has neither
# and `flutter pub get` does not create them — it only writes
# local.properties. The wrapper is injected by the Flutter tool the first
# time it needs to invoke Gradle, and `--config-only` stops right after
# that injection, so this costs a couple of seconds instead of a build.
- name: Prepare Gradle wrapper
working-directory: example
run: flutter build apk --config-only

# Step 9: Run the plugin's Android JVM unit tests
# The plugin is included in the example's Gradle build as `:appsflyer_sdk`
# by the Flutter plugin loader, so this runs from example/android. Placed
# ahead of the release build: it is the faster of the two and covers the
# engine-lifecycle logic (AppsFlyerEventBus, AppsFlyerRpcBridge) that an
# appbundle build cannot exercise.
- name: Run Android native unit tests
working-directory: example/android
run: ./gradlew :appsflyer_sdk:testDebugUnitTest --console=plain

# Step 10: Publish the Gradle test report when the tests fail
- name: Upload Android test report
if: failure()
uses: actions/upload-artifact@v5
with:
name: android-native-test-report
path: |
example/build/appsflyer_sdk/reports/tests/testDebugUnitTest
example/build/appsflyer_sdk/test-results/testDebugUnitTest
retention-days: 7

# Step 11: Build Android App Bundle (release mode, no signing)
# App Bundle is the preferred format for Play Store. Catches R8/proguard
# regressions a debug APK won't. Debug APK builds were removed because
# android-e2e.yml already builds and runs `flutter build apk --debug`
Expand All @@ -235,7 +295,7 @@ jobs:
working-directory: example
run: flutter build appbundle --release

# Step 9: Upload App Bundle artifact (optional)
# Step 12: Upload App Bundle artifact (optional)
# Useful for manual install testing and archiving release-mode output.
- name: Upload App Bundle artifact
if: success()
Expand All @@ -245,10 +305,86 @@ jobs:
path: example/build/app/outputs/bundle/release/app-release.aab
retention-days: 7

# ===========================================================================
# Job 2b: Build the example app on the declared minimum toolchain
# ===========================================================================
# Every other job pins `channel: stable`, which never exercises the floor
# advertised in pubspec.yaml. This job builds the example app on exactly that
# declared minimum, so the constraint is verified rather than assumed.
#
# Debug APK rather than the release bundle: this leg is about the toolchain
# accepting the plugin, and the release path is already covered by
# build-android on stable.
# ===========================================================================
build-android-min-toolchain:
name: 🤖 Build Android Example (minimum toolchain)
runs-on: ubuntu-latest
needs: test
if: ${{ (needs.test.result == 'success' || needs.test.result == 'skipped') && inputs.skip_builds != true }}

steps:
- name: Checkout repository
uses: actions/checkout@v5

# JDK 17 is part of the declared minimum, so this leg pins it too.
- name: Setup Java
uses: actions/setup-java@v5
with:
distribution: 'temurin'
java-version: '17'
cache: 'gradle'

# Pinned, not `stable`. Keep this version equal to the `flutter:`
# constraint in pubspec.yaml.
- name: Setup Flutter SDK (declared minimum)
uses: subosito/flutter-action@v2
with:
flutter-version: '3.35.0'
cache: true

- name: Display versions
run: |
flutter --version
java -version

- name: Fail if the pinned version does not match pubspec.yaml
run: |
declared=$(grep -oE 'flutter: *">=[0-9]+\.[0-9]+\.[0-9]+"' pubspec.yaml \
| grep -oE '[0-9]+\.[0-9]+\.[0-9]+')
if [ "$declared" != "3.35.0" ]; then
echo "::error::pubspec.yaml declares Flutter >=$declared but this job pins 3.35.0."
echo "Update the flutter-version above, or the constraint in pubspec.yaml."
exit 1
fi

- name: Install plugin dependencies
run: flutter pub get

- name: Install example app dependencies
working-directory: example
run: flutter pub get

- name: Create dummy .env for CI build
working-directory: example
run: |
echo "DEV_KEY=dummy_dev_key" > .env
echo "APP_ID=dummy_app_id" >> .env

- name: Build Android APK (debug)
working-directory: example
run: flutter build apk --debug

# ===========================================================================
# Job 3: Build iOS Example App
# ===========================================================================
# Builds the example app for iOS to ensure plugin integration works
# Builds the example app to ensure plugin integration works
#
# The plugin's XCTest suite is deliberately not run here. It covers Foundation
# behavior rather than plugin code (`RunnerTests` re-implements the function
# under test instead of importing it), so a simulator boot and a second, debug
# build of the app would buy no coverage on a runner that bills at 10x. Wire
# it in once there are XCTests that exercise `AppsflyerSdkPlugin` /
# `AFRPCBridge` directly.
# Uses: macOS runner (required for Xcode and iOS builds)
# Note: macOS runners consume 10x minutes on private repos
# ===========================================================================
Expand Down Expand Up @@ -291,26 +427,31 @@ jobs:
working-directory: example
run: flutter pub get

# Step 6: Update CocoaPods repo (ensures latest pod specs)
# Step 6: Regenerate iOS build settings (Flutter.podspec deployment target, etc.)
- name: Regenerate iOS project configuration
working-directory: example
run: flutter build ios --config-only

# Step 7: Update CocoaPods repo (ensures latest pod specs)
# This can be slow, so we only update if needed
- name: Update CocoaPods repo
working-directory: example/ios
run: pod repo update

# Step 7: Install CocoaPods dependencies
# Step 8: Install CocoaPods dependencies
# This installs native iOS dependencies including AppsFlyer SDK
- name: Install CocoaPods dependencies
working-directory: example/ios
run: pod install

# Step 8: Create dummy .env file for CI (not committed to repo)
# Step 9: Create dummy .env file for CI (not committed to repo)
- name: Create dummy .env for CI build
working-directory: example
run: |
echo "DEV_KEY=dummy_dev_key" > .env
echo "APP_ID=dummy_app_id" >> .env

# Step 9: Build iOS IPA without code signing (release mode)
# Step 10: Build iOS IPA without code signing (release mode)
# Validates a full release build without requiring certificates. Catches
# archive bundling and signing-config issues a simulator-debug build
# won't. The simulator-debug build that used to live here was dropped
Expand All @@ -320,7 +461,7 @@ jobs:
working-directory: example
run: flutter build ipa --release --no-codesign

# Step 10: Upload build artifacts (optional)
# Step 11: Upload build artifacts (optional)
- name: Upload iOS build artifact
if: success()
uses: actions/upload-artifact@v5
Expand All @@ -338,7 +479,7 @@ jobs:
ci-summary:
name: 📋 CI Summary
runs-on: ubuntu-latest
needs: [test, build-android, build-ios]
needs: [test, build-android, build-android-min-toolchain, build-ios]
if: always() # Run even if previous jobs fail

steps:
Expand All @@ -347,9 +488,10 @@ jobs:
echo "==================================="
echo "Lint, Test & Build summary"
echo "==================================="
echo "Test Job: ${{ needs.test.result }}"
echo "Android Build: ${{ needs.build-android.result }}"
echo "iOS Build: ${{ needs.build-ios.result }}"
echo "Dart unit/lint: ${{ needs.test.result }}"
echo "Android native tests + build: ${{ needs.build-android.result }}"
echo "Android minimum toolchain: ${{ needs.build-android-min-toolchain.result }}"
echo "iOS build: ${{ needs.build-ios.result }}"
echo "==================================="

# 'skipped' is acceptable for any of the three jobs (skip_unit=true
Expand All @@ -358,14 +500,19 @@ jobs:
# gate decides whether a skip is acceptable for publish.
test_result="${{ needs.test.result }}"
android_result="${{ needs.build-android.result }}"
android_min_result="${{ needs.build-android-min-toolchain.result }}"
ios_result="${{ needs.build-ios.result }}"

if [[ "$test_result" != "success" && "$test_result" != "skipped" ]]; then
echo "❌ Unit/lint job failed"
exit 1
fi
if [[ "$android_result" != "success" && "$android_result" != "skipped" ]]; then
echo "❌ Android release build failed"
echo "❌ Android native tests or release build failed"
exit 1
fi
if [[ "$android_min_result" != "success" && "$android_min_result" != "skipped" ]]; then
echo "❌ Android build on the declared minimum toolchain failed"
exit 1
fi
if [[ "$ios_result" != "success" && "$ios_result" != "skipped" ]]; then
Expand Down
8 changes: 5 additions & 3 deletions .github/workflows/production-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -405,9 +405,11 @@ jobs:

## 📚 Documentation

- [Installation Guide](https://github.com/${{ github.repository }}/blob/master/doc/Installation.md)
- [Basic Integration](https://github.com/${{ github.repository }}/blob/master/doc/BasicIntegration.md)
- [API Documentation](https://github.com/${{ github.repository }}/blob/master/doc/API.md)
- [Documentation index](https://github.com/${{ github.repository }}/blob/master/doc/README.md)
- [Installation](https://github.com/${{ github.repository }}/blob/master/doc/installation-guide.md)
- [Getting started](https://github.com/${{ github.repository }}/blob/master/doc/getting-started.md)
- [API reference](https://github.com/${{ github.repository }}/blob/master/doc/api-reference.md)
- [Migrating v6 → v7](https://github.com/${{ github.repository }}/blob/master/doc/migration-guide.md)
- [Sample App](https://github.com/${{ github.repository }}/tree/master/example)

## 🔗 Links
Expand Down
Loading
Loading