Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,15 @@
### Version 5.6.0 (31st March 2026)
#### Added
- Added support for direct deep link callbacks. You can now receive direct deep links by assigning the `directDeeplinkCallback` member of your `AdjustConfig` instance.
- Added support for remote trigger callbacks. You can now receive remote trigger updates by assigning the `remoteTriggerCallback` member of your `AdjustConfig`
instance.

#### Native SDKs
- **iOS:** [v5.6.0](https://github.com/adjust/ios_sdk/tree/v5.6.0)
- **Android:** [v5.6.0](https://github.com/adjust/android_sdk/tree/v5.6.0)

---

### Version 5.5.1 (9th March 2026)
#### Fixed
- Fixed an Android build failure (`Cannot run Project.afterEvaluate(Action) when the project is already evaluated`) by handling Gradle evaluation order when `:adjust_sdk` is evaluated before the host `:app` project.
Expand Down
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
5.5.1
5.6.0
2 changes: 1 addition & 1 deletion android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -28,5 +28,5 @@ android {
}

dependencies {
implementation 'com.adjust.sdk:adjust-android:5.5.1'
implementation 'com.adjust.sdk:adjust-android:5.6.0'
}
176 changes: 175 additions & 1 deletion android/src/main/java/com/adjust/sdk/flutter/AdjustSdk.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
package com.adjust.sdk.flutter;

import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.util.Log;

Expand All @@ -23,6 +24,7 @@
import com.adjust.sdk.AdjustSessionSuccess;
import com.adjust.sdk.AdjustPlayStoreSubscription;
import com.adjust.sdk.AdjustPurchaseVerificationResult;
import com.adjust.sdk.AdjustRemoteTrigger;
import com.adjust.sdk.AdjustStoreInfo;
import com.adjust.sdk.AdjustThirdPartySharing;
import com.adjust.sdk.AdjustTestOptions;
Expand All @@ -34,6 +36,7 @@
import com.adjust.sdk.OnEventTrackingSucceededListener;
import com.adjust.sdk.OnSessionTrackingFailedListener;
import com.adjust.sdk.OnSessionTrackingSucceededListener;
import com.adjust.sdk.OnRemoteTriggerListener;
import com.adjust.sdk.OnPurchaseVerificationFinishedListener;
import com.adjust.sdk.OnLastDeeplinkReadListener;
import com.adjust.sdk.OnDeeplinkResolvedListener;
Expand All @@ -55,16 +58,23 @@
import java.util.Map;

import io.flutter.embedding.engine.plugins.FlutterPlugin;
import io.flutter.embedding.engine.plugins.activity.ActivityAware;
import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding;
import io.flutter.plugin.common.MethodChannel;
import io.flutter.plugin.common.MethodChannel.MethodCallHandler;
import io.flutter.plugin.common.MethodChannel.Result;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.PluginRegistry.NewIntentListener;

public class AdjustSdk implements FlutterPlugin, MethodCallHandler {
public class AdjustSdk implements FlutterPlugin, MethodCallHandler, ActivityAware, NewIntentListener {
private static String TAG = "AdjustBridge";
private static String DIRECT_DEEPLINK_CALLBACK_NAME = "adj-direct-deeplink";
private static boolean isDeferredDeeplinkOpeningEnabled = true;
private MethodChannel channel;
private Context applicationContext;
private ActivityPluginBinding activityPluginBinding;
private boolean isSdkInitialized = false;
private final ArrayList<HashMap<String, String>> cachedDirectDeeplinks = new ArrayList<>();

// FlutterPlugin
@Override
Expand All @@ -76,13 +86,95 @@ public void onAttachedToEngine(FlutterPluginBinding binding) {

@Override
public void onDetachedFromEngine(FlutterPluginBinding binding) {
detachFromActivity();
isSdkInitialized = false;
cachedDirectDeeplinks.clear();
applicationContext = null;
if (channel != null) {
channel.setMethodCallHandler(null);
}
channel = null;
}

// ActivityAware
@Override
public void onAttachedToActivity(ActivityPluginBinding binding) {
activityPluginBinding = binding;
activityPluginBinding.addOnNewIntentListener(this);
processDeeplinkFromIntent(activityPluginBinding.getActivity().getIntent());
}

@Override
public void onDetachedFromActivityForConfigChanges() {
detachFromActivity();
}

@Override
public void onReattachedToActivityForConfigChanges(ActivityPluginBinding binding) {
onAttachedToActivity(binding);
}

@Override
public void onDetachedFromActivity() {
detachFromActivity();
}

@Override
public boolean onNewIntent(Intent intent) {
processDeeplinkFromIntent(intent);
return false;
}

private void detachFromActivity() {
if (activityPluginBinding != null) {
activityPluginBinding.removeOnNewIntentListener(this);
activityPluginBinding = null;
}
}

private void processDeeplinkFromIntent(final Intent intent) {
if (intent == null) {
return;
}

Uri deeplinkUri = intent.getData();
if (deeplinkUri == null) {
return;
}

dispatchOrCacheDirectDeeplink(deeplinkUri, null);
}

private void dispatchOrCacheDirectDeeplink(final Uri deeplinkUri, final Uri referrerUri) {
if (deeplinkUri == null) {
return;
}

HashMap<String, String> uriParamsMap = new HashMap<String, String>();
uriParamsMap.put("deeplink", deeplinkUri.toString());
if (referrerUri != null) {
uriParamsMap.put("referrer", referrerUri.toString());
}

if (!isSdkInitialized || channel == null) {
cachedDirectDeeplinks.add(uriParamsMap);
return;
}

channel.invokeMethod(DIRECT_DEEPLINK_CALLBACK_NAME, uriParamsMap);
}

private void flushCachedDirectDeeplinks() {
if (!isSdkInitialized || channel == null || cachedDirectDeeplinks.isEmpty()) {
return;
}

for (HashMap<String, String> deeplinkMap : cachedDirectDeeplinks) {
channel.invokeMethod(DIRECT_DEEPLINK_CALLBACK_NAME, deeplinkMap);
}
cachedDirectDeeplinks.clear();
}

@Override
public void onMethodCall(MethodCall call, final Result result) {
switch (call.method) {
Expand Down Expand Up @@ -611,8 +703,25 @@ public boolean launchReceivedDeeplink(Uri deeplink) {
}
}

// remote trigger callback
if (configMap.containsKey("remoteTriggerCallback")) {
final String dartMethodName = (String) configMap.get("remoteTriggerCallback");
if (dartMethodName != null) {
adjustConfig.setOnRemoteTriggerListener(new OnRemoteTriggerListener() {
@Override
public void onRemoteTrigger(AdjustRemoteTrigger remoteTrigger) {
if (channel != null) {
channel.invokeMethod(dartMethodName, getRemoteTriggerMap(remoteTrigger));
}
}
});
}
}

// initialize SDK
Adjust.initSdk(adjustConfig);
isSdkInitialized = true;
flushCachedDirectDeeplinks();
result.success(null);
}

Expand Down Expand Up @@ -1500,4 +1609,69 @@ private void setTestOptions(final MethodCall call, final Result result) {

Adjust.setTestOptions(testOptions);
}

private HashMap<String, Object> getRemoteTriggerMap(AdjustRemoteTrigger remoteTrigger) {
HashMap<String, Object> remoteTriggerMap = new HashMap<String, Object>();
if (remoteTrigger == null) {
remoteTriggerMap.put("label", "");
remoteTriggerMap.put("payload", new HashMap<String, Object>());
return remoteTriggerMap;
}

remoteTriggerMap.put("label", remoteTrigger.getLabel());
remoteTriggerMap.put("payload", jsonObjectToMap(remoteTrigger.getPayload()));
return remoteTriggerMap;
}

private HashMap<String, Object> jsonObjectToMap(JSONObject jsonObject) {
HashMap<String, Object> map = new HashMap<String, Object>();
if (jsonObject == null) {
return map;
}

JSONArray names = jsonObject.names();
if (names == null) {
return map;
}

for (int i = 0; i < names.length(); ++i) {
String key = names.optString(i, null);
if (key == null) {
continue;
}

map.put(key, jsonValueToObject(jsonObject.opt(key)));
}

return map;
}

private ArrayList<Object> jsonArrayToList(JSONArray jsonArray) {
ArrayList<Object> list = new ArrayList<Object>();
if (jsonArray == null) {
return list;
}

for (int i = 0; i < jsonArray.length(); ++i) {
list.add(jsonValueToObject(jsonArray.opt(i)));
}

return list;
}

private Object jsonValueToObject(Object value) {
if (value == null || value == JSONObject.NULL) {
return null;
}

if (value instanceof JSONObject) {
return jsonObjectToMap((JSONObject) value);
}

if (value instanceof JSONArray) {
return jsonArrayToList((JSONArray) value);
}

return value;
}
}
2 changes: 1 addition & 1 deletion example/android/app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -42,5 +42,5 @@ flutter {
}

dependencies {
implementation("com.adjust.sdk:adjust-android-google-lvl:5.5.1")
implementation("com.adjust.sdk:adjust-android-google-lvl:5.6.0")
}
15 changes: 12 additions & 3 deletions example/android/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,23 @@
/>
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>

<intent-filter>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.BROWSABLE" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="adjust"/>
</intent-filter>

<intent-filter android:autoVerify="true">
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>
<data
android:scheme="adjust"
android:host="test" />
android:scheme="https"
android:host="chess.go.link"/>
</intent-filter>
</activity>
<!-- Don't delete the meta-data below.
Expand Down
39 changes: 21 additions & 18 deletions example/ios/Runner.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -470,12 +470,13 @@
249021D4217E4FDB00AE95B9 /* Profile */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEVELOPMENT_TEAM = QGUGW9AUMK;
ENABLE_BITCODE = NO;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEVELOPMENT_TEAM = QGUGW9AUMK;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
Expand Down Expand Up @@ -653,12 +654,13 @@
97C147061CF9000F007C117D /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEVELOPMENT_TEAM = QGUGW9AUMK;
ENABLE_BITCODE = NO;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEVELOPMENT_TEAM = QGUGW9AUMK;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
Expand All @@ -676,12 +678,13 @@
97C147071CF9000F007C117D /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEVELOPMENT_TEAM = QGUGW9AUMK;
ENABLE_BITCODE = NO;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEVELOPMENT_TEAM = QGUGW9AUMK;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
Expand Down
24 changes: 11 additions & 13 deletions example/ios/Runner/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,17 @@
<string>????</string>
<key>CFBundleVersion</key>
<string>$(FLUTTER_BUILD_NUMBER)</string>
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLName</key>
<string>com.adjust.examples</string>
<key>CFBundleURLSchemes</key>
<array>
<string>adjust</string>
</array>
</dict>
</array>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>NSUserTrackingUsageDescription</key>
Expand All @@ -47,18 +58,5 @@
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>

<!-- add the deeplink configuration here-->
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLName</key>
<string>adjust_deeplink</string>
<key>CFBundleURLSchemes</key>
<array>
<string>adjust</string>
</array>
</dict>
</array>
</dict>
</plist>
Loading