diff --git a/Adjust/adjust/src/main/java/com/adjust/sdk/CustomScheduledExecutor.java b/Adjust/adjust/src/main/java/com/adjust/sdk/CustomScheduledExecutor.java deleted file mode 100644 index 1683efee3..000000000 --- a/Adjust/adjust/src/main/java/com/adjust/sdk/CustomScheduledExecutor.java +++ /dev/null @@ -1,84 +0,0 @@ -package com.adjust.sdk; - -import java.util.concurrent.Executors; -import java.util.concurrent.Future; -import java.util.concurrent.RejectedExecutionHandler; -import java.util.concurrent.ScheduledFuture; -import java.util.concurrent.ScheduledThreadPoolExecutor; -import java.util.concurrent.ThreadFactory; -import java.util.concurrent.ThreadPoolExecutor; -import java.util.concurrent.TimeUnit; - -/** - * Created by pfms on 05/08/2016. - */ -public final class CustomScheduledExecutor extends ScheduledThreadPoolExecutor { - public CustomScheduledExecutor(final String source, boolean doKeepAlive) { - super(1, - new ThreadFactory() { // Creator of daemon threads - @Override - public Thread newThread(Runnable runnable) { - Thread thread = Executors.defaultThreadFactory().newThread(runnable); - - thread.setPriority(Thread.MIN_PRIORITY); - thread.setName(Constants.THREAD_PREFIX + thread.getName() + "-" + source); - thread.setDaemon(true); - - thread.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() { - @Override - public void uncaughtException(Thread th, Throwable tr) { - AdjustFactory.getLogger().error("Thread [%s] with error [%s]", - th.getName(), tr.getMessage()); - } - }); - - return thread; - } - }, new RejectedExecutionHandler() { // Logs rejected runnables rejected from the entering the pool - @Override - public void rejectedExecution(Runnable runnable, ThreadPoolExecutor executor) { - AdjustFactory.getLogger().warn("Runnable [%s] rejected from [%s] ", - runnable.toString(), source); - } - } - ); - - if (!doKeepAlive) { - setKeepAliveTime(10L, TimeUnit.MILLISECONDS); - allowCoreThreadTimeOut(true); - } - } - - @Override - public Future submit(Runnable task) { - return super.submit(new RunnableWrapper(task)); - } - - @Override - public ScheduledFuture scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit) { - return super.scheduleWithFixedDelay(new RunnableWrapper(command), initialDelay, delay, unit); - } - - @Override - public ScheduledFuture schedule(Runnable command, long delay, TimeUnit unit) { - return super.schedule(new RunnableWrapper(command), delay, unit); - } - - private static class RunnableWrapper implements Runnable { - private Runnable runnable; - - RunnableWrapper(Runnable runnable) { - this.runnable = runnable; - } - - @Override - public void run() { - try { - runnable.run(); - } catch (Throwable t) { - AdjustFactory.getLogger().error("Runnable error [%s] of type [%s]", - t.getMessage(), t.getClass().getCanonicalName()); - } - } - } -} diff --git a/Adjust/adjust/src/main/java/com/adjust/sdk/PackageBuilder.java b/Adjust/adjust/src/main/java/com/adjust/sdk/PackageBuilder.java deleted file mode 100644 index 996d361c7..000000000 --- a/Adjust/adjust/src/main/java/com/adjust/sdk/PackageBuilder.java +++ /dev/null @@ -1,415 +0,0 @@ -// -// PackageBuilder.java -// Adjust -// -// Created by Christian Wellenbrock on 2013-06-25. -// Copyright (c) 2013 adjust GmbH. All rights reserved. -// See the file MIT-LICENSE for copying permission. -// - -package com.adjust.sdk; - -import android.content.ContentResolver; -import android.content.Context; -import android.telephony.TelephonyManager; -import android.text.TextUtils; - -import org.json.JSONObject; - -import java.util.Date; -import java.util.HashMap; -import java.util.Locale; -import java.util.Map; - -import static com.adjust.sdk.Constants.CALLBACK_PARAMETERS; -import static com.adjust.sdk.Constants.PARTNER_PARAMETERS; - -class PackageBuilder { - private AdjustConfig adjustConfig; - private DeviceInfo deviceInfo; - private ActivityStateCopy activityStateCopy; - private SessionParameters sessionParameters; - private long createdAt; - - // reattributions - Map extraParameters; - AdjustAttribution attribution; - String reftag; - String referrer; - String rawReferrer; - String deeplink; - long clickTimeInMilliseconds = -1; - - long clicktTimeInSeconds = -1; - long installBeginTimeInSeconds = -1; - - private static ILogger logger = AdjustFactory.getLogger(); - - private class ActivityStateCopy { - long lastInterval = -1; - int eventCount = -1; - String uuid = null; - int sessionCount = -1; - int subsessionCount = -1; - long sessionLength = -1; - long timeSpent = -1; - String pushToken = null; - - ActivityStateCopy(ActivityState activityState) { - if (activityState == null) { - return; - } - this.lastInterval = activityState.lastInterval; - this.eventCount = activityState.eventCount; - this.uuid = activityState.uuid; - this.sessionCount = activityState.sessionCount; - this.subsessionCount = activityState.subsessionCount; - this.sessionLength = activityState.sessionLength; - this.timeSpent = activityState.timeSpent; - this.pushToken = activityState.pushToken; - } - } - - public PackageBuilder(AdjustConfig adjustConfig, - DeviceInfo deviceInfo, - ActivityState activityState, - SessionParameters sessionParameters, - long createdAt) { - this.adjustConfig = adjustConfig; - this.deviceInfo = deviceInfo; - this.activityStateCopy = new ActivityStateCopy(activityState); - this.sessionParameters = sessionParameters; - this.createdAt = createdAt; - } - - public ActivityPackage buildSessionPackage(boolean isInDelay) { - Map parameters; - parameters = getAttributableParameters(isInDelay); - - ActivityPackage sessionPackage = getDefaultActivityPackage(ActivityKind.SESSION); - sessionPackage.setPath("/session"); - sessionPackage.setSuffix(""); - sessionPackage.setParameters(parameters); - - return sessionPackage; - } - - public ActivityPackage buildEventPackage(AdjustEvent event, - boolean isInDelay) { - Map parameters = getDefaultParameters(); - PackageBuilder.addLong(parameters, "event_count", activityStateCopy.eventCount); - PackageBuilder.addString(parameters, "event_token", event.eventToken); - PackageBuilder.addDouble(parameters, "revenue", event.revenue); - PackageBuilder.addString(parameters, "currency", event.currency); - PackageBuilder.addString(parameters, "event_callback_id", event.callbackId); - - if (!isInDelay) { - PackageBuilder.addMapJson(parameters, CALLBACK_PARAMETERS, - Util.mergeParameters(this.sessionParameters.callbackParameters, event.callbackParameters, "Callback")); - PackageBuilder.addMapJson(parameters, PARTNER_PARAMETERS, - Util.mergeParameters(this.sessionParameters.partnerParameters, event.partnerParameters, "Partner")); - } - ActivityPackage eventPackage = getDefaultActivityPackage(ActivityKind.EVENT); - eventPackage.setPath("/event"); - eventPackage.setSuffix(getEventSuffix(event)); - eventPackage.setParameters(parameters); - - if (isInDelay) { - eventPackage.setCallbackParameters(event.callbackParameters); - eventPackage.setPartnerParameters(event.partnerParameters); - } - - return eventPackage; - } - - public ActivityPackage buildClickPackage(String source) { - Map parameters = getAttributableParameters(false); - - PackageBuilder.addString(parameters, "source", source); - PackageBuilder.addDateInMilliseconds(parameters, "click_time", clickTimeInMilliseconds); - PackageBuilder.addString(parameters, "reftag", reftag); - PackageBuilder.addMapJson(parameters, "params", extraParameters); - PackageBuilder.addString(parameters, "referrer", referrer); - PackageBuilder.addString(parameters, "raw_referrer", rawReferrer); - PackageBuilder.addString(parameters, "deeplink", deeplink); - PackageBuilder.addDateInSeconds(parameters, "click_time", clicktTimeInSeconds); - PackageBuilder.addDateInSeconds(parameters, "install_begin_time", installBeginTimeInSeconds); - injectAttribution(parameters); - - ActivityPackage clickPackage = getDefaultActivityPackage(ActivityKind.CLICK); - clickPackage.setPath("/sdk_click"); - clickPackage.setSuffix(""); - clickPackage.setClickTimeInMilliseconds(clickTimeInMilliseconds); - clickPackage.setClickTimeInSeconds(clicktTimeInSeconds); - clickPackage.setInstallBeginTimeInSeconds(installBeginTimeInSeconds); - clickPackage.setParameters(parameters); - - return clickPackage; - } - - public ActivityPackage buildInfoPackage(String source) { - Map parameters = getIdsParameters(); - - PackageBuilder.addString(parameters, "source", source); - - ActivityPackage clickPackage = getDefaultActivityPackage(ActivityKind.INFO); - clickPackage.setPath("/sdk_info"); - clickPackage.setSuffix(""); - clickPackage.setParameters(parameters); - - return clickPackage; - } - - public ActivityPackage buildAttributionPackage() { - Map parameters = getIdsParameters(); - - ActivityPackage attributionPackage = getDefaultActivityPackage(ActivityKind.ATTRIBUTION); - attributionPackage.setPath("attribution"); // does not contain '/' because of Uri.Builder.appendPath - attributionPackage.setSuffix(""); - attributionPackage.setParameters(parameters); - - return attributionPackage; - } - - public ActivityPackage buildGdprPackage() { - Map parameters = getIdsParameters(); - - ActivityPackage gdprPackage = getDefaultActivityPackage(ActivityKind.GDPR); - gdprPackage.setPath("/gdpr_forget_device"); - gdprPackage.setSuffix(""); - gdprPackage.setParameters(parameters); - - return gdprPackage; - } - - private ActivityPackage getDefaultActivityPackage(ActivityKind activityKind) { - ActivityPackage activityPackage = new ActivityPackage(activityKind); - activityPackage.setClientSdk(deviceInfo.clientSdk); - return activityPackage; - } - - private Map getAttributableParameters(boolean isInDelay) { - Map parameters = getDefaultParameters(); - PackageBuilder.addDuration(parameters, "last_interval", activityStateCopy.lastInterval); - PackageBuilder.addString(parameters, "default_tracker", adjustConfig.defaultTracker); - PackageBuilder.addString(parameters, "installed_at", deviceInfo.appInstallTime); - PackageBuilder.addString(parameters, "updated_at", deviceInfo.appUpdateTime); - - if (!isInDelay) { - PackageBuilder.addMapJson(parameters, CALLBACK_PARAMETERS, this.sessionParameters.callbackParameters); - PackageBuilder.addMapJson(parameters, PARTNER_PARAMETERS, this.sessionParameters.partnerParameters); - } - - return parameters; - } - - private Map getDefaultParameters() { - Map parameters = new HashMap(); - - injectDeviceInfo(parameters); - injectConfig(parameters); - injectActivityState(parameters); - injectCommonParameters(parameters); - - // general - checkDeviceIds(parameters); - - return parameters; - } - - private Map getIdsParameters() { - Map parameters = new HashMap(); - - injectDeviceInfoIds(parameters); - injectConfig(parameters); - injectCommonParameters(parameters); - - checkDeviceIds(parameters); - - return parameters; - } - - private void injectDeviceInfo(Map parameters) { - injectDeviceInfoIds(parameters); - PackageBuilder.addString(parameters, "fb_id", deviceInfo.fbAttributionId); - PackageBuilder.addString(parameters, "package_name", deviceInfo.packageName); - PackageBuilder.addString(parameters, "app_version", deviceInfo.appVersion); - PackageBuilder.addString(parameters, "device_type", deviceInfo.deviceType); - PackageBuilder.addString(parameters, "device_name", deviceInfo.deviceName); - PackageBuilder.addString(parameters, "device_manufacturer", deviceInfo.deviceManufacturer); - PackageBuilder.addString(parameters, "os_name", deviceInfo.osName); - PackageBuilder.addString(parameters, "os_version", deviceInfo.osVersion); - PackageBuilder.addString(parameters, "api_level", deviceInfo.apiLevel); - PackageBuilder.addString(parameters, "language", deviceInfo.language); - PackageBuilder.addString(parameters, "country", deviceInfo.country); - PackageBuilder.addString(parameters, "screen_size", deviceInfo.screenSize); - PackageBuilder.addString(parameters, "screen_format", deviceInfo.screenFormat); - PackageBuilder.addString(parameters, "screen_density", deviceInfo.screenDensity); - PackageBuilder.addString(parameters, "display_width", deviceInfo.displayWidth); - PackageBuilder.addString(parameters, "display_height", deviceInfo.displayHeight); - PackageBuilder.addString(parameters, "hardware_name", deviceInfo.hardwareName); - PackageBuilder.addString(parameters, "cpu_type", deviceInfo.abi); - PackageBuilder.addString(parameters, "os_build", deviceInfo.buildName); - PackageBuilder.addString(parameters, "mcc", Util.getMcc(adjustConfig.context)); - PackageBuilder.addString(parameters, "mnc", Util.getMnc(adjustConfig.context)); - PackageBuilder.addLong(parameters, "connectivity_type", Util.getConnectivityType(adjustConfig.context)); - PackageBuilder.addLong(parameters, "network_type", Util.getNetworkType(adjustConfig.context)); - } - - private void injectDeviceInfoIds(Map parameters) { - deviceInfo.reloadDeviceIds(adjustConfig.context); - - PackageBuilder.addBoolean(parameters, "tracking_enabled", deviceInfo.isTrackingEnabled); - PackageBuilder.addString(parameters, "gps_adid", deviceInfo.playAdId); - - if (deviceInfo.playAdId == null) { - PackageBuilder.addString(parameters, "mac_sha1", deviceInfo.macSha1); - PackageBuilder.addString(parameters, "mac_md5", deviceInfo.macShortMd5); - PackageBuilder.addString(parameters, "android_id", deviceInfo.androidId); - } - } - - private void injectConfig(Map parameters) { - PackageBuilder.addString(parameters, "app_token", adjustConfig.appToken); - PackageBuilder.addString(parameters, "environment", adjustConfig.environment); - PackageBuilder.addBoolean(parameters, "device_known", adjustConfig.deviceKnown); - - PackageBuilder.addBoolean(parameters, "event_buffering_enabled", adjustConfig.eventBufferingEnabled); - PackageBuilder.addString(parameters, "push_token", activityStateCopy.pushToken); - ContentResolver contentResolver = adjustConfig.context.getContentResolver(); - String fireAdId = Util.getFireAdvertisingId(contentResolver); - PackageBuilder.addString(parameters, "fire_adid", fireAdId); - Boolean fireTrackingEnabled = Util.getFireTrackingEnabled(contentResolver); - PackageBuilder.addBoolean(parameters, "fire_tracking_enabled", fireTrackingEnabled); - - PackageBuilder.addString(parameters, "secret_id", adjustConfig.secretId); - PackageBuilder.addString(parameters, "app_secret", adjustConfig.appSecret); - } - - private void injectActivityState(Map parameters) { - PackageBuilder.addString(parameters, "android_uuid", activityStateCopy.uuid); - PackageBuilder.addLong(parameters, "session_count", activityStateCopy.sessionCount); - PackageBuilder.addLong(parameters, "subsession_count", activityStateCopy.subsessionCount); - PackageBuilder.addDuration(parameters, "session_length", activityStateCopy.sessionLength); - PackageBuilder.addDuration(parameters, "time_spent", activityStateCopy.timeSpent); - } - - private void injectCommonParameters(Map parameters) { - PackageBuilder.addDateInMilliseconds(parameters, "created_at", createdAt); - PackageBuilder.addBoolean(parameters, "attribution_deeplink", true); - PackageBuilder.addBoolean(parameters, "needs_response_details", true); - } - - private void injectAttribution(Map parameters) { - if (attribution == null) { - return; - } - PackageBuilder.addString(parameters, "tracker", attribution.trackerName); - PackageBuilder.addString(parameters, "campaign", attribution.campaign); - PackageBuilder.addString(parameters, "adgroup", attribution.adgroup); - PackageBuilder.addString(parameters, "creative", attribution.creative); - } - - private void checkDeviceIds(Map parameters) { - if (!parameters.containsKey("mac_sha1") - && !parameters.containsKey("mac_md5") - && !parameters.containsKey("android_id") - && !parameters.containsKey("gps_adid")) { - logger.error("Missing device id's. Please check if Proguard is correctly set with Adjust SDK"); - } - } - - private String getEventSuffix(AdjustEvent event) { - if (event.revenue == null) { - return Util.formatString("'%s'", event.eventToken); - } else { - return Util.formatString("(%.5f %s, '%s')", event.revenue, event.currency, event.eventToken); - } - } - - public static void addString(Map parameters, String key, String value) { - if (TextUtils.isEmpty(value)) { - return; - } - - parameters.put(key, value); - } - - public static void addLong(Map parameters, String key, long value) { - if (value < 0) { - return; - } - - String valueString = Long.toString(value); - PackageBuilder.addString(parameters, key, valueString); - } - - public static void addDateInMilliseconds(Map parameters, String key, long value) { - if (value <= 0) { - return; - } - - Date date = new Date(value); - PackageBuilder.addDate(parameters, key, date); - } - - public static void addDateInSeconds(Map parameters, String key, long value) { - if (value <= 0) { - return; - } - - Date date = new Date(value * 1000); - PackageBuilder.addDate(parameters, key, date); - } - - public static void addDate(Map parameters, String key, Date value) { - if (value == null) { - return; - } - - String dateString = Util.dateFormatter.format(value); - PackageBuilder.addString(parameters, key, dateString); - } - - public static void addDuration(Map parameters, String key, long durationInMilliSeconds) { - if (durationInMilliSeconds < 0) { - return; - } - - long durationInSeconds = (durationInMilliSeconds + 500) / 1000; - PackageBuilder.addLong(parameters, key, durationInSeconds); - } - - public static void addMapJson(Map parameters, String key, Map map) { - if (map == null) { - return; - } - - if (map.size() == 0) { - return; - } - - JSONObject jsonObject = new JSONObject(map); - String jsonString = jsonObject.toString(); - - PackageBuilder.addString(parameters, key, jsonString); - } - - public static void addBoolean(Map parameters, String key, Boolean value) { - if (value == null) { - return; - } - - int intValue = value ? 1 : 0; - - PackageBuilder.addLong(parameters, key, intValue); - } - - public static void addDouble(Map parameters, String key, Double value) { - if (value == null) return; - - String doubleString = Util.formatString("%.5f", value); - - PackageBuilder.addString(parameters, key, doubleString); - } -} diff --git a/Adjust/build.gradle b/Adjust/build.gradle index e5dd4c73d..4a41c449e 100644 --- a/Adjust/build.gradle +++ b/Adjust/build.gradle @@ -1,16 +1,34 @@ // Top-level build file where you can add configuration options common to all sub-projects/modules. +// common in all sub-projects +subprojects { +} + +ext { + // Android config. + coreMinSdkVersion = 9 + coreCompileSdkVersion = 28 + coreTargetSdkVersion = 28 + coreVersionName = '4.16.0' + defaultVersionCode = 1 + + // POM. + adjustGroupId = 'com.adjust.sdk' +} + buildscript { + ext.kotlin_version = '1.2.71' + repositories { jcenter() google() } dependencies { - classpath 'com.android.tools.build:gradle:3.1.4' + classpath 'com.android.tools.build:gradle:3.2.1' // NOTE: Do not place your application dependencies here; they belong - // in the individual module build.gradle files - } + // in the individual module build.gradle files. + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" } } allprojects { diff --git a/Adjust/example-fbpixel/.gitignore b/Adjust/example-app-fbpixel/.gitignore similarity index 100% rename from Adjust/example-fbpixel/.gitignore rename to Adjust/example-app-fbpixel/.gitignore diff --git a/Adjust/example-fbpixel/build.gradle b/Adjust/example-app-fbpixel/build.gradle similarity index 83% rename from Adjust/example-fbpixel/build.gradle rename to Adjust/example-app-fbpixel/build.gradle index f4d06aaad..6b2cf453c 100644 --- a/Adjust/example-fbpixel/build.gradle +++ b/Adjust/example-app-fbpixel/build.gradle @@ -3,17 +3,13 @@ apply plugin: 'com.android.application' android { compileSdkVersion 28 - - defaultConfig { applicationId "com.adjust.examples" minSdkVersion 14 targetSdkVersion 28 versionCode 1 versionName "1.0" - testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" - } buildTypes { @@ -22,16 +18,14 @@ android { proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } - } dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) - implementation project(':adjust') - implementation project(':webbridge') - - implementation 'com.android.support:appcompat-v7:28.0.0-rc01' - implementation 'com.android.support.constraint:constraint-layout:1.1.2' + implementation project(':sdk-core') + implementation project(':sdk-webbridge') + implementation 'com.android.support:appcompat-v7:28.0.0' + implementation 'com.android.support.constraint:constraint-layout:1.1.3' testImplementation 'junit:junit:4.12' androidTestImplementation 'com.android.support.test:runner:1.0.2' androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' diff --git a/Adjust/example-fbpixel/proguard-rules.pro b/Adjust/example-app-fbpixel/proguard-rules.pro similarity index 100% rename from Adjust/example-fbpixel/proguard-rules.pro rename to Adjust/example-app-fbpixel/proguard-rules.pro diff --git a/Adjust/example-fbpixel/src/androidTest/java/com/adjust/examples/ExampleInstrumentedTest.java b/Adjust/example-app-fbpixel/src/androidTest/java/com/adjust/examples/ExampleInstrumentedTest.java similarity index 100% rename from Adjust/example-fbpixel/src/androidTest/java/com/adjust/examples/ExampleInstrumentedTest.java rename to Adjust/example-app-fbpixel/src/androidTest/java/com/adjust/examples/ExampleInstrumentedTest.java diff --git a/Adjust/example-fbpixel/src/main/AndroidManifest.xml b/Adjust/example-app-fbpixel/src/main/AndroidManifest.xml similarity index 100% rename from Adjust/example-fbpixel/src/main/AndroidManifest.xml rename to Adjust/example-app-fbpixel/src/main/AndroidManifest.xml diff --git a/Adjust/example-fbpixel/src/main/assets/AdjustExample-FbPixel.html b/Adjust/example-app-fbpixel/src/main/assets/AdjustExample-FbPixel.html similarity index 100% rename from Adjust/example-fbpixel/src/main/assets/AdjustExample-FbPixel.html rename to Adjust/example-app-fbpixel/src/main/assets/AdjustExample-FbPixel.html diff --git a/Adjust/example-fbpixel/src/main/java/com/adjust/examples/MainActivity.java b/Adjust/example-app-fbpixel/src/main/java/com/adjust/examples/MainActivity.java similarity index 93% rename from Adjust/example-fbpixel/src/main/java/com/adjust/examples/MainActivity.java rename to Adjust/example-app-fbpixel/src/main/java/com/adjust/examples/MainActivity.java index f6ce591e3..aace8111c 100644 --- a/Adjust/example-fbpixel/src/main/java/com/adjust/examples/MainActivity.java +++ b/Adjust/example-app-fbpixel/src/main/java/com/adjust/examples/MainActivity.java @@ -10,8 +10,8 @@ import android.webkit.WebView; import android.webkit.WebViewClient; -import com.adjust.sdk.bridge.AdjustBridge; -import com.adjust.sdk.bridge.AdjustBridgeInstance; +import com.adjust.sdk.webbridge.AdjustBridge; +import com.adjust.sdk.webbridge.AdjustBridgeInstance; public class MainActivity extends AppCompatActivity { diff --git a/Adjust/example-fbpixel/src/main/res/drawable-v24/ic_launcher_foreground.xml b/Adjust/example-app-fbpixel/src/main/res/drawable-v24/ic_launcher_foreground.xml similarity index 100% rename from Adjust/example-fbpixel/src/main/res/drawable-v24/ic_launcher_foreground.xml rename to Adjust/example-app-fbpixel/src/main/res/drawable-v24/ic_launcher_foreground.xml diff --git a/Adjust/example-fbpixel/src/main/res/drawable/ic_launcher_background.xml b/Adjust/example-app-fbpixel/src/main/res/drawable/ic_launcher_background.xml similarity index 100% rename from Adjust/example-fbpixel/src/main/res/drawable/ic_launcher_background.xml rename to Adjust/example-app-fbpixel/src/main/res/drawable/ic_launcher_background.xml diff --git a/Adjust/example-fbpixel/src/main/res/layout/activity_main.xml b/Adjust/example-app-fbpixel/src/main/res/layout/activity_main.xml similarity index 100% rename from Adjust/example-fbpixel/src/main/res/layout/activity_main.xml rename to Adjust/example-app-fbpixel/src/main/res/layout/activity_main.xml diff --git a/Adjust/example-fbpixel/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/Adjust/example-app-fbpixel/src/main/res/mipmap-anydpi-v26/ic_launcher.xml similarity index 100% rename from Adjust/example-fbpixel/src/main/res/mipmap-anydpi-v26/ic_launcher.xml rename to Adjust/example-app-fbpixel/src/main/res/mipmap-anydpi-v26/ic_launcher.xml diff --git a/Adjust/example-fbpixel/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/Adjust/example-app-fbpixel/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml similarity index 100% rename from Adjust/example-fbpixel/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml rename to Adjust/example-app-fbpixel/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml diff --git a/Adjust/example-fbpixel/src/main/res/mipmap-hdpi/ic_launcher.png b/Adjust/example-app-fbpixel/src/main/res/mipmap-hdpi/ic_launcher.png similarity index 100% rename from Adjust/example-fbpixel/src/main/res/mipmap-hdpi/ic_launcher.png rename to Adjust/example-app-fbpixel/src/main/res/mipmap-hdpi/ic_launcher.png diff --git a/Adjust/example-fbpixel/src/main/res/mipmap-hdpi/ic_launcher_round.png b/Adjust/example-app-fbpixel/src/main/res/mipmap-hdpi/ic_launcher_round.png similarity index 100% rename from Adjust/example-fbpixel/src/main/res/mipmap-hdpi/ic_launcher_round.png rename to Adjust/example-app-fbpixel/src/main/res/mipmap-hdpi/ic_launcher_round.png diff --git a/Adjust/example-fbpixel/src/main/res/mipmap-mdpi/ic_launcher.png b/Adjust/example-app-fbpixel/src/main/res/mipmap-mdpi/ic_launcher.png similarity index 100% rename from Adjust/example-fbpixel/src/main/res/mipmap-mdpi/ic_launcher.png rename to Adjust/example-app-fbpixel/src/main/res/mipmap-mdpi/ic_launcher.png diff --git a/Adjust/example-fbpixel/src/main/res/mipmap-mdpi/ic_launcher_round.png b/Adjust/example-app-fbpixel/src/main/res/mipmap-mdpi/ic_launcher_round.png similarity index 100% rename from Adjust/example-fbpixel/src/main/res/mipmap-mdpi/ic_launcher_round.png rename to Adjust/example-app-fbpixel/src/main/res/mipmap-mdpi/ic_launcher_round.png diff --git a/Adjust/example-fbpixel/src/main/res/mipmap-xhdpi/ic_launcher.png b/Adjust/example-app-fbpixel/src/main/res/mipmap-xhdpi/ic_launcher.png similarity index 100% rename from Adjust/example-fbpixel/src/main/res/mipmap-xhdpi/ic_launcher.png rename to Adjust/example-app-fbpixel/src/main/res/mipmap-xhdpi/ic_launcher.png diff --git a/Adjust/example-fbpixel/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/Adjust/example-app-fbpixel/src/main/res/mipmap-xhdpi/ic_launcher_round.png similarity index 100% rename from Adjust/example-fbpixel/src/main/res/mipmap-xhdpi/ic_launcher_round.png rename to Adjust/example-app-fbpixel/src/main/res/mipmap-xhdpi/ic_launcher_round.png diff --git a/Adjust/example-fbpixel/src/main/res/mipmap-xxhdpi/ic_launcher.png b/Adjust/example-app-fbpixel/src/main/res/mipmap-xxhdpi/ic_launcher.png similarity index 100% rename from Adjust/example-fbpixel/src/main/res/mipmap-xxhdpi/ic_launcher.png rename to Adjust/example-app-fbpixel/src/main/res/mipmap-xxhdpi/ic_launcher.png diff --git a/Adjust/example-fbpixel/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/Adjust/example-app-fbpixel/src/main/res/mipmap-xxhdpi/ic_launcher_round.png similarity index 100% rename from Adjust/example-fbpixel/src/main/res/mipmap-xxhdpi/ic_launcher_round.png rename to Adjust/example-app-fbpixel/src/main/res/mipmap-xxhdpi/ic_launcher_round.png diff --git a/Adjust/example-fbpixel/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/Adjust/example-app-fbpixel/src/main/res/mipmap-xxxhdpi/ic_launcher.png similarity index 100% rename from Adjust/example-fbpixel/src/main/res/mipmap-xxxhdpi/ic_launcher.png rename to Adjust/example-app-fbpixel/src/main/res/mipmap-xxxhdpi/ic_launcher.png diff --git a/Adjust/example-fbpixel/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/Adjust/example-app-fbpixel/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png similarity index 100% rename from Adjust/example-fbpixel/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png rename to Adjust/example-app-fbpixel/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png diff --git a/Adjust/example-fbpixel/src/main/res/values/colors.xml b/Adjust/example-app-fbpixel/src/main/res/values/colors.xml similarity index 100% rename from Adjust/example-fbpixel/src/main/res/values/colors.xml rename to Adjust/example-app-fbpixel/src/main/res/values/colors.xml diff --git a/Adjust/example-fbpixel/src/main/res/values/strings.xml b/Adjust/example-app-fbpixel/src/main/res/values/strings.xml similarity index 100% rename from Adjust/example-fbpixel/src/main/res/values/strings.xml rename to Adjust/example-app-fbpixel/src/main/res/values/strings.xml diff --git a/Adjust/example-fbpixel/src/main/res/values/styles.xml b/Adjust/example-app-fbpixel/src/main/res/values/styles.xml similarity index 100% rename from Adjust/example-fbpixel/src/main/res/values/styles.xml rename to Adjust/example-app-fbpixel/src/main/res/values/styles.xml diff --git a/Adjust/example-fbpixel/src/test/java/com/adjust/examples/ExampleUnitTest.java b/Adjust/example-app-fbpixel/src/test/java/com/adjust/examples/ExampleUnitTest.java similarity index 100% rename from Adjust/example-fbpixel/src/test/java/com/adjust/examples/ExampleUnitTest.java rename to Adjust/example-app-fbpixel/src/test/java/com/adjust/examples/ExampleUnitTest.java diff --git a/Adjust/example/build.gradle b/Adjust/example-app-java/build.gradle similarity index 62% rename from Adjust/example/build.gradle rename to Adjust/example-app-java/build.gradle index 7c588d675..9895199f4 100644 --- a/Adjust/example/build.gradle +++ b/Adjust/example-app-java/build.gradle @@ -1,13 +1,18 @@ apply plugin: 'com.android.application' +repositories { + maven { + url "https://oss.sonatype.org/content/repositories/staging/" + } +} + android { - compileSdkVersion 26 - buildToolsVersion '27.0.3' + compileSdkVersion 28 defaultConfig { applicationId "com.adjust.examples" minSdkVersion 14 - targetSdkVersion 26 + targetSdkVersion 28 versionCode 1 versionName "1.0" } @@ -20,17 +25,18 @@ android { } dependencies { - implementation 'com.android.support:appcompat-v7:26.1.0' - implementation 'com.google.android.gms:play-services-analytics:11.8.0' + implementation 'com.android.support:appcompat-v7:28.0.0' + implementation 'com.google.android.gms:play-services-analytics:16.0.4' // Add SDK via module. - implementation project(":adjust") + implementation project(':sdk-core') + // implementation project(':plugin-imei') + // implementation project(":plugin-play") // Add SDK via Maven. - // implementation 'com.adjust.sdk:adjust-android:4.15.1' + // implementation 'com.adjust.sdk:adjust-android:4.16.0' - debugImplementation 'com.squareup.leakcanary:leakcanary-android:1.5.4' - releaseImplementation 'com.squareup.leakcanary:leakcanary-android-no-op:1.5.4' - testImplementation 'com.squareup.leakcanary:leakcanary-android-no-op:1.5.4' + debugImplementation 'com.squareup.leakcanary:leakcanary-android:1.6.2' + releaseImplementation 'com.squareup.leakcanary:leakcanary-android-no-op:1.6.2' // Add new referrer API support. implementation 'com.android.installreferrer:installreferrer:1.0' diff --git a/Adjust/example/proguard-rules.pro b/Adjust/example-app-java/proguard-rules.pro similarity index 74% rename from Adjust/example/proguard-rules.pro rename to Adjust/example-app-java/proguard-rules.pro index 9708978d6..27f2a6a1c 100644 --- a/Adjust/example/proguard-rules.pro +++ b/Adjust/example-app-java/proguard-rules.pro @@ -15,8 +15,10 @@ #-keepclassmembers class fqcn.of.javascript.interface.for.webview { # public *; #} - -keep public class com.adjust.sdk.** { *; } +-keep class com.google.android.gms.common.ConnectionResult { + int SUCCESS; +} -keep class com.google.android.gms.ads.identifier.AdvertisingIdClient { com.google.android.gms.ads.identifier.AdvertisingIdClient$Info getAdvertisingIdInfo(android.content.Context); } @@ -24,17 +26,4 @@ java.lang.String getId(); boolean isLimitAdTrackingEnabled(); } --keep class dalvik.system.VMRuntime { - java.lang.String getRuntime(); -} --keep class android.os.Build { - java.lang.String[] SUPPORTED_ABIS; - java.lang.String CPU_ABI; -} --keep class android.content.res.Configuration { - android.os.LocaleList getLocales(); - java.util.Locale locale; -} --keep class android.os.LocaleList { - java.util.Locale get(int); -} +-keep public class com.android.installreferrer.** { *; } diff --git a/Adjust/example-tv/src/androidTest/java/com/adjust/examples/ApplicationTest.java b/Adjust/example-app-java/src/androidTest/java/com/adjust/examples/ApplicationTest.java old mode 100755 new mode 100644 similarity index 100% rename from Adjust/example-tv/src/androidTest/java/com/adjust/examples/ApplicationTest.java rename to Adjust/example-app-java/src/androidTest/java/com/adjust/examples/ApplicationTest.java diff --git a/Adjust/example/src/main/AndroidManifest.xml b/Adjust/example-app-java/src/main/AndroidManifest.xml similarity index 87% rename from Adjust/example/src/main/AndroidManifest.xml rename to Adjust/example-app-java/src/main/AndroidManifest.xml index 5f8b78ad2..693f75e5a 100644 --- a/Adjust/example/src/main/AndroidManifest.xml +++ b/Adjust/example-app-java/src/main/AndroidManifest.xml @@ -1,11 +1,10 @@ - - + + - - - - + + - - \ No newline at end of file diff --git a/Adjust/example/src/main/java/com/adjust/examples/GlobalApplication.java b/Adjust/example-app-java/src/main/java/com/adjust/examples/GlobalApplication.java similarity index 97% rename from Adjust/example/src/main/java/com/adjust/examples/GlobalApplication.java rename to Adjust/example-app-java/src/main/java/com/adjust/examples/GlobalApplication.java index b69777cf2..573ade0d5 100644 --- a/Adjust/example/src/main/java/com/adjust/examples/GlobalApplication.java +++ b/Adjust/example-app-java/src/main/java/com/adjust/examples/GlobalApplication.java @@ -29,15 +29,14 @@ public class GlobalApplication extends Application { @Override public void onCreate() { + super.onCreate(); if (LeakCanary.isInAnalyzerProcess(this)) { // This process is dedicated to LeakCanary for heap analysis. // You should not init your app in this process. return; } - super.onCreate(); - LeakCanary.install(this); - +/* StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder() .detectAll() .penaltyLog() @@ -46,7 +45,7 @@ public void onCreate() { .detectAll() .penaltyLog() .build()); - +*/ // Configure adjust SDK. String appToken = "2fm9gkqubvpc"; String environment = AdjustConfig.ENVIRONMENT_SANDBOX; @@ -147,6 +146,11 @@ public boolean launchReceivedDeeplink(Uri deeplink) { // Remove all session partner parameters. Adjust.resetSessionPartnerParameters(); + // Enable IMEI reading ONLY IF: + // - IMEI plugin is added to your app. + // - Your app is NOT distributed in Google Play Store. + // AdjustImei.readImei(); + // Initialise the adjust SDK. Adjust.onCreate(config); diff --git a/Adjust/example/src/main/java/com/adjust/examples/MainActivity.java b/Adjust/example-app-java/src/main/java/com/adjust/examples/MainActivity.java similarity index 100% rename from Adjust/example/src/main/java/com/adjust/examples/MainActivity.java rename to Adjust/example-app-java/src/main/java/com/adjust/examples/MainActivity.java diff --git a/Adjust/example/src/main/java/com/adjust/examples/ServiceActivity.java b/Adjust/example-app-java/src/main/java/com/adjust/examples/ServiceActivity.java similarity index 100% rename from Adjust/example/src/main/java/com/adjust/examples/ServiceActivity.java rename to Adjust/example-app-java/src/main/java/com/adjust/examples/ServiceActivity.java diff --git a/Adjust/example/src/main/java/com/adjust/examples/ServiceExample.java b/Adjust/example-app-java/src/main/java/com/adjust/examples/ServiceExample.java similarity index 100% rename from Adjust/example/src/main/java/com/adjust/examples/ServiceExample.java rename to Adjust/example-app-java/src/main/java/com/adjust/examples/ServiceExample.java diff --git a/Adjust/example/src/main/res/layout/activity_main.xml b/Adjust/example-app-java/src/main/res/layout/activity_main.xml similarity index 100% rename from Adjust/example/src/main/res/layout/activity_main.xml rename to Adjust/example-app-java/src/main/res/layout/activity_main.xml diff --git a/Adjust/example/src/main/res/layout/activity_service.xml b/Adjust/example-app-java/src/main/res/layout/activity_service.xml similarity index 100% rename from Adjust/example/src/main/res/layout/activity_service.xml rename to Adjust/example-app-java/src/main/res/layout/activity_service.xml diff --git a/Adjust/example/src/main/res/menu/menu_main.xml b/Adjust/example-app-java/src/main/res/menu/menu_main.xml similarity index 100% rename from Adjust/example/src/main/res/menu/menu_main.xml rename to Adjust/example-app-java/src/main/res/menu/menu_main.xml diff --git a/Adjust/example-tv/src/main/res/mipmap-hdpi/ic_launcher.png b/Adjust/example-app-java/src/main/res/mipmap-hdpi/ic_launcher.png old mode 100755 new mode 100644 similarity index 100% rename from Adjust/example-tv/src/main/res/mipmap-hdpi/ic_launcher.png rename to Adjust/example-app-java/src/main/res/mipmap-hdpi/ic_launcher.png diff --git a/Adjust/example-tv/src/main/res/mipmap-mdpi/ic_launcher.png b/Adjust/example-app-java/src/main/res/mipmap-mdpi/ic_launcher.png old mode 100755 new mode 100644 similarity index 100% rename from Adjust/example-tv/src/main/res/mipmap-mdpi/ic_launcher.png rename to Adjust/example-app-java/src/main/res/mipmap-mdpi/ic_launcher.png diff --git a/Adjust/example-tv/src/main/res/mipmap-xhdpi/ic_launcher.png b/Adjust/example-app-java/src/main/res/mipmap-xhdpi/ic_launcher.png old mode 100755 new mode 100644 similarity index 100% rename from Adjust/example-tv/src/main/res/mipmap-xhdpi/ic_launcher.png rename to Adjust/example-app-java/src/main/res/mipmap-xhdpi/ic_launcher.png diff --git a/Adjust/example-tv/src/main/res/mipmap-xxhdpi/ic_launcher.png b/Adjust/example-app-java/src/main/res/mipmap-xxhdpi/ic_launcher.png old mode 100755 new mode 100644 similarity index 100% rename from Adjust/example-tv/src/main/res/mipmap-xxhdpi/ic_launcher.png rename to Adjust/example-app-java/src/main/res/mipmap-xxhdpi/ic_launcher.png diff --git a/Adjust/example-tv/src/main/res/values-w820dp/dimens.xml b/Adjust/example-app-java/src/main/res/values-w820dp/dimens.xml old mode 100755 new mode 100644 similarity index 100% rename from Adjust/example-tv/src/main/res/values-w820dp/dimens.xml rename to Adjust/example-app-java/src/main/res/values-w820dp/dimens.xml diff --git a/Adjust/example-tv/src/main/res/values/dimens.xml b/Adjust/example-app-java/src/main/res/values/dimens.xml old mode 100755 new mode 100644 similarity index 100% rename from Adjust/example-tv/src/main/res/values/dimens.xml rename to Adjust/example-app-java/src/main/res/values/dimens.xml diff --git a/Adjust/example/src/main/res/values/strings.xml b/Adjust/example-app-java/src/main/res/values/strings.xml similarity index 100% rename from Adjust/example/src/main/res/values/strings.xml rename to Adjust/example-app-java/src/main/res/values/strings.xml diff --git a/Adjust/example/src/main/res/values/styles.xml b/Adjust/example-app-java/src/main/res/values/styles.xml similarity index 100% rename from Adjust/example/src/main/res/values/styles.xml rename to Adjust/example-app-java/src/main/res/values/styles.xml diff --git a/Adjust/example-tv/build.gradle b/Adjust/example-app-tv/build.gradle similarity index 64% rename from Adjust/example-tv/build.gradle rename to Adjust/example-app-tv/build.gradle index 0684641c2..0f2d223e6 100755 --- a/Adjust/example-tv/build.gradle +++ b/Adjust/example-app-tv/build.gradle @@ -1,13 +1,18 @@ apply plugin: 'com.android.application' +repositories { + maven { + url "https://oss.sonatype.org/content/repositories/staging/" + } +} + android { - compileSdkVersion 26 - buildToolsVersion '27.0.3' + compileSdkVersion 28 defaultConfig { applicationId "com.adjust.examples" minSdkVersion 21 - targetSdkVersion 26 + targetSdkVersion 28 versionCode 1 versionName "1.0" } @@ -21,10 +26,9 @@ android { dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) - implementation 'com.android.support:leanback-v17:26.1.0' - implementation 'com.android.support:appcompat-v7:26.1.0' - - implementation project(":adjust") + implementation 'com.android.support:leanback-v17:28.0.0' + implementation 'com.android.support:appcompat-v7:28.0.0' + implementation project(':sdk-core') implementation 'com.android.installreferrer:installreferrer:1.0' - implementation 'com.google.android.gms:play-services-analytics:15.0.2' + implementation 'com.google.android.gms:play-services-analytics:16.0.4' } diff --git a/Adjust/example-tv/proguard-rules.pro b/Adjust/example-app-tv/proguard-rules.pro similarity index 100% rename from Adjust/example-tv/proguard-rules.pro rename to Adjust/example-app-tv/proguard-rules.pro diff --git a/Adjust/example/src/androidTest/java/com/adjust/examples/ApplicationTest.java b/Adjust/example-app-tv/src/androidTest/java/com/adjust/examples/ApplicationTest.java old mode 100644 new mode 100755 similarity index 100% rename from Adjust/example/src/androidTest/java/com/adjust/examples/ApplicationTest.java rename to Adjust/example-app-tv/src/androidTest/java/com/adjust/examples/ApplicationTest.java diff --git a/Adjust/example-tv/src/main/AndroidManifest.xml b/Adjust/example-app-tv/src/main/AndroidManifest.xml similarity index 100% rename from Adjust/example-tv/src/main/AndroidManifest.xml rename to Adjust/example-app-tv/src/main/AndroidManifest.xml diff --git a/Adjust/example-tv/src/main/java/com/adjust/examples/GlobalApplication.java b/Adjust/example-app-tv/src/main/java/com/adjust/examples/GlobalApplication.java similarity index 100% rename from Adjust/example-tv/src/main/java/com/adjust/examples/GlobalApplication.java rename to Adjust/example-app-tv/src/main/java/com/adjust/examples/GlobalApplication.java diff --git a/Adjust/example-tv/src/main/java/com/adjust/examples/MainActivity.java b/Adjust/example-app-tv/src/main/java/com/adjust/examples/MainActivity.java similarity index 100% rename from Adjust/example-tv/src/main/java/com/adjust/examples/MainActivity.java rename to Adjust/example-app-tv/src/main/java/com/adjust/examples/MainActivity.java diff --git a/Adjust/example-tv/src/main/res/layout/activity_main.xml b/Adjust/example-app-tv/src/main/res/layout/activity_main.xml similarity index 100% rename from Adjust/example-tv/src/main/res/layout/activity_main.xml rename to Adjust/example-app-tv/src/main/res/layout/activity_main.xml diff --git a/Adjust/example/src/main/res/mipmap-hdpi/ic_launcher.png b/Adjust/example-app-tv/src/main/res/mipmap-hdpi/ic_launcher.png old mode 100644 new mode 100755 similarity index 100% rename from Adjust/example/src/main/res/mipmap-hdpi/ic_launcher.png rename to Adjust/example-app-tv/src/main/res/mipmap-hdpi/ic_launcher.png diff --git a/Adjust/example/src/main/res/mipmap-mdpi/ic_launcher.png b/Adjust/example-app-tv/src/main/res/mipmap-mdpi/ic_launcher.png old mode 100644 new mode 100755 similarity index 100% rename from Adjust/example/src/main/res/mipmap-mdpi/ic_launcher.png rename to Adjust/example-app-tv/src/main/res/mipmap-mdpi/ic_launcher.png diff --git a/Adjust/example/src/main/res/mipmap-xhdpi/ic_launcher.png b/Adjust/example-app-tv/src/main/res/mipmap-xhdpi/ic_launcher.png old mode 100644 new mode 100755 similarity index 100% rename from Adjust/example/src/main/res/mipmap-xhdpi/ic_launcher.png rename to Adjust/example-app-tv/src/main/res/mipmap-xhdpi/ic_launcher.png diff --git a/Adjust/example/src/main/res/mipmap-xxhdpi/ic_launcher.png b/Adjust/example-app-tv/src/main/res/mipmap-xxhdpi/ic_launcher.png old mode 100644 new mode 100755 similarity index 100% rename from Adjust/example/src/main/res/mipmap-xxhdpi/ic_launcher.png rename to Adjust/example-app-tv/src/main/res/mipmap-xxhdpi/ic_launcher.png diff --git a/Adjust/example/src/main/res/values-w820dp/dimens.xml b/Adjust/example-app-tv/src/main/res/values-w820dp/dimens.xml old mode 100644 new mode 100755 similarity index 100% rename from Adjust/example/src/main/res/values-w820dp/dimens.xml rename to Adjust/example-app-tv/src/main/res/values-w820dp/dimens.xml diff --git a/Adjust/example/src/main/res/values/dimens.xml b/Adjust/example-app-tv/src/main/res/values/dimens.xml old mode 100644 new mode 100755 similarity index 100% rename from Adjust/example/src/main/res/values/dimens.xml rename to Adjust/example-app-tv/src/main/res/values/dimens.xml diff --git a/Adjust/example-tv/src/main/res/values/strings.xml b/Adjust/example-app-tv/src/main/res/values/strings.xml similarity index 100% rename from Adjust/example-tv/src/main/res/values/strings.xml rename to Adjust/example-app-tv/src/main/res/values/strings.xml diff --git a/Adjust/example-tv/src/main/res/values/styles.xml b/Adjust/example-app-tv/src/main/res/values/styles.xml similarity index 100% rename from Adjust/example-tv/src/main/res/values/styles.xml rename to Adjust/example-app-tv/src/main/res/values/styles.xml diff --git a/Adjust/example-webbridge/.gitignore b/Adjust/example-app-webbridge/.gitignore similarity index 100% rename from Adjust/example-webbridge/.gitignore rename to Adjust/example-app-webbridge/.gitignore diff --git a/Adjust/example-webbridge/build.gradle b/Adjust/example-app-webbridge/build.gradle similarity index 74% rename from Adjust/example-webbridge/build.gradle rename to Adjust/example-app-webbridge/build.gradle index 6d009cfa9..65e46a00c 100644 --- a/Adjust/example-webbridge/build.gradle +++ b/Adjust/example-app-webbridge/build.gradle @@ -1,19 +1,15 @@ apply plugin: 'com.android.application' android { - compileSdkVersion 27 - - + compileSdkVersion 28 defaultConfig { applicationId "com.example.examples" minSdkVersion 14 - targetSdkVersion 27 + targetSdkVersion 28 versionCode 1 versionName "1.0" - testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" - } buildTypes { release { @@ -21,16 +17,15 @@ android { proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } - buildToolsVersion '27.0.3' } dependencies { implementation fileTree(include: ['*.jar'], dir: 'libs') - implementation project(':adjust') - implementation project(':webbridge') - implementation 'com.android.support:appcompat-v7:27.0.2' - implementation 'com.android.support.constraint:constraint-layout:1.0.2' + implementation project(':sdk-core') + implementation project(':sdk-webbridge') + implementation 'com.android.support:appcompat-v7:28.0.0' + implementation 'com.android.support.constraint:constraint-layout:1.1.3' testImplementation 'junit:junit:4.12' - androidTestImplementation 'com.android.support.test:runner:1.0.1' - androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1' + androidTestImplementation 'com.android.support.test:runner:1.0.2' + androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' } diff --git a/Adjust/example-webbridge/proguard-rules.pro b/Adjust/example-app-webbridge/proguard-rules.pro similarity index 100% rename from Adjust/example-webbridge/proguard-rules.pro rename to Adjust/example-app-webbridge/proguard-rules.pro diff --git a/Adjust/example-webbridge/src/androidTest/java/com/example/examples/ExampleInstrumentedTest.java b/Adjust/example-app-webbridge/src/androidTest/java/com/example/examples/ExampleInstrumentedTest.java similarity index 100% rename from Adjust/example-webbridge/src/androidTest/java/com/example/examples/ExampleInstrumentedTest.java rename to Adjust/example-app-webbridge/src/androidTest/java/com/example/examples/ExampleInstrumentedTest.java diff --git a/Adjust/example-webbridge/src/main/AndroidManifest.xml b/Adjust/example-app-webbridge/src/main/AndroidManifest.xml similarity index 100% rename from Adjust/example-webbridge/src/main/AndroidManifest.xml rename to Adjust/example-app-webbridge/src/main/AndroidManifest.xml diff --git a/Adjust/example-webbridge/src/main/assets/AdjustExample-WebView.html b/Adjust/example-app-webbridge/src/main/assets/AdjustExample-WebView.html similarity index 100% rename from Adjust/example-webbridge/src/main/assets/AdjustExample-WebView.html rename to Adjust/example-app-webbridge/src/main/assets/AdjustExample-WebView.html diff --git a/Adjust/example-webbridge/src/main/java/com/example/examples/MainActivity.java b/Adjust/example-app-webbridge/src/main/java/com/example/examples/MainActivity.java similarity index 86% rename from Adjust/example-webbridge/src/main/java/com/example/examples/MainActivity.java rename to Adjust/example-app-webbridge/src/main/java/com/example/examples/MainActivity.java index d7b03c3a1..119f3ece6 100644 --- a/Adjust/example-webbridge/src/main/java/com/example/examples/MainActivity.java +++ b/Adjust/example-app-webbridge/src/main/java/com/example/examples/MainActivity.java @@ -1,15 +1,13 @@ package com.example.examples; -import android.content.Intent; -import android.net.Uri; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.webkit.WebChromeClient; import android.webkit.WebView; import android.webkit.WebViewClient; -import com.adjust.sdk.bridge.AdjustBridge; -import com.adjust.sdk.bridge.AdjustBridgeInstance; +import com.adjust.sdk.webbridge.AdjustBridge; +import com.adjust.sdk.webbridge.AdjustBridgeInstance; public class MainActivity extends AppCompatActivity { diff --git a/Adjust/example-webbridge/src/main/res/drawable-v24/ic_launcher_foreground.xml b/Adjust/example-app-webbridge/src/main/res/drawable-v24/ic_launcher_foreground.xml similarity index 100% rename from Adjust/example-webbridge/src/main/res/drawable-v24/ic_launcher_foreground.xml rename to Adjust/example-app-webbridge/src/main/res/drawable-v24/ic_launcher_foreground.xml diff --git a/Adjust/example-webbridge/src/main/res/drawable/ic_launcher_background.xml b/Adjust/example-app-webbridge/src/main/res/drawable/ic_launcher_background.xml similarity index 100% rename from Adjust/example-webbridge/src/main/res/drawable/ic_launcher_background.xml rename to Adjust/example-app-webbridge/src/main/res/drawable/ic_launcher_background.xml diff --git a/Adjust/example-webbridge/src/main/res/layout/activity_main.xml b/Adjust/example-app-webbridge/src/main/res/layout/activity_main.xml similarity index 100% rename from Adjust/example-webbridge/src/main/res/layout/activity_main.xml rename to Adjust/example-app-webbridge/src/main/res/layout/activity_main.xml diff --git a/Adjust/example-webbridge/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/Adjust/example-app-webbridge/src/main/res/mipmap-anydpi-v26/ic_launcher.xml similarity index 100% rename from Adjust/example-webbridge/src/main/res/mipmap-anydpi-v26/ic_launcher.xml rename to Adjust/example-app-webbridge/src/main/res/mipmap-anydpi-v26/ic_launcher.xml diff --git a/Adjust/example-webbridge/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/Adjust/example-app-webbridge/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml similarity index 100% rename from Adjust/example-webbridge/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml rename to Adjust/example-app-webbridge/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml diff --git a/Adjust/example-webbridge/src/main/res/mipmap-hdpi/ic_launcher.png b/Adjust/example-app-webbridge/src/main/res/mipmap-hdpi/ic_launcher.png similarity index 100% rename from Adjust/example-webbridge/src/main/res/mipmap-hdpi/ic_launcher.png rename to Adjust/example-app-webbridge/src/main/res/mipmap-hdpi/ic_launcher.png diff --git a/Adjust/example-webbridge/src/main/res/mipmap-hdpi/ic_launcher_round.png b/Adjust/example-app-webbridge/src/main/res/mipmap-hdpi/ic_launcher_round.png similarity index 100% rename from Adjust/example-webbridge/src/main/res/mipmap-hdpi/ic_launcher_round.png rename to Adjust/example-app-webbridge/src/main/res/mipmap-hdpi/ic_launcher_round.png diff --git a/Adjust/example-webbridge/src/main/res/mipmap-mdpi/ic_launcher.png b/Adjust/example-app-webbridge/src/main/res/mipmap-mdpi/ic_launcher.png similarity index 100% rename from Adjust/example-webbridge/src/main/res/mipmap-mdpi/ic_launcher.png rename to Adjust/example-app-webbridge/src/main/res/mipmap-mdpi/ic_launcher.png diff --git a/Adjust/example-webbridge/src/main/res/mipmap-mdpi/ic_launcher_round.png b/Adjust/example-app-webbridge/src/main/res/mipmap-mdpi/ic_launcher_round.png similarity index 100% rename from Adjust/example-webbridge/src/main/res/mipmap-mdpi/ic_launcher_round.png rename to Adjust/example-app-webbridge/src/main/res/mipmap-mdpi/ic_launcher_round.png diff --git a/Adjust/example-webbridge/src/main/res/mipmap-xhdpi/ic_launcher.png b/Adjust/example-app-webbridge/src/main/res/mipmap-xhdpi/ic_launcher.png similarity index 100% rename from Adjust/example-webbridge/src/main/res/mipmap-xhdpi/ic_launcher.png rename to Adjust/example-app-webbridge/src/main/res/mipmap-xhdpi/ic_launcher.png diff --git a/Adjust/example-webbridge/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/Adjust/example-app-webbridge/src/main/res/mipmap-xhdpi/ic_launcher_round.png similarity index 100% rename from Adjust/example-webbridge/src/main/res/mipmap-xhdpi/ic_launcher_round.png rename to Adjust/example-app-webbridge/src/main/res/mipmap-xhdpi/ic_launcher_round.png diff --git a/Adjust/example-webbridge/src/main/res/mipmap-xxhdpi/ic_launcher.png b/Adjust/example-app-webbridge/src/main/res/mipmap-xxhdpi/ic_launcher.png similarity index 100% rename from Adjust/example-webbridge/src/main/res/mipmap-xxhdpi/ic_launcher.png rename to Adjust/example-app-webbridge/src/main/res/mipmap-xxhdpi/ic_launcher.png diff --git a/Adjust/example-webbridge/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/Adjust/example-app-webbridge/src/main/res/mipmap-xxhdpi/ic_launcher_round.png similarity index 100% rename from Adjust/example-webbridge/src/main/res/mipmap-xxhdpi/ic_launcher_round.png rename to Adjust/example-app-webbridge/src/main/res/mipmap-xxhdpi/ic_launcher_round.png diff --git a/Adjust/example-webbridge/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/Adjust/example-app-webbridge/src/main/res/mipmap-xxxhdpi/ic_launcher.png similarity index 100% rename from Adjust/example-webbridge/src/main/res/mipmap-xxxhdpi/ic_launcher.png rename to Adjust/example-app-webbridge/src/main/res/mipmap-xxxhdpi/ic_launcher.png diff --git a/Adjust/example-webbridge/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/Adjust/example-app-webbridge/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png similarity index 100% rename from Adjust/example-webbridge/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png rename to Adjust/example-app-webbridge/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png diff --git a/Adjust/example-webbridge/src/main/res/values/colors.xml b/Adjust/example-app-webbridge/src/main/res/values/colors.xml similarity index 100% rename from Adjust/example-webbridge/src/main/res/values/colors.xml rename to Adjust/example-app-webbridge/src/main/res/values/colors.xml diff --git a/Adjust/example-webbridge/src/main/res/values/strings.xml b/Adjust/example-app-webbridge/src/main/res/values/strings.xml similarity index 100% rename from Adjust/example-webbridge/src/main/res/values/strings.xml rename to Adjust/example-app-webbridge/src/main/res/values/strings.xml diff --git a/Adjust/example-webbridge/src/main/res/values/styles.xml b/Adjust/example-app-webbridge/src/main/res/values/styles.xml similarity index 100% rename from Adjust/example-webbridge/src/main/res/values/styles.xml rename to Adjust/example-app-webbridge/src/main/res/values/styles.xml diff --git a/Adjust/example-webbridge/src/test/java/com/example/examples/ExampleUnitTest.java b/Adjust/example-app-webbridge/src/test/java/com/example/examples/ExampleUnitTest.java similarity index 100% rename from Adjust/example-webbridge/src/test/java/com/example/examples/ExampleUnitTest.java rename to Adjust/example-app-webbridge/src/test/java/com/example/examples/ExampleUnitTest.java diff --git a/Adjust/gradle/wrapper/gradle-wrapper.properties b/Adjust/gradle/wrapper/gradle-wrapper.properties index 1d8104d0e..42b3ef71c 100644 --- a/Adjust/gradle/wrapper/gradle-wrapper.properties +++ b/Adjust/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Mon Feb 12 10:45:26 CET 2018 +#Wed Sep 26 14:50:43 CEST 2018 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.5-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-4.6-all.zip diff --git a/Adjust/pom.xml b/Adjust/pom.xml index 4251ba04e..07868fbf9 100644 --- a/Adjust/pom.xml +++ b/Adjust/pom.xml @@ -5,7 +5,7 @@ 4.0.0 adjust-android com.adjust.sdk - 4.15.1 + 4.16.0 jar Adjust Android SDK https://github.com/adjust/android_sdk diff --git a/Adjust/pom_bridge.xml b/Adjust/pom_bridge.xml deleted file mode 100644 index 05d618240..000000000 --- a/Adjust/pom_bridge.xml +++ /dev/null @@ -1,174 +0,0 @@ - - - 4.0.0 - adjust-android-bridge - com.adjust.sdk - 4.7.0 - jar - Adjust Android SDK - https://github.com/adjust/android_sdk - The Adjust SDK for Android - - - MIT License - http://www.opensource.org/licenses/mit-license.php - - - - - Pedro Silva - pedro@adjust.com - adjust GmbH - http://www.adjust.com - - - Ugljesa Erceg - ugljesa@adjust.com - adjust GmbH - http://www.adjust.com - - - - scm:git:git@github.com:adjust/android_sdk.git - scm:git:git@github.com:adjust/android_sdk.git - git@github.com:adjust/android_sdk.git - - - UTF-8 - 4.1.1.4 - 23 - - - - android - ${android.version} - com.google.android - provided - - - - - ossrh - https://oss.sonatype.org/content/repositories/snapshots - - - ossrh - https://oss.sonatype.org/service/local/staging/deploy/maven2/ - - - - adjust/src/main/java - - - org.apache.maven.plugins - maven-compiler-plugin - 3.5.1 - - 1.8 - 1.8 - - - - org.apache.maven.plugins - maven-source-plugin - 3.0.1 - - - attach-sources - - jar-no-fork - - - - - - org.apache.maven.plugins - maven-javadoc-plugin - 2.10.4 - - - attach-javadocs - - jar - - - - - - com.jayway.maven.plugins.android.generation2 - android-maven-plugin - 3.8.2 - true - - - ${android.version.platform} - - - - - maven-deploy-plugin - 2.8.2 - - - default-deploy - deploy - - deploy - - - - - - org.apache.maven.plugins - maven-gpg-plugin - 1.6 - - - sign-artifacts - verify - - sign - - - - - - org.sonatype.plugins - nexus-staging-maven-plugin - 1.6.2 - true - - ossrh - https://oss.sonatype.org/ - false - - - - org.codehaus.mojo - build-helper-maven-plugin - 1.10 - - - add-source - generate-sources - - add-source - - - - bridge/WebBridge - - - - - - - - - bridge/Assets - - - - diff --git a/Adjust/pom_criteo.xml b/Adjust/pom_criteo.xml index 39feefac8..247e7f6b4 100644 --- a/Adjust/pom_criteo.xml +++ b/Adjust/pom_criteo.xml @@ -5,7 +5,7 @@ 4.0.0 adjust-android-criteo com.adjust.sdk - 4.15.0 + 4.16.0 jar Adjust Android SDK https://github.com/adjust/android_sdk diff --git a/Adjust/pom_sociomantic.xml b/Adjust/pom_sociomantic.xml index 6a8f7daf7..e97a26416 100644 --- a/Adjust/pom_sociomantic.xml +++ b/Adjust/pom_sociomantic.xml @@ -5,7 +5,7 @@ 4.0.0 adjust-android-sociomantic com.adjust.sdk - 4.15.0 + 4.16.0 jar Adjust Android SDK https://github.com/adjust/android_sdk diff --git a/Adjust/pom_trademob.xml b/Adjust/pom_trademob.xml index 97e60d969..4ae556f42 100644 --- a/Adjust/pom_trademob.xml +++ b/Adjust/pom_trademob.xml @@ -5,7 +5,7 @@ 4.0.0 adjust-android-trademob com.adjust.sdk - 4.15.0 + 4.16.0 jar Adjust Android SDK https://github.com/adjust/android_sdk diff --git a/Adjust/adjust/adjust-proguard-rules.txt b/Adjust/sdk-core/adjust-proguard-rules.txt similarity index 100% rename from Adjust/adjust/adjust-proguard-rules.txt rename to Adjust/sdk-core/adjust-proguard-rules.txt diff --git a/Adjust/adjust/build.gradle b/Adjust/sdk-core/build.gradle similarity index 62% rename from Adjust/adjust/build.gradle rename to Adjust/sdk-core/build.gradle index b721d095a..ec430adb4 100644 --- a/Adjust/adjust/build.gradle +++ b/Adjust/sdk-core/build.gradle @@ -2,19 +2,14 @@ apply plugin: 'com.android.library' apply plugin: 'maven-publish' apply plugin: 'signing' -def getVersionName() { - return "4.15.1" -} - android { - compileSdkVersion 28 + compileSdkVersion rootProject.ext.coreCompileSdkVersion defaultConfig { - minSdkVersion 9 - targetSdkVersion 28 - versionCode 1 - versionName getVersionName() - consumerProguardFiles 'adjust-proguard-rules.txt' + minSdkVersion rootProject.ext.coreMinSdkVersion + targetSdkVersion rootProject.ext.coreTargetSdkVersion + versionName rootProject.ext.coreVersionName + versionCode rootProject.ext.defaultVersionCode } } @@ -23,16 +18,27 @@ dependencies { } task adjustCoreAndroidJar(type: Jar) { - dependsOn 'build' - - from('build/intermediates/classes/release/') + dependsOn 'compileReleaseJavaWithJavac' + from('build/intermediates/javac/release/compileReleaseJavaWithJavac/classes/') archiveName "${project.name}.jar" } +task adjustSdkNonNativeJarDebug(type: Jar) { + dependsOn 'compileDebugJavaWithJavac' + from('build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/') + archiveName "adjust-sdk-debug.jar" +} + +task adjustSdkNonNativeJarRelease(type: Jar) { + dependsOn 'compileReleaseJavaWithJavac' + from('build/intermediates/javac/release/compileReleaseJavaWithJavac/classes/') + archiveName "adjust-sdk-release.jar" +} + task androidJavadocs(type: Javadoc) { source = android.sourceSets.main.java.srcDirs classpath += project.files(android.getBootClasspath().join(File.pathSeparator)) - // JDK 1.8 is more strict then 1.7. Have JDK 1.8 behave like 1.7 for javadoc generation + // JDK 1.8 is more strict then 1.7. Have JDK 1.8 behave like 1.7 for javadoc generation. if (org.gradle.internal.jvm.Jvm.current().getJavaVersion() == JavaVersion.VERSION_1_8) { options.addStringOption('Xdoclint:none', '-quiet') } @@ -40,7 +46,6 @@ task androidJavadocs(type: Javadoc) { task adjustCoreAndroidJavadocsJar(type: Jar) { dependsOn 'androidJavadocs' - classifier = 'javadoc' from androidJavadocs.destinationDir } @@ -51,7 +56,7 @@ task adjustCoreAndroidSourcesJar(type: Jar) { } artifacts { - //archives adjustCoreAndroidJar + archives adjustCoreAndroidJar archives adjustCoreAndroidJavadocsJar archives adjustCoreAndroidSourcesJar } @@ -60,11 +65,11 @@ publishing { publications { mavenAndroidCore(MavenPublication) { customizePom(pom) - groupId 'com.adjust.sdk' + groupId rootProject.ext.adjustGroupId artifactId 'adjust-android' - version getVersionName() + version rootProject.ext.coreVersionName - // create the sign pom artifact + // Create the signed POM artifact. pom.withXml { def pomFile = file("${project.buildDir}/generated-pom.xml") writeTo(pomFile) @@ -75,16 +80,26 @@ publishing { } } - // create the signed artifacts + // Create the signed artifacts. project.tasks.signArchives.signatureFiles.each { + // Exclude "usual" archive artifact .aar. + def signFileName = it.toString() + if (signFileName.contains('aar')) { + return + } + // Create a Maven artifact for each asc signature. artifact(it) { - def matcher = it.file =~ /-(sources|javadoc)\.jar\.asc$/ - if (matcher.find()) { - classifier = matcher.group(1) + //println "archive name ${signFileName}" + if (signFileName.contains('-sources')) { + classifier = 'sources' + extension = 'jar.asc' + } else if (signFileName.contains('-javadoc')) { + classifier = 'javadoc' + extension = 'jar.asc' } else { classifier = null + extension = 'jar.asc' } - extension = 'jar.asc' } } @@ -97,9 +112,11 @@ publishing { repositories { maven { url "https://oss.sonatype.org/service/local/staging/deploy/maven2" - credentials { - username sonatypeUsername - password sonatypePassword + if (project.hasProperty("sonatypeUsername")) { + credentials { + username sonatypeUsername + password sonatypePassword + } } } } @@ -107,11 +124,9 @@ publishing { def customizePom(pom) { pom.withXml { - def root = asNode() - - // add all items necessary for maven central publication - root.children().last() + { - + // Add all items necessary for maven central publication. + asNode().children().last() + { + resolveStrategy = Closure.DELEGATE_FIRST description 'The Adjust SDK for Android' name 'Adjust Android SDK' url 'https://github.com/adjust/android_sdk' @@ -120,7 +135,6 @@ def customizePom(pom) { name 'adjust GmbH' url 'http://www.adjust.com' } - licenses { license { name 'MIT License' @@ -137,7 +151,6 @@ def customizePom(pom) { name 'Pedro Silva' email 'pedro@adjust.com' } - developer { name 'Ugljesa Erceg' email 'ugljesa@adjust.com' @@ -161,4 +174,4 @@ model { signing { sign configurations.archives -} \ No newline at end of file +} diff --git a/Adjust/adjust/src/main/AndroidManifest.xml b/Adjust/sdk-core/src/main/AndroidManifest.xml similarity index 100% rename from Adjust/adjust/src/main/AndroidManifest.xml rename to Adjust/sdk-core/src/main/AndroidManifest.xml diff --git a/Adjust/adjust/src/main/java/com/adjust/sdk/ActivityHandler.java b/Adjust/sdk-core/src/main/java/com/adjust/sdk/ActivityHandler.java similarity index 96% rename from Adjust/adjust/src/main/java/com/adjust/sdk/ActivityHandler.java rename to Adjust/sdk-core/src/main/java/com/adjust/sdk/ActivityHandler.java index 62e1da670..96d3e0c49 100644 --- a/Adjust/adjust/src/main/java/com/adjust/sdk/ActivityHandler.java +++ b/Adjust/sdk-core/src/main/java/com/adjust/sdk/ActivityHandler.java @@ -17,6 +17,11 @@ import android.net.Uri; import android.os.Handler; +import com.adjust.sdk.scheduler.SingleThreadCachedScheduler; +import com.adjust.sdk.scheduler.ThreadExecutor; +import com.adjust.sdk.scheduler.TimerCycle; +import com.adjust.sdk.scheduler.TimerOnce; + import java.io.InputStream; import java.util.ArrayList; import java.util.LinkedHashMap; @@ -45,7 +50,7 @@ public class ActivityHandler implements IActivityHandler { private static final String SESSION_PARTNER_PARAMETERS_NAME = "Session Partner parameters"; private static final String SESSION_PARAMETERS_NAME = "Session parameters"; - private CustomScheduledExecutor scheduledExecutor; + private ThreadExecutor executor; private IPackageHandler packageHandler; private ActivityState activityState; private ILogger logger; @@ -75,10 +80,8 @@ public void teardown() { if (delayStartTimer != null) { delayStartTimer.teardown(); } - if (scheduledExecutor != null) { - try { - scheduledExecutor.shutdownNow(); - } catch(SecurityException se) {} + if (executor != null) { + executor.teardown(); } if (packageHandler != null) { packageHandler.teardown(); @@ -105,7 +108,7 @@ public void teardown() { packageHandler = null; logger = null; foregroundTimer = null; - scheduledExecutor = null; + executor = null; backgroundTimer = null; delayStartTimer = null; internalState = null; @@ -201,7 +204,7 @@ private ActivityHandler(AdjustConfig adjustConfig) { logger.lockLogLevel(); - scheduledExecutor = new CustomScheduledExecutor("ActivityHandler", false); + executor = new SingleThreadCachedScheduler("ActivityHandler"); internalState = new InternalState(); // enabled by default @@ -219,7 +222,7 @@ private ActivityHandler(AdjustConfig adjustConfig) { // does not have first start by default internalState.firstSdkStart = false; - scheduledExecutor.submit(new Runnable() { + executor.submit(new Runnable() { @Override public void run() { initI(); @@ -290,7 +293,7 @@ public static ActivityHandler getInstance(AdjustConfig adjustConfig) { public void onResume() { internalState.background = false; - scheduledExecutor.submit(new Runnable() { + executor.submit(new Runnable() { @Override public void run() { delayStartI(); @@ -310,7 +313,7 @@ public void run() { public void onPause() { internalState.background = true; - scheduledExecutor.submit(new Runnable() { + executor.submit(new Runnable() { @Override public void run() { stopForegroundTimerI(); @@ -326,7 +329,7 @@ public void run() { @Override public void trackEvent(final AdjustEvent event) { - scheduledExecutor.submit(new Runnable() { + executor.submit(new Runnable() { @Override public void run() { if (internalState.hasFirstSdkStartNotOcurred()) { @@ -362,7 +365,7 @@ public void finishedTrackingActivity(ResponseData responseData) { @Override public void setEnabled(final boolean enabled) { - scheduledExecutor.submit(new Runnable() { + executor.submit(new Runnable() { @Override public void run() { setEnabledI(enabled); @@ -372,7 +375,7 @@ public void run() { @Override public void setOfflineMode(final boolean offline) { - scheduledExecutor.submit(new Runnable() { + executor.submit(new Runnable() { @Override public void run() { setOfflineModeI(offline); @@ -395,7 +398,7 @@ private boolean isEnabledI() { @Override public void readOpenUrl(final Uri url, final long clickTime) { - scheduledExecutor.submit(new Runnable() { + executor.submit(new Runnable() { @Override public void run() { readOpenUrlI(url, clickTime); @@ -434,7 +437,7 @@ public boolean updateAttributionI(AdjustAttribution attribution) { @Override public void setAskingAttribution(final boolean askingAttribution) { - scheduledExecutor.submit(new Runnable() { + executor.submit(new Runnable() { @Override public void run() { setAskingAttributionI(askingAttribution); @@ -444,7 +447,7 @@ public void run() { @Override public void sendReftagReferrer() { - scheduledExecutor.submit(new Runnable() { + executor.submit(new Runnable() { @Override public void run() { sendReftagReferrerI(); @@ -453,18 +456,18 @@ public void run() { } @Override - public void sendInstallReferrer(final long clickTime, final long installBegin, final String installReferrer) { - scheduledExecutor.submit(new Runnable() { + public void sendInstallReferrer(final String installReferrer, final long referrerClickTimestampSeconds, final long installBeginTimestampSeconds) { + executor.submit(new Runnable() { @Override public void run() { - sendInstallReferrerI(clickTime, installBegin, installReferrer); + sendInstallReferrerI(installReferrer, referrerClickTimestampSeconds, installBeginTimestampSeconds); } }); } @Override public void launchEventResponseTasks(final EventResponseData eventResponseData) { - scheduledExecutor.submit(new Runnable() { + executor.submit(new Runnable() { @Override public void run() { launchEventResponseTasksI(eventResponseData); @@ -474,7 +477,7 @@ public void run() { @Override public void launchSdkClickResponseTasks(final SdkClickResponseData sdkClickResponseData) { - scheduledExecutor.submit(new Runnable() { + executor.submit(new Runnable() { @Override public void run() { launchSdkClickResponseTasksI(sdkClickResponseData); @@ -484,7 +487,7 @@ public void run() { @Override public void launchSessionResponseTasks(final SessionResponseData sessionResponseData) { - scheduledExecutor.submit(new Runnable() { + executor.submit(new Runnable() { @Override public void run() { launchSessionResponseTasksI(sessionResponseData); @@ -494,7 +497,7 @@ public void run() { @Override public void launchAttributionResponseTasks(final AttributionResponseData attributionResponseData) { - scheduledExecutor.submit(new Runnable() { + executor.submit(new Runnable() { @Override public void run() { launchAttributionResponseTasksI(attributionResponseData); @@ -504,7 +507,7 @@ public void run() { @Override public void sendFirstPackages () { - scheduledExecutor.submit(new Runnable() { + executor.submit(new Runnable() { @Override public void run() { sendFirstPackagesI(); @@ -514,7 +517,7 @@ public void run() { @Override public void addSessionCallbackParameter(final String key, final String value) { - scheduledExecutor.submit(new Runnable() { + executor.submit(new Runnable() { @Override public void run() { addSessionCallbackParameterI(key, value); @@ -524,7 +527,7 @@ public void run() { @Override public void addSessionPartnerParameter(final String key, final String value) { - scheduledExecutor.submit(new Runnable() { + executor.submit(new Runnable() { @Override public void run() { addSessionPartnerParameterI(key, value); @@ -534,7 +537,7 @@ public void run() { @Override public void removeSessionCallbackParameter(final String key) { - scheduledExecutor.submit(new Runnable() { + executor.submit(new Runnable() { @Override public void run() { removeSessionCallbackParameterI(key); @@ -544,7 +547,7 @@ public void run() { @Override public void removeSessionPartnerParameter(final String key) { - scheduledExecutor.submit(new Runnable() { + executor.submit(new Runnable() { @Override public void run() { removeSessionPartnerParameterI(key); @@ -554,7 +557,7 @@ public void run() { @Override public void resetSessionCallbackParameters() { - scheduledExecutor.submit(new Runnable() { + executor.submit(new Runnable() { @Override public void run() { resetSessionCallbackParametersI(); @@ -564,7 +567,7 @@ public void run() { @Override public void resetSessionPartnerParameters() { - scheduledExecutor.submit(new Runnable() { + executor.submit(new Runnable() { @Override public void run() { resetSessionPartnerParametersI(); @@ -574,7 +577,7 @@ public void run() { @Override public void setPushToken(final String token, final boolean preSaved) { - scheduledExecutor.submit(new Runnable() { + executor.submit(new Runnable() { @Override public void run() { if (!preSaved) { @@ -595,7 +598,7 @@ public void run() { @Override public void gdprForgetMe() { - scheduledExecutor.submit(new Runnable() { + executor.submit(new Runnable() { @Override public void run() { gdprForgetMeI(); @@ -605,7 +608,7 @@ public void run() { @Override public void gotOptOutResponse() { - scheduledExecutor.submit(new Runnable() { + executor.submit(new Runnable() { @Override public void run() { gotOptOutResponseI(); @@ -619,7 +622,7 @@ public Context getContext() { } public void foregroundTimerFired() { - scheduledExecutor.submit(new Runnable() { + executor.submit(new Runnable() { @Override public void run() { foregroundTimerFiredI(); @@ -628,7 +631,7 @@ public void run() { } public void backgroundTimerFired() { - scheduledExecutor.submit(new Runnable() { + executor.submit(new Runnable() { @Override public void run() { backgroundTimerFiredI(); @@ -659,16 +662,6 @@ public String getGdprPath() { return this.gdprPath; } - public ActivityPackage getAttributionPackageI() { - long now = System.currentTimeMillis(); - PackageBuilder attributionBuilder = new PackageBuilder(adjustConfig, - deviceInfo, - activityState, - sessionParameters, - now); - return attributionBuilder.buildAttributionPackage(); - } - public InternalState getInternalState() { return internalState; } @@ -717,6 +710,7 @@ public void run(ActivityHandler activityHandler) { logger.info("Event buffering is enabled"); } + deviceInfo.reloadPlayIds(adjustConfig.context); if (deviceInfo.playAdId == null) { logger.warn("Unable to get Google Play Services Advertising ID at start time"); if (deviceInfo.macSha1 == null && @@ -803,11 +797,7 @@ public void run() { packageHandler = AdjustFactory.getPackageHandler(this, adjustConfig.context, toSendI(false)); - ActivityPackage attributionPackage = getAttributionPackageI(); - - attributionHandler = AdjustFactory.getAttributionHandler(this, - attributionPackage, - toSendI(false)); + attributionHandler = AdjustFactory.getAttributionHandler(this, toSendI(false)); sdkClickHandler = AdjustFactory.getSdkClickHandler(this, toSendI(true)); @@ -815,7 +805,12 @@ public void run() { updatePackagesI(); } - installReferrer = new InstallReferrer(adjustConfig.context, this); + installReferrer = new InstallReferrer(adjustConfig.context, new InstallReferrerReadListener() { + @Override + public void onInstallReferrerRead(String installReferrer, long referrerClickTimestampSeconds, long installBeginTimestampSeconds) { + sendInstallReferrer(installReferrer, referrerClickTimestampSeconds, installBeginTimestampSeconds); + } + }); preLaunchActionsI(adjustConfig.preLaunchActionsArray); sendReftagReferrerI(); } @@ -1437,7 +1432,7 @@ private void sendReftagReferrerI() { sdkClickHandler.sendReftagReferrers(); } - private void sendInstallReferrerI(final long clickTime, final long installBegin, final String installReferrer) { + private void sendInstallReferrerI(String installReferrer, long referrerClickTimestampSeconds, long installBeginTimestampSeconds) { if (!isEnabledI()) { return; } @@ -1446,8 +1441,8 @@ private void sendInstallReferrerI(final long clickTime, final long installBegin, return; } - if (clickTime == activityState.clickTime - && installBegin == activityState.installBegin + if (referrerClickTimestampSeconds == activityState.clickTime + && installBeginTimestampSeconds == activityState.installBegin && installReferrer.equals(activityState.installReferrer)) { // Same click already sent before, nothing to be done. return; @@ -1456,8 +1451,8 @@ private void sendInstallReferrerI(final long clickTime, final long installBegin, // Create sdk click ActivityPackage sdkClickPackage = PackageFactory.buildInstallReferrerSdkClickPackage( installReferrer, - clickTime, - installBegin, + referrerClickTimestampSeconds, + installBeginTimestampSeconds, activityState, adjustConfig, deviceInfo, @@ -1471,6 +1466,11 @@ private void readOpenUrlI(Uri url, long clickTime) { return; } + if (Util.isUrlFilteredOut(url)) { + logger.debug("Deep link (" + url.toString() + ") processing skipped"); + return; + } + ActivityPackage sdkClickPackage = PackageFactory.buildDeeplinkSdkClickPackage( url, clickTime, diff --git a/Adjust/adjust/src/main/java/com/adjust/sdk/ActivityKind.java b/Adjust/sdk-core/src/main/java/com/adjust/sdk/ActivityKind.java similarity index 100% rename from Adjust/adjust/src/main/java/com/adjust/sdk/ActivityKind.java rename to Adjust/sdk-core/src/main/java/com/adjust/sdk/ActivityKind.java diff --git a/Adjust/adjust/src/main/java/com/adjust/sdk/ActivityPackage.java b/Adjust/sdk-core/src/main/java/com/adjust/sdk/ActivityPackage.java similarity index 100% rename from Adjust/adjust/src/main/java/com/adjust/sdk/ActivityPackage.java rename to Adjust/sdk-core/src/main/java/com/adjust/sdk/ActivityPackage.java diff --git a/Adjust/adjust/src/main/java/com/adjust/sdk/ActivityState.java b/Adjust/sdk-core/src/main/java/com/adjust/sdk/ActivityState.java similarity index 100% rename from Adjust/adjust/src/main/java/com/adjust/sdk/ActivityState.java rename to Adjust/sdk-core/src/main/java/com/adjust/sdk/ActivityState.java diff --git a/Adjust/adjust/src/main/java/com/adjust/sdk/Adjust.java b/Adjust/sdk-core/src/main/java/com/adjust/sdk/Adjust.java similarity index 99% rename from Adjust/adjust/src/main/java/com/adjust/sdk/Adjust.java rename to Adjust/sdk-core/src/main/java/com/adjust/sdk/Adjust.java index 4211be309..db2dcf231 100644 --- a/Adjust/adjust/src/main/java/com/adjust/sdk/Adjust.java +++ b/Adjust/sdk-core/src/main/java/com/adjust/sdk/Adjust.java @@ -30,7 +30,7 @@ private Adjust() { */ public static synchronized AdjustInstance getDefaultInstance() { @SuppressWarnings("unused") - String VERSION = "!SDK-VERSION-STRING!:com.adjust.sdk:adjust-android:4.15.1"; + String VERSION = "!SDK-VERSION-STRING!:com.adjust.sdk:adjust-android:4.16.0"; if (defaultInstance == null) { defaultInstance = new AdjustInstance(); diff --git a/Adjust/adjust/src/main/java/com/adjust/sdk/AdjustAttribution.java b/Adjust/sdk-core/src/main/java/com/adjust/sdk/AdjustAttribution.java similarity index 100% rename from Adjust/adjust/src/main/java/com/adjust/sdk/AdjustAttribution.java rename to Adjust/sdk-core/src/main/java/com/adjust/sdk/AdjustAttribution.java diff --git a/Adjust/adjust/src/main/java/com/adjust/sdk/AdjustConfig.java b/Adjust/sdk-core/src/main/java/com/adjust/sdk/AdjustConfig.java similarity index 100% rename from Adjust/adjust/src/main/java/com/adjust/sdk/AdjustConfig.java rename to Adjust/sdk-core/src/main/java/com/adjust/sdk/AdjustConfig.java diff --git a/Adjust/adjust/src/main/java/com/adjust/sdk/AdjustEvent.java b/Adjust/sdk-core/src/main/java/com/adjust/sdk/AdjustEvent.java similarity index 100% rename from Adjust/adjust/src/main/java/com/adjust/sdk/AdjustEvent.java rename to Adjust/sdk-core/src/main/java/com/adjust/sdk/AdjustEvent.java diff --git a/Adjust/adjust/src/main/java/com/adjust/sdk/AdjustEventFailure.java b/Adjust/sdk-core/src/main/java/com/adjust/sdk/AdjustEventFailure.java similarity index 100% rename from Adjust/adjust/src/main/java/com/adjust/sdk/AdjustEventFailure.java rename to Adjust/sdk-core/src/main/java/com/adjust/sdk/AdjustEventFailure.java diff --git a/Adjust/adjust/src/main/java/com/adjust/sdk/AdjustEventSuccess.java b/Adjust/sdk-core/src/main/java/com/adjust/sdk/AdjustEventSuccess.java similarity index 100% rename from Adjust/adjust/src/main/java/com/adjust/sdk/AdjustEventSuccess.java rename to Adjust/sdk-core/src/main/java/com/adjust/sdk/AdjustEventSuccess.java diff --git a/Adjust/adjust/src/main/java/com/adjust/sdk/AdjustFactory.java b/Adjust/sdk-core/src/main/java/com/adjust/sdk/AdjustFactory.java similarity index 97% rename from Adjust/adjust/src/main/java/com/adjust/sdk/AdjustFactory.java rename to Adjust/sdk-core/src/main/java/com/adjust/sdk/AdjustFactory.java index f8232534e..6dbd75ec5 100644 --- a/Adjust/adjust/src/main/java/com/adjust/sdk/AdjustFactory.java +++ b/Adjust/sdk-core/src/main/java/com/adjust/sdk/AdjustFactory.java @@ -125,12 +125,11 @@ public static IActivityHandler getActivityHandler(AdjustConfig config) { } public static IAttributionHandler getAttributionHandler(IActivityHandler activityHandler, - ActivityPackage attributionPackage, boolean startsSending) { if (attributionHandler == null) { - return new AttributionHandler(activityHandler, attributionPackage, startsSending); + return new AttributionHandler(activityHandler, startsSending); } - attributionHandler.init(activityHandler, attributionPackage, startsSending); + attributionHandler.init(activityHandler, startsSending); return attributionHandler; } diff --git a/Adjust/adjust/src/main/java/com/adjust/sdk/AdjustInstance.java b/Adjust/sdk-core/src/main/java/com/adjust/sdk/AdjustInstance.java similarity index 100% rename from Adjust/adjust/src/main/java/com/adjust/sdk/AdjustInstance.java rename to Adjust/sdk-core/src/main/java/com/adjust/sdk/AdjustInstance.java diff --git a/Adjust/adjust/src/main/java/com/adjust/sdk/AdjustReferrerReceiver.java b/Adjust/sdk-core/src/main/java/com/adjust/sdk/AdjustReferrerReceiver.java similarity index 100% rename from Adjust/adjust/src/main/java/com/adjust/sdk/AdjustReferrerReceiver.java rename to Adjust/sdk-core/src/main/java/com/adjust/sdk/AdjustReferrerReceiver.java diff --git a/Adjust/adjust/src/main/java/com/adjust/sdk/AdjustSessionFailure.java b/Adjust/sdk-core/src/main/java/com/adjust/sdk/AdjustSessionFailure.java similarity index 100% rename from Adjust/adjust/src/main/java/com/adjust/sdk/AdjustSessionFailure.java rename to Adjust/sdk-core/src/main/java/com/adjust/sdk/AdjustSessionFailure.java diff --git a/Adjust/adjust/src/main/java/com/adjust/sdk/AdjustSessionSuccess.java b/Adjust/sdk-core/src/main/java/com/adjust/sdk/AdjustSessionSuccess.java similarity index 100% rename from Adjust/adjust/src/main/java/com/adjust/sdk/AdjustSessionSuccess.java rename to Adjust/sdk-core/src/main/java/com/adjust/sdk/AdjustSessionSuccess.java diff --git a/Adjust/adjust/src/main/java/com/adjust/sdk/AdjustTestOptions.java b/Adjust/sdk-core/src/main/java/com/adjust/sdk/AdjustTestOptions.java similarity index 100% rename from Adjust/adjust/src/main/java/com/adjust/sdk/AdjustTestOptions.java rename to Adjust/sdk-core/src/main/java/com/adjust/sdk/AdjustTestOptions.java diff --git a/Adjust/adjust/src/main/java/com/adjust/sdk/AndroidIdUtil.java b/Adjust/sdk-core/src/main/java/com/adjust/sdk/AndroidIdUtil.java similarity index 100% rename from Adjust/adjust/src/main/java/com/adjust/sdk/AndroidIdUtil.java rename to Adjust/sdk-core/src/main/java/com/adjust/sdk/AndroidIdUtil.java diff --git a/Adjust/adjust/src/main/java/com/adjust/sdk/AttributionHandler.java b/Adjust/sdk-core/src/main/java/com/adjust/sdk/AttributionHandler.java similarity index 72% rename from Adjust/adjust/src/main/java/com/adjust/sdk/AttributionHandler.java rename to Adjust/sdk-core/src/main/java/com/adjust/sdk/AttributionHandler.java index 9fba7e354..571cbeea8 100644 --- a/Adjust/adjust/src/main/java/com/adjust/sdk/AttributionHandler.java +++ b/Adjust/sdk-core/src/main/java/com/adjust/sdk/AttributionHandler.java @@ -1,87 +1,89 @@ +// +// AttributionHandler.java +// Adjust SDK +// +// Created by Pedro Silva (@nonelse) on 7th November 2014. +// Copyright (c) 2014-2018 Adjust GmbH. All rights reserved. +// + package com.adjust.sdk; import android.net.Uri; +import com.adjust.sdk.scheduler.SingleThreadCachedScheduler; +import com.adjust.sdk.scheduler.ThreadScheduler; +import com.adjust.sdk.scheduler.TimerOnce; + import org.json.JSONObject; import java.lang.ref.WeakReference; -import java.net.URL; -import java.util.Map; -/** - * Created by pfms on 07/11/14. - */ public class AttributionHandler implements IAttributionHandler { - private CustomScheduledExecutor scheduledExecutor; - private WeakReference activityHandlerWeakRef; - private ILogger logger; - private ActivityPackage attributionPackage; - private TimerOnce timer; private static final String ATTRIBUTION_TIMER_NAME = "Attribution timer"; - private boolean paused; private String basePath; + private String clientSdk; + private String lastInitiatedBy; + + private ILogger logger; + private TimerOnce timer; + private ThreadScheduler scheduler; + private WeakReference activityHandlerWeakRef; @Override public void teardown() { logger.verbose("AttributionHandler teardown"); + if (timer != null) { timer.teardown(); } - if (scheduledExecutor != null) { - try { - scheduledExecutor.shutdownNow(); - } catch(SecurityException se) {} + if (scheduler != null) { + scheduler.teardown(); } if (activityHandlerWeakRef != null) { activityHandlerWeakRef.clear(); } - scheduledExecutor = null; - activityHandlerWeakRef = null; - logger = null; - attributionPackage = null; + timer = null; + logger = null; + scheduler = null; + activityHandlerWeakRef = null; } - public AttributionHandler(IActivityHandler activityHandler, - ActivityPackage attributionPackage, - boolean startsSending) { - scheduledExecutor = new CustomScheduledExecutor("AttributionHandler", false); + public AttributionHandler(IActivityHandler activityHandler, boolean startsSending) { logger = AdjustFactory.getLogger(); - + scheduler = new SingleThreadCachedScheduler("AttributionHandler"); timer = new TimerOnce(new Runnable() { @Override public void run() { sendAttributionRequest(); } }, ATTRIBUTION_TIMER_NAME); - basePath = activityHandler.getBasePath(); - init(activityHandler, attributionPackage, startsSending); + clientSdk = activityHandler.getDeviceInfo().clientSdk; + init(activityHandler, startsSending); } @Override - public void init(IActivityHandler activityHandler, - ActivityPackage attributionPackage, - boolean startsSending) { + public void init(IActivityHandler activityHandler, boolean startsSending) { this.activityHandlerWeakRef = new WeakReference(activityHandler); - this.attributionPackage = attributionPackage; this.paused = !startsSending; } @Override public void getAttribution() { - scheduledExecutor.submit(new Runnable() { + scheduler.submit(new Runnable() { @Override public void run() { - getAttributionI(0, true); + lastInitiatedBy = "sdk"; + getAttributionI(0); } }); } @Override public void checkSessionResponse(final SessionResponseData sessionResponseData) { - scheduledExecutor.submit(new Runnable() { + scheduler.submit(new Runnable() { @Override public void run() { IActivityHandler activityHandler = activityHandlerWeakRef.get(); @@ -95,28 +97,26 @@ public void run() { @Override public void checkSdkClickResponse(final SdkClickResponseData sdkClickResponseData) { - scheduledExecutor.submit(new Runnable() { + scheduler.submit(new Runnable() { @Override public void run() { IActivityHandler activityHandler = activityHandlerWeakRef.get(); if (activityHandler == null) { return; } - checkSdkClickResponseI(activityHandler, sdkClickResponseData); } }); } public void checkAttributionResponse(final AttributionResponseData attributionResponseData) { - scheduledExecutor.submit(new Runnable() { + scheduler.submit(new Runnable() { @Override public void run() { IActivityHandler activityHandler = activityHandlerWeakRef.get(); if (activityHandler == null) { return; } - checkAttributionResponseI(activityHandler, attributionResponseData); } }); @@ -132,8 +132,8 @@ public void resumeSending() { paused = false; } - public void sendAttributionRequest() { - scheduledExecutor.submit(new Runnable() { + private void sendAttributionRequest() { + scheduler.submit(new Runnable() { @Override public void run() { sendAttributionRequestI(); @@ -141,8 +141,8 @@ public void run() { }); } - private void getAttributionI(long delayInMilliseconds, boolean isInitiatedBySdk) { - // don't reset if new time is shorter than last one + private void getAttributionI(long delayInMilliseconds) { + // Don't reset if new time is shorter than last one. if (timer.getFireIn() > delayInMilliseconds) { return; } @@ -150,14 +150,10 @@ private void getAttributionI(long delayInMilliseconds, boolean isInitiatedBySdk) if (delayInMilliseconds != 0) { double waitTimeSeconds = delayInMilliseconds / 1000.0; String secondsString = Util.SecondsDisplayFormat.format(waitTimeSeconds); - logger.debug("Waiting to query attribution in %s seconds", secondsString); } - String initiatedBy = isInitiatedBySdk ? "sdk" : "backend"; - attributionPackage.getParameters().put("initiated_by", initiatedBy); - - // set the new time the timer will fire in + // Set the new time the timer will fire in. timer.startIn(delayInMilliseconds); } @@ -167,39 +163,34 @@ private void checkAttributionI(IActivityHandler activityHandler, ResponseData re } long timerMilliseconds = responseData.jsonResponse.optLong("ask_in", -1); - if (timerMilliseconds >= 0) { activityHandler.setAskingAttribution(true); - - getAttributionI(timerMilliseconds, false); - + lastInitiatedBy = "backend"; + getAttributionI(timerMilliseconds); return; } - activityHandler.setAskingAttribution(false); + activityHandler.setAskingAttribution(false); JSONObject attributionJson = responseData.jsonResponse.optJSONObject("attribution"); - responseData.attribution = AdjustAttribution.fromJson(attributionJson, + responseData.attribution = AdjustAttribution.fromJson( + attributionJson, responseData.adid, - Util.getSdkPrefixPlatform(attributionPackage.getClientSdk())); + Util.getSdkPrefixPlatform(clientSdk)); } private void checkSessionResponseI(IActivityHandler activityHandler, SessionResponseData sessionResponseData) { checkAttributionI(activityHandler, sessionResponseData); - activityHandler.launchSessionResponseTasks(sessionResponseData); } private void checkSdkClickResponseI(IActivityHandler activityHandler, SdkClickResponseData sdkClickResponseData) { checkAttributionI(activityHandler, sdkClickResponseData); - activityHandler.launchSdkClickResponseTasks(sdkClickResponseData); } private void checkAttributionResponseI(IActivityHandler activityHandler, AttributionResponseData attributionResponseData) { checkAttributionI(activityHandler, attributionResponseData); - checkDeeplinkI(attributionResponseData); - activityHandler.launchAttributionResponseTasks(attributionResponseData); } @@ -207,17 +198,14 @@ private void checkDeeplinkI(AttributionResponseData attributionResponseData) { if (attributionResponseData.jsonResponse == null) { return; } - JSONObject attributionJson = attributionResponseData.jsonResponse.optJSONObject("attribution"); if (attributionJson == null) { return; } - String deeplinkString = attributionJson.optString("deeplink", null); if (deeplinkString == null) { return; } - attributionResponseData.deeplink = Uri.parse(deeplinkString); } @@ -230,24 +218,36 @@ private void sendAttributionRequestI() { return; } + // Create attribution package before sending attribution request. + ActivityPackage attributionPackage = buildAndGetAttributionPackage(); logger.verbose("%s", attributionPackage.getExtendedString()); try { ResponseData responseData = UtilNetworking.createGETHttpsURLConnection(attributionPackage, basePath); - if (!(responseData instanceof AttributionResponseData)) { return; } - if (responseData.trackingState == TrackingState.OPTED_OUT) { activityHandlerWeakRef.get().gotOptOutResponse(); return; } - checkAttributionResponse((AttributionResponseData)responseData); } catch (Exception e) { logger.error("Failed to get attribution (%s)", e.getMessage()); - return; } } + + private ActivityPackage buildAndGetAttributionPackage() { + long now = System.currentTimeMillis(); + IActivityHandler activityHandler = activityHandlerWeakRef.get(); + PackageBuilder packageBuilder = new PackageBuilder( + activityHandler.getAdjustConfig(), + activityHandler.getDeviceInfo(), + activityHandler.getActivityState(), + activityHandler.getSessionParameters(), + now); + ActivityPackage activityPackage = packageBuilder.buildAttributionPackage(lastInitiatedBy); + lastInitiatedBy = null; + return activityPackage; + } } \ No newline at end of file diff --git a/Adjust/adjust/src/main/java/com/adjust/sdk/AttributionResponseData.java b/Adjust/sdk-core/src/main/java/com/adjust/sdk/AttributionResponseData.java similarity index 100% rename from Adjust/adjust/src/main/java/com/adjust/sdk/AttributionResponseData.java rename to Adjust/sdk-core/src/main/java/com/adjust/sdk/AttributionResponseData.java diff --git a/Adjust/adjust/src/main/java/com/adjust/sdk/BackoffStrategy.java b/Adjust/sdk-core/src/main/java/com/adjust/sdk/BackoffStrategy.java similarity index 100% rename from Adjust/adjust/src/main/java/com/adjust/sdk/BackoffStrategy.java rename to Adjust/sdk-core/src/main/java/com/adjust/sdk/BackoffStrategy.java diff --git a/Adjust/adjust/src/main/java/com/adjust/sdk/Constants.java b/Adjust/sdk-core/src/main/java/com/adjust/sdk/Constants.java similarity index 93% rename from Adjust/adjust/src/main/java/com/adjust/sdk/Constants.java rename to Adjust/sdk-core/src/main/java/com/adjust/sdk/Constants.java index 0efc49863..3269ccc91 100644 --- a/Adjust/adjust/src/main/java/com/adjust/sdk/Constants.java +++ b/Adjust/sdk-core/src/main/java/com/adjust/sdk/Constants.java @@ -30,7 +30,7 @@ public interface Constants { String GDPR_URL = "https://gdpr.adjust.com"; String SCHEME = "https"; String AUTHORITY = "app.adjust.com"; - String CLIENT_SDK = "android4.15.1"; + String CLIENT_SDK = "android4.16.0"; String LOGTAG = "Adjust"; String REFTAG = "reftag"; String INSTALL_REFERRER = "install_referrer"; @@ -63,4 +63,6 @@ public interface Constants { String PARTNER_PARAMETERS = "partner_params"; int MAX_INSTALL_REFERRER_RETRIES = 2; + + String FB_AUTH_REGEX = "^(fb|vk)[0-9]{5,}[^:]*://authorize.*access_token=.*"; } diff --git a/Adjust/adjust/src/main/java/com/adjust/sdk/DeviceInfo.java b/Adjust/sdk-core/src/main/java/com/adjust/sdk/DeviceInfo.java similarity index 93% rename from Adjust/adjust/src/main/java/com/adjust/sdk/DeviceInfo.java rename to Adjust/sdk-core/src/main/java/com/adjust/sdk/DeviceInfo.java index 22ac95d4d..3cb9656a1 100644 --- a/Adjust/adjust/src/main/java/com/adjust/sdk/DeviceInfo.java +++ b/Adjust/sdk-core/src/main/java/com/adjust/sdk/DeviceInfo.java @@ -13,7 +13,6 @@ import java.util.Date; import java.util.Locale; -import java.util.Map; import static com.adjust.sdk.Constants.HIGH; import static com.adjust.sdk.Constants.LARGE; @@ -29,8 +28,9 @@ */ class DeviceInfo { String playAdId; + String playAdIdSource; Boolean isTrackingEnabled; - private boolean nonGoogleIdsRead = false; + private boolean nonGoogleIdsReadOnce = false; String macSha1; String macShortMd5; String androidId; @@ -65,8 +65,6 @@ class DeviceInfo { int screenLayout = configuration.screenLayout; ContentResolver contentResolver = context.getContentResolver(); - reloadDeviceIds(context); - packageName = getPackageName(context); appVersion = getAppVersion(context); deviceType = getDeviceType(screenLayout); @@ -91,17 +89,20 @@ class DeviceInfo { appUpdateTime = getAppUpdateTime(context); } - void reloadDeviceIds(Context context) { + void reloadPlayIds(Context context) { + playAdIdSource = null; for (int i = 0; i < 3; i += 1) { try { GooglePlayServicesClient.GooglePlayServicesInfo gpsInfo = GooglePlayServicesClient.getGooglePlayServicesInfo(context); playAdId = gpsInfo.getGpsAdid(); if (playAdId != null) { + playAdIdSource = "service"; break; } } catch (Exception e) {} playAdId = Util.getPlayAdId(context); if (playAdId != null) { + playAdIdSource = "library"; break; } } @@ -118,17 +119,20 @@ void reloadDeviceIds(Context context) { break; } } + } - if (playAdId == null && !nonGoogleIdsRead) { - if (!Util.checkPermission(context, android.Manifest.permission.ACCESS_WIFI_STATE)) { - AdjustFactory.getLogger().warn("Missing permission: ACCESS_WIFI_STATE"); - } - String macAddress = Util.getMacAddress(context); - macSha1 = getMacSha1(macAddress); - macShortMd5 = getMacShortMd5(macAddress); - androidId = Util.getAndroidId(context); - nonGoogleIdsRead = true; + void reloadNonPlayIds(Context context) { + if (nonGoogleIdsReadOnce) { + return; + } + if (!Util.checkPermission(context, android.Manifest.permission.ACCESS_WIFI_STATE)) { + AdjustFactory.getLogger().warn("Missing permission: ACCESS_WIFI_STATE"); } + String macAddress = Util.getMacAddress(context); + macSha1 = getMacSha1(macAddress); + macShortMd5 = getMacShortMd5(macAddress); + androidId = Util.getAndroidId(context); + nonGoogleIdsReadOnce = true; } private String getMacAddress(Context context, boolean isGooglePlayServicesAvailable) { diff --git a/Adjust/adjust/src/main/java/com/adjust/sdk/EventResponseData.java b/Adjust/sdk-core/src/main/java/com/adjust/sdk/EventResponseData.java similarity index 100% rename from Adjust/adjust/src/main/java/com/adjust/sdk/EventResponseData.java rename to Adjust/sdk-core/src/main/java/com/adjust/sdk/EventResponseData.java diff --git a/Adjust/adjust/src/main/java/com/adjust/sdk/GooglePlayServicesClient.java b/Adjust/sdk-core/src/main/java/com/adjust/sdk/GooglePlayServicesClient.java similarity index 100% rename from Adjust/adjust/src/main/java/com/adjust/sdk/GooglePlayServicesClient.java rename to Adjust/sdk-core/src/main/java/com/adjust/sdk/GooglePlayServicesClient.java diff --git a/Adjust/adjust/src/main/java/com/adjust/sdk/IActivityHandler.java b/Adjust/sdk-core/src/main/java/com/adjust/sdk/IActivityHandler.java similarity index 93% rename from Adjust/adjust/src/main/java/com/adjust/sdk/IActivityHandler.java rename to Adjust/sdk-core/src/main/java/com/adjust/sdk/IActivityHandler.java index c704503b4..bf506a659 100644 --- a/Adjust/adjust/src/main/java/com/adjust/sdk/IActivityHandler.java +++ b/Adjust/sdk-core/src/main/java/com/adjust/sdk/IActivityHandler.java @@ -35,7 +35,7 @@ public interface IActivityHandler { void sendReftagReferrer(); - void sendInstallReferrer(long clickTime, long installBegin, String installReferrer); + void sendInstallReferrer(String installReferrer, long referrerClickTimestampSeconds, long installBeginTimestampSeconds); void setOfflineMode(boolean enabled); diff --git a/Adjust/adjust/src/main/java/com/adjust/sdk/IAttributionHandler.java b/Adjust/sdk-core/src/main/java/com/adjust/sdk/IAttributionHandler.java similarity index 55% rename from Adjust/adjust/src/main/java/com/adjust/sdk/IAttributionHandler.java rename to Adjust/sdk-core/src/main/java/com/adjust/sdk/IAttributionHandler.java index 7c5b48776..8b52facb2 100644 --- a/Adjust/adjust/src/main/java/com/adjust/sdk/IAttributionHandler.java +++ b/Adjust/sdk-core/src/main/java/com/adjust/sdk/IAttributionHandler.java @@ -1,22 +1,19 @@ +// +// IAttributionHandler.java +// Adjust SDK +// +// Created by Pedro Silva (@nonelse) on 15th December 2014. +// Copyright (c) 2014-2018 Adjust GmbH. All rights reserved. +// + package com.adjust.sdk; -/** - * Created by pfms on 15/12/14. - */ public interface IAttributionHandler { - void init(IActivityHandler activityHandler, - ActivityPackage attributionPackage, - boolean startsSending); - - void getAttribution(); - + void init(IActivityHandler activityHandler, boolean startsSending); void checkSessionResponse(SessionResponseData sessionResponseData); - void checkSdkClickResponse(SdkClickResponseData sdkClickResponseData); - void pauseSending(); - void resumeSending(); - + void getAttribution(); void teardown(); } diff --git a/Adjust/adjust/src/main/java/com/adjust/sdk/ILogger.java b/Adjust/sdk-core/src/main/java/com/adjust/sdk/ILogger.java similarity index 100% rename from Adjust/adjust/src/main/java/com/adjust/sdk/ILogger.java rename to Adjust/sdk-core/src/main/java/com/adjust/sdk/ILogger.java diff --git a/Adjust/adjust/src/main/java/com/adjust/sdk/IPackageHandler.java b/Adjust/sdk-core/src/main/java/com/adjust/sdk/IPackageHandler.java similarity index 100% rename from Adjust/adjust/src/main/java/com/adjust/sdk/IPackageHandler.java rename to Adjust/sdk-core/src/main/java/com/adjust/sdk/IPackageHandler.java diff --git a/Adjust/adjust/src/main/java/com/adjust/sdk/IRequestHandler.java b/Adjust/sdk-core/src/main/java/com/adjust/sdk/IRequestHandler.java similarity index 100% rename from Adjust/adjust/src/main/java/com/adjust/sdk/IRequestHandler.java rename to Adjust/sdk-core/src/main/java/com/adjust/sdk/IRequestHandler.java diff --git a/Adjust/adjust/src/main/java/com/adjust/sdk/IRunActivityHandler.java b/Adjust/sdk-core/src/main/java/com/adjust/sdk/IRunActivityHandler.java similarity index 100% rename from Adjust/adjust/src/main/java/com/adjust/sdk/IRunActivityHandler.java rename to Adjust/sdk-core/src/main/java/com/adjust/sdk/IRunActivityHandler.java diff --git a/Adjust/adjust/src/main/java/com/adjust/sdk/ISdkClickHandler.java b/Adjust/sdk-core/src/main/java/com/adjust/sdk/ISdkClickHandler.java similarity index 100% rename from Adjust/adjust/src/main/java/com/adjust/sdk/ISdkClickHandler.java rename to Adjust/sdk-core/src/main/java/com/adjust/sdk/ISdkClickHandler.java diff --git a/Adjust/adjust/src/main/java/com/adjust/sdk/InstallReferrer.java b/Adjust/sdk-core/src/main/java/com/adjust/sdk/InstallReferrer.java similarity index 78% rename from Adjust/adjust/src/main/java/com/adjust/sdk/InstallReferrer.java rename to Adjust/sdk-core/src/main/java/com/adjust/sdk/InstallReferrer.java index c426d75f3..882b0c4df 100644 --- a/Adjust/adjust/src/main/java/com/adjust/sdk/InstallReferrer.java +++ b/Adjust/sdk-core/src/main/java/com/adjust/sdk/InstallReferrer.java @@ -2,13 +2,13 @@ import android.content.Context; -import java.io.PrintWriter; -import java.io.StringWriter; -import java.lang.ref.WeakReference; +import com.adjust.sdk.scheduler.TimerOnce; + import java.lang.reflect.InvocationHandler; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Proxy; +import java.util.concurrent.atomic.AtomicBoolean; import static com.adjust.sdk.Constants.ONE_SECOND; @@ -62,7 +62,7 @@ public class InstallReferrer implements InvocationHandler { /** * Boolean indicating whether service responded with install referrer information. */ - private boolean hasInstallReferrerBeenRead; + private final AtomicBoolean hasInstallReferrerBeenRead; /** * Adjust logger instance. @@ -79,11 +79,6 @@ public class InstallReferrer implements InvocationHandler { */ private Context context; - /** - * Lock. - */ - private final Object flagLock; - /** * Timer which fires retry attempts. */ @@ -92,19 +87,21 @@ public class InstallReferrer implements InvocationHandler { /** * Weak reference to ActivityHandler instance. */ - private WeakReference activityHandlerWeakRef; + private final InstallReferrerReadListener referrerCallback; + + private Object playInstallReferrer; /** * Default constructor. * * @param context Application context - * @param activityHandler ActivityHandler reference + * @param referrerCallback Callback for referrer information */ - public InstallReferrer(final Context context, final IActivityHandler activityHandler) { + public InstallReferrer(final Context context, final InstallReferrerReadListener referrerCallback) { this.logger = AdjustFactory.getLogger(); + this.playInstallReferrer = createInstallReferrer(context, referrerCallback, logger); this.context = context; - this.flagLock = new Object(); - this.hasInstallReferrerBeenRead = false; + this.hasInstallReferrerBeenRead = new AtomicBoolean(false); this.retries = 0; this.retryTimer = new TimerOnce(new Runnable() { @Override @@ -112,23 +109,36 @@ public void run() { startConnection(); } }, "InstallReferrer"); - activityHandlerWeakRef = new WeakReference(activityHandler); + this.referrerCallback = referrerCallback; + } + + private Object createInstallReferrer(Context context, InstallReferrerReadListener referrerCallback, ILogger logger) { + return Reflection.createInstance("com.adjust.sdk.play.InstallReferrer", + new Class[]{Context.class, InstallReferrerReadListener.class, ILogger.class}, + context, referrerCallback, logger); } /** * Start connection with install referrer service. */ public void startConnection() { + if (this.playInstallReferrer != null) { + try { + Reflection.invokeInstanceMethod(this.playInstallReferrer, "startConnection", null); + return; + } catch (Exception e) { + logger.error("Call to Play startConnection error: %s", e.getMessage()); + } + } + if (!AdjustFactory.getTryInstallReferrer()) { return; } closeReferrerClient(); - synchronized (flagLock) { - if (hasInstallReferrerBeenRead) { - logger.debug("Install referrer has already been read"); - return; - } + if (hasInstallReferrerBeenRead.get()) { + logger.debug("Install referrer has already been read"); + return; } if (context == null) { @@ -287,7 +297,8 @@ public Object invoke(final Object proxy, final Method method, Object[] args) onInstallReferrerSetupFinishedInt(responseCode); } else if (methodName.equals("onInstallReferrerServiceDisconnected")) { - logger.debug("InstallReferrer onInstallReferrerServiceDisconnected"); + logger.debug("Connection to install referrer service was lost. Retrying ..."); + retry(); } return null; } @@ -298,7 +309,9 @@ public Object invoke(final Object proxy, final Method method, Object[] args) * @param responseCode Response code from install referrer service */ private void onInstallReferrerSetupFinishedInt(final int responseCode) { + boolean retryAtEnd = false; switch (responseCode) { + /** Success. */ case STATUS_OK: // Connection established try { @@ -310,43 +323,55 @@ private void onInstallReferrerSetupFinishedInt(final int responseCode) { logger.debug("installReferrer: %s, clickTime: %d, installBeginTime: %d", installReferrer, clickTime, installBegin); + logger.debug("Install Referrer read successfully. Closing connection"); + // Stuff successfully read, try to send it. - IActivityHandler activityHandler = activityHandlerWeakRef.get(); - if (activityHandler != null) { - activityHandler.sendInstallReferrer(clickTime, installBegin, installReferrer); - } - synchronized (flagLock) { - hasInstallReferrerBeenRead = true; - } - closeReferrerClient(); + referrerCallback.onInstallReferrerRead(installReferrer, clickTime, installBegin); + + hasInstallReferrerBeenRead.set(true); } catch (Exception e) { - logger.warn("Couldn't get install referrer from client (%s). Retrying ...", e.getMessage()); - retry(); + logger.warn("Couldn't get install referrer from client (%s). Retrying...", e.getMessage()); + retryAtEnd = true; } break; + /** Install Referrer API not supported by the installed Play Store app. */ case STATUS_FEATURE_NOT_SUPPORTED: // API not available on the current Play Store app - logger.debug("Install referrer not available on the current Play Store app."); + logger.debug("Install Referrer API not supported by the installed Play Store app. Closing connection"); break; + /** Could not initiate connection to the Install Referrer service. */ case STATUS_SERVICE_UNAVAILABLE: // Connection could not be established - logger.debug("Could not initiate connection to the Install Referrer service. Retrying ..."); - retry(); - break; - case STATUS_DEVELOPER_ERROR: - logger.debug("Install referrer general errors caused by incorrect usage. Retrying ..."); - retry(); + logger.debug("Could not initiate connection to the Install Referrer service. Retrying..."); + retryAtEnd = true; break; + /** + * Play Store service is not connected now - potentially transient state. + * + *

E.g. Play Store could have been updated in the background while your app was still + * running. So feel free to introduce your retry policy for such use case. It should lead to a + * call to {@link #startConnection(InstallReferrerStateListener)} right after or in some time + * after you received this code. + */ case STATUS_SERVICE_DISCONNECTED: // Play Store service is not connected now - potentially transient state - logger.debug("Play Store service is not connected now. Retrying ..."); - retry(); + logger.debug("Play Store service is not connected now. Retrying..."); + retryAtEnd = true; + break; + /** General errors caused by incorrect usage */ + case STATUS_DEVELOPER_ERROR: + logger.debug("Install Referrer API general errors caused by incorrect usage. Retrying..."); + retryAtEnd = true; break; default: - logger.debug("Unexpected response code of install referrer response: %d", responseCode); - closeReferrerClient(); + logger.debug("Unexpected response code of install referrer response: %d. Closing connection", responseCode); break; } + if (retryAtEnd) { + retry(); + } else { + closeReferrerClient(); + } } /** @@ -439,16 +464,14 @@ private long getInstallBeginTimestampSeconds(final Object referrerDetails) { * Retry connection to install referrer service. */ private void retry() { - synchronized (flagLock) { - if (hasInstallReferrerBeenRead) { - logger.debug("Install referrer has already been read"); - return; - } + if (hasInstallReferrerBeenRead.get()) { + logger.debug("Install referrer has already been read"); + closeReferrerClient(); + return; } - // Increase retry counter - retries++; - if (retries > Constants.MAX_INSTALL_REFERRER_RETRIES) { - logger.debug("Limit number of retry for install referrer surpassed"); + // Check increase retry counter + if (retries + 1 > Constants.MAX_INSTALL_REFERRER_RETRIES) { + logger.debug("Limit number of retry of %d for install referrer surpassed", Constants.MAX_INSTALL_REFERRER_RETRIES); return; } @@ -457,6 +480,10 @@ private void retry() { logger.debug("Already waiting to retry to read install referrer in %d milliseconds", firingIn); return; } + + retries++; + logger.debug("Retry number %d to connect to install referrer API", retries); + retryTimer.startIn(retryWaitTime); } @@ -470,6 +497,7 @@ private void closeReferrerClient() { try { Reflection.invokeInstanceMethod(referrerClient, "endConnection", null); + logger.debug("Install Referrer API connection closed"); } catch (Exception e) { logger.error("closeReferrerClient error (%s) thrown by (%s)", e.getMessage(), diff --git a/Adjust/sdk-core/src/main/java/com/adjust/sdk/InstallReferrerReadListener.java b/Adjust/sdk-core/src/main/java/com/adjust/sdk/InstallReferrerReadListener.java new file mode 100644 index 000000000..3c9270922 --- /dev/null +++ b/Adjust/sdk-core/src/main/java/com/adjust/sdk/InstallReferrerReadListener.java @@ -0,0 +1,5 @@ +package com.adjust.sdk; + +public interface InstallReferrerReadListener { + void onInstallReferrerRead(String installReferrer, long referrerClickTimestampSeconds, long installBeginTimestampSeconds); +} diff --git a/Adjust/adjust/src/main/java/com/adjust/sdk/LogLevel.java b/Adjust/sdk-core/src/main/java/com/adjust/sdk/LogLevel.java similarity index 100% rename from Adjust/adjust/src/main/java/com/adjust/sdk/LogLevel.java rename to Adjust/sdk-core/src/main/java/com/adjust/sdk/LogLevel.java diff --git a/Adjust/adjust/src/main/java/com/adjust/sdk/Logger.java b/Adjust/sdk-core/src/main/java/com/adjust/sdk/Logger.java similarity index 100% rename from Adjust/adjust/src/main/java/com/adjust/sdk/Logger.java rename to Adjust/sdk-core/src/main/java/com/adjust/sdk/Logger.java diff --git a/Adjust/adjust/src/main/java/com/adjust/sdk/MacAddressUtil.java b/Adjust/sdk-core/src/main/java/com/adjust/sdk/MacAddressUtil.java similarity index 100% rename from Adjust/adjust/src/main/java/com/adjust/sdk/MacAddressUtil.java rename to Adjust/sdk-core/src/main/java/com/adjust/sdk/MacAddressUtil.java diff --git a/Adjust/adjust/src/main/java/com/adjust/sdk/OnAttributionChangedListener.java b/Adjust/sdk-core/src/main/java/com/adjust/sdk/OnAttributionChangedListener.java similarity index 100% rename from Adjust/adjust/src/main/java/com/adjust/sdk/OnAttributionChangedListener.java rename to Adjust/sdk-core/src/main/java/com/adjust/sdk/OnAttributionChangedListener.java diff --git a/Adjust/adjust/src/main/java/com/adjust/sdk/OnDeeplinkResponseListener.java b/Adjust/sdk-core/src/main/java/com/adjust/sdk/OnDeeplinkResponseListener.java similarity index 100% rename from Adjust/adjust/src/main/java/com/adjust/sdk/OnDeeplinkResponseListener.java rename to Adjust/sdk-core/src/main/java/com/adjust/sdk/OnDeeplinkResponseListener.java diff --git a/Adjust/adjust/src/main/java/com/adjust/sdk/OnDeviceIdsRead.java b/Adjust/sdk-core/src/main/java/com/adjust/sdk/OnDeviceIdsRead.java similarity index 100% rename from Adjust/adjust/src/main/java/com/adjust/sdk/OnDeviceIdsRead.java rename to Adjust/sdk-core/src/main/java/com/adjust/sdk/OnDeviceIdsRead.java diff --git a/Adjust/adjust/src/main/java/com/adjust/sdk/OnEventTrackingFailedListener.java b/Adjust/sdk-core/src/main/java/com/adjust/sdk/OnEventTrackingFailedListener.java similarity index 100% rename from Adjust/adjust/src/main/java/com/adjust/sdk/OnEventTrackingFailedListener.java rename to Adjust/sdk-core/src/main/java/com/adjust/sdk/OnEventTrackingFailedListener.java diff --git a/Adjust/adjust/src/main/java/com/adjust/sdk/OnEventTrackingSucceededListener.java b/Adjust/sdk-core/src/main/java/com/adjust/sdk/OnEventTrackingSucceededListener.java similarity index 100% rename from Adjust/adjust/src/main/java/com/adjust/sdk/OnEventTrackingSucceededListener.java rename to Adjust/sdk-core/src/main/java/com/adjust/sdk/OnEventTrackingSucceededListener.java diff --git a/Adjust/adjust/src/main/java/com/adjust/sdk/OnSessionTrackingFailedListener.java b/Adjust/sdk-core/src/main/java/com/adjust/sdk/OnSessionTrackingFailedListener.java similarity index 100% rename from Adjust/adjust/src/main/java/com/adjust/sdk/OnSessionTrackingFailedListener.java rename to Adjust/sdk-core/src/main/java/com/adjust/sdk/OnSessionTrackingFailedListener.java diff --git a/Adjust/adjust/src/main/java/com/adjust/sdk/OnSessionTrackingSucceededListener.java b/Adjust/sdk-core/src/main/java/com/adjust/sdk/OnSessionTrackingSucceededListener.java similarity index 100% rename from Adjust/adjust/src/main/java/com/adjust/sdk/OnSessionTrackingSucceededListener.java rename to Adjust/sdk-core/src/main/java/com/adjust/sdk/OnSessionTrackingSucceededListener.java diff --git a/Adjust/sdk-core/src/main/java/com/adjust/sdk/PackageBuilder.java b/Adjust/sdk-core/src/main/java/com/adjust/sdk/PackageBuilder.java new file mode 100644 index 000000000..71e47a4cc --- /dev/null +++ b/Adjust/sdk-core/src/main/java/com/adjust/sdk/PackageBuilder.java @@ -0,0 +1,641 @@ +// +// PackageBuilder.java +// Adjust SDK +// +// Created by Christian Wellenbrock (@wellle) on 25th June 2013. +// Copyright (c) 2013-2018 Adjust GmbH. All rights reserved. +// + +package com.adjust.sdk; + +import java.util.Map; +import java.util.Date; +import java.util.HashMap; + +import org.json.JSONObject; + +import android.text.TextUtils; +import android.content.ContentResolver; + +public class PackageBuilder { + private static ILogger logger = AdjustFactory.getLogger(); + private long createdAt; + private DeviceInfo deviceInfo; + private AdjustConfig adjustConfig; + private ActivityStateCopy activityStateCopy; + private SessionParameters sessionParameters; + + long clickTimeInSeconds = -1; + long clickTimeInMilliseconds = -1; + long installBeginTimeInSeconds = -1; + String reftag; + String deeplink; + String referrer; + String rawReferrer; + AdjustAttribution attribution; + Map extraParameters; + + private class ActivityStateCopy { + int eventCount = -1; + int sessionCount = -1; + int subsessionCount = -1; + long timeSpent = -1; + long lastInterval = -1; + long sessionLength = -1; + String uuid = null; + String pushToken = null; + + ActivityStateCopy(ActivityState activityState) { + if (activityState == null) { + return; + } + this.eventCount = activityState.eventCount; + this.sessionCount = activityState.sessionCount; + this.subsessionCount = activityState.subsessionCount; + this.timeSpent = activityState.timeSpent; + this.lastInterval = activityState.lastInterval; + this.sessionLength = activityState.sessionLength; + this.uuid = activityState.uuid; + this.pushToken = activityState.pushToken; + } + } + + PackageBuilder(AdjustConfig adjustConfig, + DeviceInfo deviceInfo, + ActivityState activityState, + SessionParameters sessionParameters, + long createdAt) { + this.createdAt = createdAt; + this.deviceInfo = deviceInfo; + this.adjustConfig = adjustConfig; + this.activityStateCopy = new ActivityStateCopy(activityState); + this.sessionParameters = sessionParameters; + } + + ActivityPackage buildSessionPackage(boolean isInDelay) { + Map parameters = getSessionParameters(isInDelay); + ActivityPackage sessionPackage = getDefaultActivityPackage(ActivityKind.SESSION); + sessionPackage.setPath("/session"); + sessionPackage.setSuffix(""); + sessionPackage.setParameters(parameters); + return sessionPackage; + } + + ActivityPackage buildEventPackage(AdjustEvent event, boolean isInDelay) { + Map parameters = getEventParameters(event, isInDelay); + ActivityPackage eventPackage = getDefaultActivityPackage(ActivityKind.EVENT); + eventPackage.setPath("/event"); + eventPackage.setSuffix(getEventSuffix(event)); + eventPackage.setParameters(parameters); + + if (isInDelay) { + eventPackage.setCallbackParameters(event.callbackParameters); + eventPackage.setPartnerParameters(event.partnerParameters); + } + + return eventPackage; + } + + ActivityPackage buildInfoPackage(String source) { + Map parameters = getInfoParameters(source); + ActivityPackage clickPackage = getDefaultActivityPackage(ActivityKind.INFO); + clickPackage.setPath("/sdk_info"); + clickPackage.setSuffix(""); + clickPackage.setParameters(parameters); + return clickPackage; + } + + ActivityPackage buildClickPackage(String source) { + Map parameters = getClickParameters(source); + ActivityPackage clickPackage = getDefaultActivityPackage(ActivityKind.CLICK); + clickPackage.setPath("/sdk_click"); + clickPackage.setSuffix(""); + clickPackage.setClickTimeInMilliseconds(clickTimeInMilliseconds); + clickPackage.setClickTimeInSeconds(clickTimeInSeconds); + clickPackage.setInstallBeginTimeInSeconds(installBeginTimeInSeconds); + clickPackage.setParameters(parameters); + return clickPackage; + } + + ActivityPackage buildAttributionPackage(String initiatedByDescription) { + Map parameters = getAttributionParameters(initiatedByDescription); + ActivityPackage attributionPackage = getDefaultActivityPackage(ActivityKind.ATTRIBUTION); + attributionPackage.setPath("attribution"); // does not contain '/' because of Uri.Builder.appendPath + attributionPackage.setSuffix(""); + attributionPackage.setParameters(parameters); + return attributionPackage; + } + + ActivityPackage buildGdprPackage() { + Map parameters = getGdprParameters(); + ActivityPackage gdprPackage = getDefaultActivityPackage(ActivityKind.GDPR); + gdprPackage.setPath("/gdpr_forget_device"); + gdprPackage.setSuffix(""); + gdprPackage.setParameters(parameters); + return gdprPackage; + } + + private Map getSessionParameters(boolean isInDelay) { + ContentResolver contentResolver = adjustConfig.context.getContentResolver(); + Map parameters = new HashMap(); + Map imeiParameters = Reflection.getImeiParameters(adjustConfig.context, logger); + + // Check if plugin is used and if yes, add read parameters. + if (imeiParameters != null) { + parameters.putAll(imeiParameters); + } + + // Callback and partner parameters. + if (!isInDelay) { + PackageBuilder.addMapJson(parameters, "callback_params", this.sessionParameters.callbackParameters); + PackageBuilder.addMapJson(parameters, "partner_params", this.sessionParameters.partnerParameters); + } + + // Device identifiers. + deviceInfo.reloadPlayIds(adjustConfig.context); + PackageBuilder.addString(parameters, "android_uuid", activityStateCopy.uuid); + PackageBuilder.addBoolean(parameters, "tracking_enabled", deviceInfo.isTrackingEnabled); + PackageBuilder.addString(parameters, "gps_adid", deviceInfo.playAdId); + PackageBuilder.addString(parameters, "gps_adid_src", deviceInfo.playAdIdSource); + + if (!containsPlayIds(parameters)) { + logger.warn("Google Advertising ID not detected, fallback to non Google Play identifiers will take place"); + deviceInfo.reloadNonPlayIds(adjustConfig.context); + PackageBuilder.addString(parameters, "mac_sha1", deviceInfo.macSha1); + PackageBuilder.addString(parameters, "mac_md5", deviceInfo.macShortMd5); + PackageBuilder.addString(parameters, "android_id", deviceInfo.androidId); + } + + // Rest of the parameters. + PackageBuilder.addString(parameters, "api_level", deviceInfo.apiLevel); + PackageBuilder.addString(parameters, "app_secret", adjustConfig.appSecret); + PackageBuilder.addString(parameters, "app_token", adjustConfig.appToken); + PackageBuilder.addString(parameters, "app_version", deviceInfo.appVersion); + PackageBuilder.addBoolean(parameters, "attribution_deeplink", true); + PackageBuilder.addLong(parameters, "connectivity_type", Util.getConnectivityType(adjustConfig.context)); + PackageBuilder.addString(parameters, "country", deviceInfo.country); + PackageBuilder.addString(parameters, "cpu_type", deviceInfo.abi); + PackageBuilder.addDateInMilliseconds(parameters, "created_at", createdAt); + PackageBuilder.addString(parameters, "default_tracker", adjustConfig.defaultTracker); + PackageBuilder.addBoolean(parameters, "device_known", adjustConfig.deviceKnown); + PackageBuilder.addString(parameters, "device_manufacturer", deviceInfo.deviceManufacturer); + PackageBuilder.addString(parameters, "device_name", deviceInfo.deviceName); + PackageBuilder.addString(parameters, "device_type", deviceInfo.deviceType); + PackageBuilder.addString(parameters, "display_height", deviceInfo.displayHeight); + PackageBuilder.addString(parameters, "display_width", deviceInfo.displayWidth); + PackageBuilder.addString(parameters, "environment", adjustConfig.environment); + PackageBuilder.addBoolean(parameters, "event_buffering_enabled", adjustConfig.eventBufferingEnabled); + PackageBuilder.addString(parameters, "fb_id", deviceInfo.fbAttributionId); + PackageBuilder.addString(parameters, "fire_adid", Util.getFireAdvertisingId(contentResolver)); + PackageBuilder.addBoolean(parameters, "fire_tracking_enabled", Util.getFireTrackingEnabled(contentResolver)); + PackageBuilder.addString(parameters, "hardware_name", deviceInfo.hardwareName); + PackageBuilder.addString(parameters, "installed_at", deviceInfo.appInstallTime); + PackageBuilder.addString(parameters, "language", deviceInfo.language); + PackageBuilder.addDuration(parameters, "last_interval", activityStateCopy.lastInterval); + PackageBuilder.addString(parameters, "mcc", Util.getMcc(adjustConfig.context)); + PackageBuilder.addString(parameters, "mnc", Util.getMnc(adjustConfig.context)); + PackageBuilder.addBoolean(parameters, "needs_response_details", true); + PackageBuilder.addLong(parameters, "network_type", Util.getNetworkType(adjustConfig.context)); + PackageBuilder.addString(parameters, "os_build", deviceInfo.buildName); + PackageBuilder.addString(parameters, "os_name", deviceInfo.osName); + PackageBuilder.addString(parameters, "os_version", deviceInfo.osVersion); + PackageBuilder.addString(parameters, "package_name", deviceInfo.packageName); + PackageBuilder.addString(parameters, "push_token", activityStateCopy.pushToken); + PackageBuilder.addString(parameters, "screen_density", deviceInfo.screenDensity); + PackageBuilder.addString(parameters, "screen_format", deviceInfo.screenFormat); + PackageBuilder.addString(parameters, "screen_size", deviceInfo.screenSize); + PackageBuilder.addString(parameters, "secret_id", adjustConfig.secretId); + PackageBuilder.addLong(parameters, "session_count", activityStateCopy.sessionCount); + PackageBuilder.addDuration(parameters, "session_length", activityStateCopy.sessionLength); + PackageBuilder.addLong(parameters, "subsession_count", activityStateCopy.subsessionCount); + PackageBuilder.addDuration(parameters, "time_spent", activityStateCopy.timeSpent); + PackageBuilder.addString(parameters, "updated_at", deviceInfo.appUpdateTime); + + checkDeviceIds(parameters); + return parameters; + } + + public Map getEventParameters(AdjustEvent event, boolean isInDelay) { + ContentResolver contentResolver = adjustConfig.context.getContentResolver(); + Map parameters = new HashMap(); + Map imeiParameters = Reflection.getImeiParameters(adjustConfig.context, logger); + + // Check if plugin is used and if yes, add read parameters. + if (imeiParameters != null) { + parameters.putAll(imeiParameters); + } + + // Callback and partner parameters. + if (!isInDelay) { + PackageBuilder.addMapJson(parameters, "callback_params", Util.mergeParameters(this.sessionParameters.callbackParameters, event.callbackParameters, "Callback")); + PackageBuilder.addMapJson(parameters, "partner_params", Util.mergeParameters(this.sessionParameters.partnerParameters, event.partnerParameters, "Partner")); + } + + // Device identifiers. + deviceInfo.reloadPlayIds(adjustConfig.context); + PackageBuilder.addString(parameters, "android_uuid", activityStateCopy.uuid); + PackageBuilder.addBoolean(parameters, "tracking_enabled", deviceInfo.isTrackingEnabled); + PackageBuilder.addString(parameters, "gps_adid", deviceInfo.playAdId); + PackageBuilder.addString(parameters, "gps_adid_src", deviceInfo.playAdIdSource); + + if (!containsPlayIds(parameters)) { + logger.warn("Google Advertising ID not detected, fallback to non Google Play identifiers will take place"); + deviceInfo.reloadNonPlayIds(adjustConfig.context); + PackageBuilder.addString(parameters, "mac_sha1", deviceInfo.macSha1); + PackageBuilder.addString(parameters, "mac_md5", deviceInfo.macShortMd5); + PackageBuilder.addString(parameters, "android_id", deviceInfo.androidId); + } + + // Rest of the parameters. + PackageBuilder.addString(parameters, "api_level", deviceInfo.apiLevel); + PackageBuilder.addString(parameters, "app_secret", adjustConfig.appSecret); + PackageBuilder.addString(parameters, "app_token", adjustConfig.appToken); + PackageBuilder.addString(parameters, "app_version", deviceInfo.appVersion); + PackageBuilder.addBoolean(parameters, "attribution_deeplink", true); + PackageBuilder.addLong(parameters, "connectivity_type", Util.getConnectivityType(adjustConfig.context)); + PackageBuilder.addString(parameters, "country", deviceInfo.country); + PackageBuilder.addString(parameters, "cpu_type", deviceInfo.abi); + PackageBuilder.addDateInMilliseconds(parameters, "created_at", createdAt); + PackageBuilder.addString(parameters, "currency", event.currency); + PackageBuilder.addBoolean(parameters, "device_known", adjustConfig.deviceKnown); + PackageBuilder.addString(parameters, "device_manufacturer", deviceInfo.deviceManufacturer); + PackageBuilder.addString(parameters, "device_name", deviceInfo.deviceName); + PackageBuilder.addString(parameters, "device_type", deviceInfo.deviceType); + PackageBuilder.addString(parameters, "display_height", deviceInfo.displayHeight); + PackageBuilder.addString(parameters, "display_width", deviceInfo.displayWidth); + PackageBuilder.addString(parameters, "environment", adjustConfig.environment); + PackageBuilder.addString(parameters, "event_callback_id", event.callbackId); + PackageBuilder.addLong(parameters, "event_count", activityStateCopy.eventCount); + PackageBuilder.addBoolean(parameters, "event_buffering_enabled", adjustConfig.eventBufferingEnabled); + PackageBuilder.addString(parameters, "event_token", event.eventToken); + PackageBuilder.addString(parameters, "fb_id", deviceInfo.fbAttributionId); + PackageBuilder.addString(parameters, "fire_adid", Util.getFireAdvertisingId(contentResolver)); + PackageBuilder.addBoolean(parameters, "fire_tracking_enabled", Util.getFireTrackingEnabled(contentResolver)); + PackageBuilder.addString(parameters, "hardware_name", deviceInfo.hardwareName); + PackageBuilder.addString(parameters, "language", deviceInfo.language); + PackageBuilder.addString(parameters, "mcc", Util.getMcc(adjustConfig.context)); + PackageBuilder.addString(parameters, "mnc", Util.getMnc(adjustConfig.context)); + PackageBuilder.addBoolean(parameters, "needs_response_details", true); + PackageBuilder.addLong(parameters, "network_type", Util.getNetworkType(adjustConfig.context)); + PackageBuilder.addString(parameters, "os_build", deviceInfo.buildName); + PackageBuilder.addString(parameters, "os_name", deviceInfo.osName); + PackageBuilder.addString(parameters, "os_version", deviceInfo.osVersion); + PackageBuilder.addString(parameters, "package_name", deviceInfo.packageName); + PackageBuilder.addString(parameters, "push_token", activityStateCopy.pushToken); + PackageBuilder.addDouble(parameters, "revenue", event.revenue); + PackageBuilder.addString(parameters, "screen_density", deviceInfo.screenDensity); + PackageBuilder.addString(parameters, "screen_format", deviceInfo.screenFormat); + PackageBuilder.addString(parameters, "screen_size", deviceInfo.screenSize); + PackageBuilder.addString(parameters, "secret_id", adjustConfig.secretId); + PackageBuilder.addLong(parameters, "session_count", activityStateCopy.sessionCount); + PackageBuilder.addDuration(parameters, "session_length", activityStateCopy.sessionLength); + PackageBuilder.addLong(parameters, "subsession_count", activityStateCopy.subsessionCount); + PackageBuilder.addDuration(parameters, "time_spent", activityStateCopy.timeSpent); + + checkDeviceIds(parameters); + return parameters; + } + + private Map getInfoParameters(String source) { + ContentResolver contentResolver = adjustConfig.context.getContentResolver(); + Map parameters = new HashMap(); + Map imeiParameters = Reflection.getImeiParameters(adjustConfig.context, logger); + + // Check if plugin is used and if yes, add read parameters. + if (imeiParameters != null) { + parameters.putAll(imeiParameters); + } + + // Device identifiers. + deviceInfo.reloadPlayIds(adjustConfig.context); + PackageBuilder.addString(parameters, "android_uuid", activityStateCopy.uuid); + PackageBuilder.addBoolean(parameters, "tracking_enabled", deviceInfo.isTrackingEnabled); + PackageBuilder.addString(parameters, "gps_adid", deviceInfo.playAdId); + PackageBuilder.addString(parameters, "gps_adid_src", deviceInfo.playAdIdSource); + + if (!containsPlayIds(parameters)) { + logger.warn("Google Advertising ID not detected, fallback to non Google Play identifiers will take place"); + deviceInfo.reloadNonPlayIds(adjustConfig.context); + PackageBuilder.addString(parameters, "mac_sha1", deviceInfo.macSha1); + PackageBuilder.addString(parameters, "mac_md5", deviceInfo.macShortMd5); + PackageBuilder.addString(parameters, "android_id", deviceInfo.androidId); + } + + // Rest of the parameters. + PackageBuilder.addString(parameters, "app_secret", adjustConfig.appSecret); + PackageBuilder.addString(parameters, "app_token", adjustConfig.appToken); + PackageBuilder.addBoolean(parameters, "attribution_deeplink", true); + PackageBuilder.addDateInMilliseconds(parameters, "created_at", createdAt); + PackageBuilder.addBoolean(parameters, "device_known", adjustConfig.deviceKnown); + PackageBuilder.addString(parameters, "environment", adjustConfig.environment); + PackageBuilder.addBoolean(parameters, "event_buffering_enabled", adjustConfig.eventBufferingEnabled); + PackageBuilder.addString(parameters, "fire_adid", Util.getFireAdvertisingId(contentResolver)); + PackageBuilder.addBoolean(parameters, "fire_tracking_enabled", Util.getFireTrackingEnabled(contentResolver)); + PackageBuilder.addBoolean(parameters, "needs_response_details", true); + PackageBuilder.addString(parameters, "push_token", activityStateCopy.pushToken); + PackageBuilder.addString(parameters, "secret_id", adjustConfig.secretId); + PackageBuilder.addString(parameters, "source", source); + + checkDeviceIds(parameters); + return parameters; + } + + private Map getClickParameters(String source) { + ContentResolver contentResolver = adjustConfig.context.getContentResolver(); + Map parameters = new HashMap(); + Map imeiParameters = Reflection.getImeiParameters(adjustConfig.context, logger); + + // Check if plugin is used and if yes, add read parameters. + if (imeiParameters != null) { + parameters.putAll(imeiParameters); + } + + // Device identifiers. + deviceInfo.reloadPlayIds(adjustConfig.context); + PackageBuilder.addString(parameters, "android_uuid", activityStateCopy.uuid); + PackageBuilder.addBoolean(parameters, "tracking_enabled", deviceInfo.isTrackingEnabled); + PackageBuilder.addString(parameters, "gps_adid", deviceInfo.playAdId); + PackageBuilder.addString(parameters, "gps_adid_src", deviceInfo.playAdIdSource); + + if (!containsPlayIds(parameters)) { + logger.warn("Google Advertising ID not detected, fallback to non Google Play identifiers will take place"); + deviceInfo.reloadNonPlayIds(adjustConfig.context); + PackageBuilder.addString(parameters, "mac_sha1", deviceInfo.macSha1); + PackageBuilder.addString(parameters, "mac_md5", deviceInfo.macShortMd5); + PackageBuilder.addString(parameters, "android_id", deviceInfo.androidId); + } + + // Attribution parameters. + if (attribution != null) { + PackageBuilder.addString(parameters, "tracker", attribution.trackerName); + PackageBuilder.addString(parameters, "campaign", attribution.campaign); + PackageBuilder.addString(parameters, "adgroup", attribution.adgroup); + PackageBuilder.addString(parameters, "creative", attribution.creative); + } + + // Rest of the parameters. + PackageBuilder.addString(parameters, "api_level", deviceInfo.apiLevel); + PackageBuilder.addString(parameters, "app_secret", adjustConfig.appSecret); + PackageBuilder.addString(parameters, "app_token", adjustConfig.appToken); + PackageBuilder.addString(parameters, "app_version", deviceInfo.appVersion); + PackageBuilder.addBoolean(parameters, "attribution_deeplink", true); + PackageBuilder.addMapJson(parameters, "callback_params", this.sessionParameters.callbackParameters); + PackageBuilder.addDateInMilliseconds(parameters, "click_time", clickTimeInMilliseconds); + PackageBuilder.addDateInSeconds(parameters, "click_time", clickTimeInSeconds); + PackageBuilder.addLong(parameters, "connectivity_type", Util.getConnectivityType(adjustConfig.context)); + PackageBuilder.addString(parameters, "country", deviceInfo.country); + PackageBuilder.addString(parameters, "cpu_type", deviceInfo.abi); + PackageBuilder.addDateInMilliseconds(parameters, "created_at", createdAt); + PackageBuilder.addString(parameters, "deeplink", deeplink); + PackageBuilder.addBoolean(parameters, "device_known", adjustConfig.deviceKnown); + PackageBuilder.addString(parameters, "device_manufacturer", deviceInfo.deviceManufacturer); + PackageBuilder.addString(parameters, "device_name", deviceInfo.deviceName); + PackageBuilder.addString(parameters, "device_type", deviceInfo.deviceType); + PackageBuilder.addString(parameters, "display_height", deviceInfo.displayHeight); + PackageBuilder.addString(parameters, "display_width", deviceInfo.displayWidth); + PackageBuilder.addString(parameters, "environment", adjustConfig.environment); + PackageBuilder.addBoolean(parameters, "event_buffering_enabled", adjustConfig.eventBufferingEnabled); + PackageBuilder.addString(parameters, "fb_id", deviceInfo.fbAttributionId); + PackageBuilder.addString(parameters, "fire_adid", Util.getFireAdvertisingId(contentResolver)); + PackageBuilder.addBoolean(parameters, "fire_tracking_enabled", Util.getFireTrackingEnabled(contentResolver)); + PackageBuilder.addString(parameters, "hardware_name", deviceInfo.hardwareName); + PackageBuilder.addDateInSeconds(parameters, "install_begin_time", installBeginTimeInSeconds); + PackageBuilder.addString(parameters, "installed_at", deviceInfo.appInstallTime); + PackageBuilder.addString(parameters, "language", deviceInfo.language); + PackageBuilder.addDuration(parameters, "last_interval", activityStateCopy.lastInterval); + PackageBuilder.addString(parameters, "mcc", Util.getMcc(adjustConfig.context)); + PackageBuilder.addString(parameters, "mnc", Util.getMnc(adjustConfig.context)); + PackageBuilder.addBoolean(parameters, "needs_response_details", true); + PackageBuilder.addLong(parameters, "network_type", Util.getNetworkType(adjustConfig.context)); + PackageBuilder.addString(parameters, "os_build", deviceInfo.buildName); + PackageBuilder.addString(parameters, "os_name", deviceInfo.osName); + PackageBuilder.addString(parameters, "os_version", deviceInfo.osVersion); + PackageBuilder.addString(parameters, "package_name", deviceInfo.packageName); + PackageBuilder.addMapJson(parameters, "params", extraParameters); + PackageBuilder.addMapJson(parameters, "partner_params", this.sessionParameters.partnerParameters); + PackageBuilder.addString(parameters, "push_token", activityStateCopy.pushToken); + PackageBuilder.addString(parameters, "raw_referrer", rawReferrer); + PackageBuilder.addString(parameters, "referrer", referrer); + PackageBuilder.addString(parameters, "reftag", reftag); + PackageBuilder.addString(parameters, "screen_density", deviceInfo.screenDensity); + PackageBuilder.addString(parameters, "screen_format", deviceInfo.screenFormat); + PackageBuilder.addString(parameters, "screen_size", deviceInfo.screenSize); + PackageBuilder.addString(parameters, "secret_id", adjustConfig.secretId); + PackageBuilder.addLong(parameters, "session_count", activityStateCopy.sessionCount); + PackageBuilder.addDuration(parameters, "session_length", activityStateCopy.sessionLength); + PackageBuilder.addString(parameters, "source", source); + PackageBuilder.addLong(parameters, "subsession_count", activityStateCopy.subsessionCount); + PackageBuilder.addDuration(parameters, "time_spent", activityStateCopy.timeSpent); + PackageBuilder.addString(parameters, "updated_at", deviceInfo.appUpdateTime); + + checkDeviceIds(parameters); + return parameters; + } + + private Map getAttributionParameters(String initiatedBy) { + ContentResolver contentResolver = adjustConfig.context.getContentResolver(); + Map parameters = new HashMap(); + Map imeiParameters = Reflection.getImeiParameters(adjustConfig.context, logger); + + // Check if plugin is used and if yes, add read parameters. + if (imeiParameters != null) { + parameters.putAll(imeiParameters); + } + + // Device identifiers. + deviceInfo.reloadPlayIds(adjustConfig.context); + PackageBuilder.addString(parameters, "android_uuid", activityStateCopy.uuid); + PackageBuilder.addBoolean(parameters, "tracking_enabled", deviceInfo.isTrackingEnabled); + PackageBuilder.addString(parameters, "gps_adid", deviceInfo.playAdId); + PackageBuilder.addString(parameters, "gps_adid_src", deviceInfo.playAdIdSource); + + if (!containsPlayIds(parameters)) { + logger.warn("Google Advertising ID not detected, fallback to non Google Play identifiers will take place"); + deviceInfo.reloadNonPlayIds(adjustConfig.context); + PackageBuilder.addString(parameters, "mac_sha1", deviceInfo.macSha1); + PackageBuilder.addString(parameters, "mac_md5", deviceInfo.macShortMd5); + PackageBuilder.addString(parameters, "android_id", deviceInfo.androidId); + } + + // Rest of the parameters. + PackageBuilder.addString(parameters, "api_level", deviceInfo.apiLevel); + PackageBuilder.addString(parameters, "app_secret", adjustConfig.appSecret); + PackageBuilder.addString(parameters, "app_token", adjustConfig.appToken); + PackageBuilder.addString(parameters, "app_version", deviceInfo.appVersion); + PackageBuilder.addBoolean(parameters, "attribution_deeplink", true); + PackageBuilder.addDateInMilliseconds(parameters, "created_at", createdAt); + PackageBuilder.addBoolean(parameters, "device_known", adjustConfig.deviceKnown); + PackageBuilder.addString(parameters, "device_name", deviceInfo.deviceName); + PackageBuilder.addString(parameters, "device_type", deviceInfo.deviceType); + PackageBuilder.addString(parameters, "environment", adjustConfig.environment); + PackageBuilder.addBoolean(parameters, "event_buffering_enabled", adjustConfig.eventBufferingEnabled); + PackageBuilder.addString(parameters, "fire_adid", Util.getFireAdvertisingId(contentResolver)); + PackageBuilder.addBoolean(parameters, "fire_tracking_enabled", Util.getFireTrackingEnabled(contentResolver)); + PackageBuilder.addString(parameters, "initiated_by", initiatedBy); + PackageBuilder.addBoolean(parameters, "needs_response_details", true); + PackageBuilder.addString(parameters, "os_name", deviceInfo.osName); + PackageBuilder.addString(parameters, "os_version", deviceInfo.osVersion); + PackageBuilder.addString(parameters, "package_name", deviceInfo.packageName); + PackageBuilder.addString(parameters, "push_token", activityStateCopy.pushToken); + PackageBuilder.addString(parameters, "secret_id", adjustConfig.secretId); + + checkDeviceIds(parameters); + return parameters; + } + + private Map getGdprParameters() { + ContentResolver contentResolver = adjustConfig.context.getContentResolver(); + Map parameters = new HashMap(); + Map imeiParameters = Reflection.getImeiParameters(adjustConfig.context, logger); + + // Check if plugin is used and if yes, add read parameters. + if (imeiParameters != null) { + parameters.putAll(imeiParameters); + } + + // Device identifiers. + deviceInfo.reloadPlayIds(adjustConfig.context); + PackageBuilder.addString(parameters, "android_uuid", activityStateCopy.uuid); + PackageBuilder.addBoolean(parameters, "tracking_enabled", deviceInfo.isTrackingEnabled); + PackageBuilder.addString(parameters, "gps_adid", deviceInfo.playAdId); + PackageBuilder.addString(parameters, "gps_adid_src", deviceInfo.playAdIdSource); + + if (!containsPlayIds(parameters)) { + logger.warn("Google Advertising ID not detected, fallback to non Google Play identifiers will take place"); + deviceInfo.reloadNonPlayIds(adjustConfig.context); + PackageBuilder.addString(parameters, "mac_sha1", deviceInfo.macSha1); + PackageBuilder.addString(parameters, "mac_md5", deviceInfo.macShortMd5); + PackageBuilder.addString(parameters, "android_id", deviceInfo.androidId); + } + + // Rest of the parameters. + PackageBuilder.addString(parameters, "api_level", deviceInfo.apiLevel); + PackageBuilder.addString(parameters, "app_secret", adjustConfig.appSecret); + PackageBuilder.addString(parameters, "app_token", adjustConfig.appToken); + PackageBuilder.addString(parameters, "app_version", deviceInfo.appVersion); + PackageBuilder.addBoolean(parameters, "attribution_deeplink", true); + PackageBuilder.addDateInMilliseconds(parameters, "created_at", createdAt); + PackageBuilder.addBoolean(parameters, "device_known", adjustConfig.deviceKnown); + PackageBuilder.addString(parameters, "device_name", deviceInfo.deviceName); + PackageBuilder.addString(parameters, "device_type", deviceInfo.deviceType); + PackageBuilder.addString(parameters, "environment", adjustConfig.environment); + PackageBuilder.addBoolean(parameters, "event_buffering_enabled", adjustConfig.eventBufferingEnabled); + PackageBuilder.addString(parameters, "fire_adid", Util.getFireAdvertisingId(contentResolver)); + PackageBuilder.addBoolean(parameters, "fire_tracking_enabled", Util.getFireTrackingEnabled(contentResolver)); + PackageBuilder.addBoolean(parameters, "needs_response_details", true); + PackageBuilder.addString(parameters, "os_name", deviceInfo.osName); + PackageBuilder.addString(parameters, "os_version", deviceInfo.osVersion); + PackageBuilder.addString(parameters, "package_name", deviceInfo.packageName); + PackageBuilder.addString(parameters, "push_token", activityStateCopy.pushToken); + PackageBuilder.addString(parameters, "secret_id", adjustConfig.secretId); + + checkDeviceIds(parameters); + return parameters; + } + + private ActivityPackage getDefaultActivityPackage(ActivityKind activityKind) { + ActivityPackage activityPackage = new ActivityPackage(activityKind); + activityPackage.setClientSdk(deviceInfo.clientSdk); + return activityPackage; + } + + public static void addString(Map parameters, String key, String value) { + if (TextUtils.isEmpty(value)) { + return; + } + parameters.put(key, value); + } + + public static void addBoolean(Map parameters, String key, Boolean value) { + if (value == null) { + return; + } + int intValue = value ? 1 : 0; + PackageBuilder.addLong(parameters, key, intValue); + } + + static void addMapJson(Map parameters, String key, Map map) { + if (map == null) { + return; + } + if (map.size() == 0) { + return; + } + + JSONObject jsonObject = new JSONObject(map); + String jsonString = jsonObject.toString(); + PackageBuilder.addString(parameters, key, jsonString); + } + + private static void addLong(Map parameters, String key, long value) { + if (value < 0) { + return; + } + String valueString = Long.toString(value); + PackageBuilder.addString(parameters, key, valueString); + } + + private static void addDateInMilliseconds(Map parameters, String key, long value) { + if (value <= 0) { + return; + } + Date date = new Date(value); + PackageBuilder.addDate(parameters, key, date); + } + + private static void addDateInSeconds(Map parameters, String key, long value) { + if (value <= 0) { + return; + } + Date date = new Date(value * 1000); + PackageBuilder.addDate(parameters, key, date); + } + + private static void addDate(Map parameters, String key, Date value) { + if (value == null) { + return; + } + String dateString = Util.dateFormatter.format(value); + PackageBuilder.addString(parameters, key, dateString); + } + + private static void addDuration(Map parameters, String key, long durationInMilliSeconds) { + if (durationInMilliSeconds < 0) { + return; + } + long durationInSeconds = (durationInMilliSeconds + 500) / 1000; + PackageBuilder.addLong(parameters, key, durationInSeconds); + } + + private static void addDouble(Map parameters, String key, Double value) { + if (value == null) { + return; + } + String doubleString = Util.formatString("%.5f", value); + PackageBuilder.addString(parameters, key, doubleString); + } + + private boolean containsPlayIds(Map parameters) { + if (parameters == null) { + return false; + } + return parameters.containsKey("tracking_enabled") || parameters.containsKey("gps_adid"); + } + + private void checkDeviceIds(Map parameters) { + if (parameters != null && !parameters.containsKey("mac_sha1") + && !parameters.containsKey("mac_md5") + && !parameters.containsKey("android_id") + && !parameters.containsKey("gps_adid")) { + logger.error("Missing device id's. Please check if Proguard is correctly set with Adjust SDK"); + } + } + + private String getEventSuffix(AdjustEvent event) { + if (event.revenue == null) { + return Util.formatString("'%s'", event.eventToken); + } else { + return Util.formatString("(%.5f %s, '%s')", event.revenue, event.currency, event.eventToken); + } + } +} diff --git a/Adjust/adjust/src/main/java/com/adjust/sdk/PackageFactory.java b/Adjust/sdk-core/src/main/java/com/adjust/sdk/PackageFactory.java similarity index 99% rename from Adjust/adjust/src/main/java/com/adjust/sdk/PackageFactory.java rename to Adjust/sdk-core/src/main/java/com/adjust/sdk/PackageFactory.java index f45e1bb37..6f0f4c074 100644 --- a/Adjust/adjust/src/main/java/com/adjust/sdk/PackageFactory.java +++ b/Adjust/sdk-core/src/main/java/com/adjust/sdk/PackageFactory.java @@ -138,7 +138,7 @@ public static ActivityPackage buildInstallReferrerSdkClickPackage(final String i } clickPackageBuilder.referrer = installReferrer; - clickPackageBuilder.clicktTimeInSeconds = clickTimeInSeconds; + clickPackageBuilder.clickTimeInSeconds = clickTimeInSeconds; clickPackageBuilder.installBeginTimeInSeconds = installBeginInSeconds; ActivityPackage clickPackage = clickPackageBuilder.buildClickPackage(Constants.INSTALL_REFERRER); diff --git a/Adjust/adjust/src/main/java/com/adjust/sdk/PackageHandler.java b/Adjust/sdk-core/src/main/java/com/adjust/sdk/PackageHandler.java similarity index 92% rename from Adjust/adjust/src/main/java/com/adjust/sdk/PackageHandler.java rename to Adjust/sdk-core/src/main/java/com/adjust/sdk/PackageHandler.java index 33621f30e..a90406bba 100644 --- a/Adjust/adjust/src/main/java/com/adjust/sdk/PackageHandler.java +++ b/Adjust/sdk-core/src/main/java/com/adjust/sdk/PackageHandler.java @@ -11,11 +11,13 @@ import android.content.Context; +import com.adjust.sdk.scheduler.SingleThreadCachedScheduler; +import com.adjust.sdk.scheduler.ThreadScheduler; + import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.List; import java.util.Map; -import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import static com.adjust.sdk.Constants.CALLBACK_PARAMETERS; @@ -26,7 +28,7 @@ public class PackageHandler implements IPackageHandler { private static final String PACKAGE_QUEUE_FILENAME = "AdjustIoPackageQueue"; private static final String PACKAGE_QUEUE_NAME = "Package queue"; - private CustomScheduledExecutor scheduledExecutor; + private ThreadScheduler scheduler; private IRequestHandler requestHandler; private WeakReference activityHandlerWeakRef; private List packageQueue; @@ -41,10 +43,8 @@ public class PackageHandler implements IPackageHandler { @Override public void teardown() { logger.verbose("PackageHandler teardown"); - if (scheduledExecutor != null) { - try { - scheduledExecutor.shutdownNow(); - } catch(SecurityException se) {} + if (scheduler != null) { + scheduler.teardown(); } if (activityHandlerWeakRef != null) { activityHandlerWeakRef.clear(); @@ -55,7 +55,7 @@ public void teardown() { if (packageQueue != null) { packageQueue.clear(); } - scheduledExecutor = null; + scheduler = null; requestHandler = null; activityHandlerWeakRef = null; packageQueue = null; @@ -72,13 +72,13 @@ static void deleteState(Context context) { public PackageHandler(IActivityHandler activityHandler, Context context, boolean startsSending) { - this.scheduledExecutor = new CustomScheduledExecutor("PackageHandler", false); + this.scheduler = new SingleThreadCachedScheduler("PackageHandler"); this.logger = AdjustFactory.getLogger(); this.backoffStrategy = AdjustFactory.getPackageHandlerBackoffStrategy(); init(activityHandler, context, startsSending); - scheduledExecutor.submit(new Runnable() { + scheduler.submit(new Runnable() { @Override public void run() { initI(); @@ -98,7 +98,7 @@ public void init(IActivityHandler activityHandler, Context context, boolean star // add a package to the queue @Override public void addPackage(final ActivityPackage activityPackage) { - scheduledExecutor.submit(new Runnable() { + scheduler.submit(new Runnable() { @Override public void run() { addI(activityPackage); @@ -109,7 +109,7 @@ public void run() { // try to send the oldest package @Override public void sendFirstPackage() { - scheduledExecutor.submit(new Runnable() { + scheduler.submit(new Runnable() { @Override public void run() { sendFirstI(); @@ -121,7 +121,7 @@ public void run() { // (after success or possibly permanent failure) @Override public void sendNextPackage(ResponseData responseData) { - scheduledExecutor.submit(new Runnable() { + scheduler.submit(new Runnable() { @Override public void run() { sendNextI(); @@ -168,7 +168,7 @@ public void run() { String secondsString = Util.SecondsDisplayFormat.format(waitTimeSeconds); logger.verbose("Waiting for %s seconds before retrying the %d time", secondsString, retries); - scheduledExecutor.schedule(runnable, waitTimeMilliSeconds, TimeUnit.MILLISECONDS); + scheduler.schedule(runnable, waitTimeMilliSeconds); } // interrupt the sending loop after the current request has finished @@ -191,7 +191,7 @@ public void updatePackages(SessionParameters sessionParameters) { } else { sessionParametersCopy = null; } - scheduledExecutor.submit(new Runnable() { + scheduler.submit(new Runnable() { @Override public void run() { updatePackagesI(sessionParametersCopy); @@ -201,7 +201,7 @@ public void run() { @Override public void flush() { - scheduledExecutor.submit(new Runnable() { + scheduler.submit(new Runnable() { @Override public void run() { flushI(); diff --git a/Adjust/adjust/src/main/java/com/adjust/sdk/Reflection.java b/Adjust/sdk-core/src/main/java/com/adjust/sdk/Reflection.java similarity index 86% rename from Adjust/adjust/src/main/java/com/adjust/sdk/Reflection.java rename to Adjust/sdk-core/src/main/java/com/adjust/sdk/Reflection.java index 0f8079650..1a58095bb 100644 --- a/Adjust/adjust/src/main/java/com/adjust/sdk/Reflection.java +++ b/Adjust/sdk-core/src/main/java/com/adjust/sdk/Reflection.java @@ -10,12 +10,26 @@ import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.Locale; +import java.util.Map; public class Reflection { private static Object getAdvertisingInfoObject(Context context) throws Exception { return invokeStaticMethod("com.google.android.gms.ads.identifier.AdvertisingIdClient", "getAdvertisingIdInfo", new Class[]{Context.class}, context); } + static Map getImeiParameters(Context context, ILogger logger) { + Object nonPlayParameters = null; + try { + nonPlayParameters = invokeStaticMethod("com.adjust.sdk.imei.Util", "getImeiParameters", new Class[]{Context.class, ILogger.class}, context, logger); + Class> stringStringMapClass = (Class>) (Class) Map.class; + if (nonPlayParameters != null && stringStringMapClass.isInstance(nonPlayParameters)) { + return (Map) nonPlayParameters; + } + } catch (Exception e) { + } + return null; + } + public static String getPlayAdId(Context context) { try { Object AdvertisingInfoObject = getAdvertisingInfoObject(context); @@ -76,14 +90,12 @@ public static Object createInstance(String className, Class[] cArgs, Object... a public static Object invokeStaticMethod(String className, String methodName, Class[] cArgs, Object... args) throws Exception { Class classObject = Class.forName(className); - return invokeMethod(classObject, methodName, null, cArgs, args); } public static Object invokeInstanceMethod(Object instance, String methodName, Class[] cArgs, Object... args) throws Exception { Class classObject = instance.getClass(); - return invokeMethod(classObject, methodName, instance, cArgs, args); } @@ -94,8 +106,8 @@ public static Object invokeMethod(Class classObject, String methodName, Object i if (methodObject == null) { return null; } - Object resultObject = methodObject.invoke(instance, args); + Object resultObject = methodObject.invoke(instance, args); return resultObject; } diff --git a/Adjust/adjust/src/main/java/com/adjust/sdk/RequestHandler.java b/Adjust/sdk-core/src/main/java/com/adjust/sdk/RequestHandler.java similarity index 92% rename from Adjust/adjust/src/main/java/com/adjust/sdk/RequestHandler.java rename to Adjust/sdk-core/src/main/java/com/adjust/sdk/RequestHandler.java index e56188306..354636997 100644 --- a/Adjust/adjust/src/main/java/com/adjust/sdk/RequestHandler.java +++ b/Adjust/sdk-core/src/main/java/com/adjust/sdk/RequestHandler.java @@ -9,15 +9,16 @@ package com.adjust.sdk; +import com.adjust.sdk.scheduler.SingleThreadCachedScheduler; +import com.adjust.sdk.scheduler.ThreadExecutor; + import java.io.IOException; import java.io.UnsupportedEncodingException; import java.lang.ref.WeakReference; import java.net.SocketTimeoutException; -import javax.net.ssl.HttpsURLConnection; - public class RequestHandler implements IRequestHandler { - private CustomScheduledExecutor scheduledExecutor; + private ThreadExecutor executor; private WeakReference packageHandlerWeakRef; private WeakReference activityHandlerWeakRef; private ILogger logger; @@ -26,7 +27,7 @@ public class RequestHandler implements IRequestHandler { public RequestHandler(IActivityHandler activityHandler, IPackageHandler packageHandler) { this.logger = AdjustFactory.getLogger(); - this.scheduledExecutor = new CustomScheduledExecutor("RequestHandler", false); + this.executor = new SingleThreadCachedScheduler("RequestHandler"); init(activityHandler, packageHandler); this.basePath = packageHandler.getBasePath(); this.gdprPath = packageHandler.getGdprPath(); @@ -40,7 +41,7 @@ public void init(IActivityHandler activityHandler, IPackageHandler packageHandle @Override public void sendPackage(final ActivityPackage activityPackage, final int queueSize) { - scheduledExecutor.submit(new Runnable() { + executor.submit(new Runnable() { @Override public void run() { sendI(activityPackage, queueSize); @@ -51,10 +52,8 @@ public void run() { @Override public void teardown() { logger.verbose("RequestHandler teardown"); - if (scheduledExecutor != null) { - try { - scheduledExecutor.shutdownNow(); - } catch(SecurityException se) {} + if (executor != null) { + executor.teardown(); } if (packageHandlerWeakRef != null) { packageHandlerWeakRef.clear(); @@ -62,7 +61,7 @@ public void teardown() { if (activityHandlerWeakRef != null) { activityHandlerWeakRef.clear(); } - scheduledExecutor = null; + executor = null; packageHandlerWeakRef = null; activityHandlerWeakRef = null; logger = null; diff --git a/Adjust/adjust/src/main/java/com/adjust/sdk/ResponseData.java b/Adjust/sdk-core/src/main/java/com/adjust/sdk/ResponseData.java similarity index 100% rename from Adjust/adjust/src/main/java/com/adjust/sdk/ResponseData.java rename to Adjust/sdk-core/src/main/java/com/adjust/sdk/ResponseData.java diff --git a/Adjust/adjust/src/main/java/com/adjust/sdk/SdkClickHandler.java b/Adjust/sdk-core/src/main/java/com/adjust/sdk/SdkClickHandler.java similarity index 95% rename from Adjust/adjust/src/main/java/com/adjust/sdk/SdkClickHandler.java rename to Adjust/sdk-core/src/main/java/com/adjust/sdk/SdkClickHandler.java index 28983fcde..9b86a03b8 100644 --- a/Adjust/adjust/src/main/java/com/adjust/sdk/SdkClickHandler.java +++ b/Adjust/sdk-core/src/main/java/com/adjust/sdk/SdkClickHandler.java @@ -1,5 +1,8 @@ package com.adjust.sdk; +import com.adjust.sdk.scheduler.SingleThreadCachedScheduler; +import com.adjust.sdk.scheduler.ThreadScheduler; + import org.json.JSONArray; import org.json.JSONException; @@ -8,7 +11,6 @@ import java.util.List; import java.util.ArrayList; -import java.util.concurrent.TimeUnit; import java.lang.ref.WeakReference; import java.net.SocketTimeoutException; @@ -69,7 +71,7 @@ public class SdkClickHandler implements ISdkClickHandler { /** * Custom actions scheduled executor. */ - private CustomScheduledExecutor scheduledExecutor; + private ThreadScheduler scheduler; /** * ActivityHandler instance. @@ -87,7 +89,7 @@ public SdkClickHandler(final IActivityHandler activityHandler, final boolean sta logger = AdjustFactory.getLogger(); backoffStrategy = AdjustFactory.getSdkClickBackoffStrategy(); - scheduledExecutor = new CustomScheduledExecutor(SCHEDULED_EXECUTOR_SOURCE, false); + scheduler = new SingleThreadCachedScheduler("SdkClickHandler"); } /** @@ -124,7 +126,7 @@ public void resumeSending() { */ @Override public void sendSdkClick(final ActivityPackage sdkClick) { - scheduledExecutor.submit(new Runnable() { + scheduler.submit(new Runnable() { @Override public void run() { packageQueue.add(sdkClick); @@ -142,7 +144,7 @@ public void run() { */ @Override public void sendReftagReferrers() { - scheduledExecutor.submit(new Runnable() { + scheduler.submit(new Runnable() { @Override public void run() { IActivityHandler activityHandler = activityHandlerWeakRef.get(); @@ -198,12 +200,8 @@ public void run() { public void teardown() { logger.verbose("SdkClickHandler teardown"); - if (scheduledExecutor != null) { - try { - scheduledExecutor.shutdownNow(); - } catch (SecurityException e) { - - } + if (scheduler != null) { + scheduler.teardown(); } if (packageQueue != null) { @@ -217,14 +215,14 @@ public void teardown() { logger = null; packageQueue = null; backoffStrategy = null; - scheduledExecutor = null; + scheduler = null; } /** * Send next sdk_click package from the queue. */ private void sendNextSdkClick() { - scheduledExecutor.submit(new Runnable() { + scheduler.submit(new Runnable() { @Override public void run() { sendNextSdkClickI(); @@ -266,7 +264,7 @@ public void run() { logger.verbose("Waiting for %s seconds before retrying sdk_click for the %d time", secondsString, retries); - scheduledExecutor.schedule(runnable, waitTimeMilliSeconds, TimeUnit.MILLISECONDS); + scheduler.schedule(runnable, waitTimeMilliSeconds); } /** diff --git a/Adjust/adjust/src/main/java/com/adjust/sdk/SdkClickResponseData.java b/Adjust/sdk-core/src/main/java/com/adjust/sdk/SdkClickResponseData.java similarity index 100% rename from Adjust/adjust/src/main/java/com/adjust/sdk/SdkClickResponseData.java rename to Adjust/sdk-core/src/main/java/com/adjust/sdk/SdkClickResponseData.java diff --git a/Adjust/adjust/src/main/java/com/adjust/sdk/SessionParameters.java b/Adjust/sdk-core/src/main/java/com/adjust/sdk/SessionParameters.java similarity index 100% rename from Adjust/adjust/src/main/java/com/adjust/sdk/SessionParameters.java rename to Adjust/sdk-core/src/main/java/com/adjust/sdk/SessionParameters.java diff --git a/Adjust/adjust/src/main/java/com/adjust/sdk/SessionResponseData.java b/Adjust/sdk-core/src/main/java/com/adjust/sdk/SessionResponseData.java similarity index 100% rename from Adjust/adjust/src/main/java/com/adjust/sdk/SessionResponseData.java rename to Adjust/sdk-core/src/main/java/com/adjust/sdk/SessionResponseData.java diff --git a/Adjust/adjust/src/main/java/com/adjust/sdk/SharedPreferencesManager.java b/Adjust/sdk-core/src/main/java/com/adjust/sdk/SharedPreferencesManager.java similarity index 100% rename from Adjust/adjust/src/main/java/com/adjust/sdk/SharedPreferencesManager.java rename to Adjust/sdk-core/src/main/java/com/adjust/sdk/SharedPreferencesManager.java diff --git a/Adjust/adjust/src/main/java/com/adjust/sdk/TrackingState.java b/Adjust/sdk-core/src/main/java/com/adjust/sdk/TrackingState.java similarity index 100% rename from Adjust/adjust/src/main/java/com/adjust/sdk/TrackingState.java rename to Adjust/sdk-core/src/main/java/com/adjust/sdk/TrackingState.java diff --git a/Adjust/adjust/src/main/java/com/adjust/sdk/Util.java b/Adjust/sdk-core/src/main/java/com/adjust/sdk/Util.java similarity index 96% rename from Adjust/adjust/src/main/java/com/adjust/sdk/Util.java rename to Adjust/sdk-core/src/main/java/com/adjust/sdk/Util.java index 8ccd054b7..ff50fb37d 100644 --- a/Adjust/adjust/src/main/java/com/adjust/sdk/Util.java +++ b/Adjust/sdk-core/src/main/java/com/adjust/sdk/Util.java @@ -15,6 +15,7 @@ import android.content.res.Configuration; import android.net.ConnectivityManager; import android.net.NetworkInfo; +import android.net.Uri; import android.os.AsyncTask; import android.os.Build; import android.os.LocaleList; @@ -223,8 +224,13 @@ public static void writeObject(T object, Context context, String filename, S } public static boolean checkPermission(Context context, String permission) { - int result = context.checkCallingOrSelfPermission(permission); - return result == PackageManager.PERMISSION_GRANTED; + try { + int result = context.checkCallingOrSelfPermission(permission); + return result == PackageManager.PERMISSION_GRANTED; + } catch (Exception e) { + getLogger().debug("Unable to check permission '%s' with message (%s)", permission, e.getMessage()); + return false; + } } public static String readStringField(ObjectInputStream.GetField fields, String name, String defaultValue) { @@ -612,4 +618,23 @@ public static String getSdkPrefixPlatform(final String clientSdk) { return splitted[0]; } + + public static boolean isUrlFilteredOut(Uri url) { + if (url == null) { + return true; + } + + String urlString = url.toString(); + + if (urlString == null || urlString.length() == 0) { + return true; + } + + // Url with FB credentials to be filtered out + if (urlString.matches(Constants.FB_AUTH_REGEX)) { + return true; + } + + return false; + } } \ No newline at end of file diff --git a/Adjust/adjust/src/main/java/com/adjust/sdk/UtilNetworking.java b/Adjust/sdk-core/src/main/java/com/adjust/sdk/UtilNetworking.java similarity index 100% rename from Adjust/adjust/src/main/java/com/adjust/sdk/UtilNetworking.java rename to Adjust/sdk-core/src/main/java/com/adjust/sdk/UtilNetworking.java diff --git a/Adjust/sdk-core/src/main/java/com/adjust/sdk/scheduler/FutureScheduler.java b/Adjust/sdk-core/src/main/java/com/adjust/sdk/scheduler/FutureScheduler.java new file mode 100644 index 000000000..357bf6f45 --- /dev/null +++ b/Adjust/sdk-core/src/main/java/com/adjust/sdk/scheduler/FutureScheduler.java @@ -0,0 +1,14 @@ +package com.adjust.sdk.scheduler; + +import java.util.concurrent.ScheduledFuture; + +/** + * Created by nonelse on 30.05.2018 + */ +public interface FutureScheduler { + ScheduledFuture scheduleFuture(Runnable command, long millisecondDelay); + ScheduledFuture scheduleFutureWithFixedDelay(Runnable command, + long initialMillisecondDelay, + long millisecondDelay); + void teardown(); +} diff --git a/Adjust/sdk-core/src/main/java/com/adjust/sdk/scheduler/RunnableWrapper.java b/Adjust/sdk-core/src/main/java/com/adjust/sdk/scheduler/RunnableWrapper.java new file mode 100644 index 000000000..5a715d96b --- /dev/null +++ b/Adjust/sdk-core/src/main/java/com/adjust/sdk/scheduler/RunnableWrapper.java @@ -0,0 +1,21 @@ +package com.adjust.sdk.scheduler; + +import com.adjust.sdk.AdjustFactory; + +public class RunnableWrapper implements Runnable { + private Runnable runnable; + + RunnableWrapper(Runnable runnable) { + this.runnable = runnable; + } + + @Override + public void run() { + try { + runnable.run(); + } catch (Throwable t) { + AdjustFactory.getLogger().error("Runnable error [%s] of type [%s]", + t.getMessage(), t.getClass().getCanonicalName()); + } + } +} diff --git a/Adjust/sdk-core/src/main/java/com/adjust/sdk/scheduler/SingleThreadCachedScheduler.java b/Adjust/sdk-core/src/main/java/com/adjust/sdk/scheduler/SingleThreadCachedScheduler.java new file mode 100644 index 000000000..33a732d72 --- /dev/null +++ b/Adjust/sdk-core/src/main/java/com/adjust/sdk/scheduler/SingleThreadCachedScheduler.java @@ -0,0 +1,126 @@ +package com.adjust.sdk.scheduler; + +import com.adjust.sdk.AdjustFactory; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.RejectedExecutionHandler; +import java.util.concurrent.SynchronousQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + +public class SingleThreadCachedScheduler implements ThreadScheduler { + private final List queue; + private boolean isThreadProcessing; + private boolean isTeardown; + private ThreadPoolExecutor threadPoolExecutor; + + public SingleThreadCachedScheduler(final String source) { + this.queue = new ArrayList<>(); + isThreadProcessing = false; + isTeardown = false; + + // Same configuration as Executors.newCachedThreadPool(). + threadPoolExecutor = new ThreadPoolExecutor( + 0, Integer.MAX_VALUE, + 60L, TimeUnit.SECONDS, + new SynchronousQueue(), + new ThreadFactoryWrapper(source), + new RejectedExecutionHandler() { // Logs rejected runnables rejected from the entering the pool + @Override + public void rejectedExecution(Runnable runnable, ThreadPoolExecutor executor) { + AdjustFactory.getLogger().warn("Runnable [%s] rejected from [%s] ", + runnable.toString(), source); + } + } + ); + } + + @Override + public void submit(Runnable task) { + synchronized (queue) { + if (isTeardown) { + return; + } + if (!isThreadProcessing) { + isThreadProcessing = true; + processQueue(task); + } + else { + queue.add(task); + } + } + } + + @Override + public void schedule(final Runnable task, final long millisecondsDelay) { + synchronized (queue) { + if (isTeardown) { + return; + } + + threadPoolExecutor.submit(new Runnable() { + @Override + public void run() { + try { + Thread.sleep(millisecondsDelay); + } catch (InterruptedException e) { + AdjustFactory.getLogger().warn("Sleep delay exception: %s", + e.getMessage()); + } + + submit(task); + } + }); + } + } + + private void processQueue(final Runnable firstRunnable) { + threadPoolExecutor.submit(new Runnable() { + @Override + public void run() { + // Execute the first task. + tryExecuteRunnable(firstRunnable); + + Runnable runnable; + // Process all available items in the queue. + while (true) { + synchronized (queue) { + // Possible teardown happened meanwhile. + if (isTeardown) { + return; + } + + if (queue.isEmpty()) { + isThreadProcessing = false; + break; + } + runnable = queue.get(0); + queue.remove(0); + } + tryExecuteRunnable(runnable); + } + } + }); + } + + private void tryExecuteRunnable(Runnable runnable) { + try { + if (isTeardown) { + return; + } + runnable.run(); + } catch (Throwable t) { + AdjustFactory.getLogger().warn("Execution failed: %s", t.getMessage()); + } + } + + @Override + public void teardown() { + synchronized (queue) { + isTeardown = true; + queue.clear(); + threadPoolExecutor.shutdown(); + } + } +} diff --git a/Adjust/sdk-core/src/main/java/com/adjust/sdk/scheduler/SingleThreadFutureScheduler.java b/Adjust/sdk-core/src/main/java/com/adjust/sdk/scheduler/SingleThreadFutureScheduler.java new file mode 100644 index 000000000..2d20bac0e --- /dev/null +++ b/Adjust/sdk-core/src/main/java/com/adjust/sdk/scheduler/SingleThreadFutureScheduler.java @@ -0,0 +1,47 @@ +package com.adjust.sdk.scheduler; + +import com.adjust.sdk.AdjustFactory; + +import java.util.concurrent.RejectedExecutionHandler; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.ScheduledThreadPoolExecutor; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + +public class SingleThreadFutureScheduler implements FutureScheduler { + private ScheduledThreadPoolExecutor scheduledThreadPoolExecutor; + + public SingleThreadFutureScheduler(final String source, boolean doKeepAlive) { + this.scheduledThreadPoolExecutor = new ScheduledThreadPoolExecutor( + 1, + new ThreadFactoryWrapper(source), + new RejectedExecutionHandler() { // Logs rejected runnables rejected from the entering the pool + @Override + public void rejectedExecution(Runnable runnable, ThreadPoolExecutor executor) { + AdjustFactory.getLogger().warn("Runnable [%s] rejected from [%s] ", + runnable.toString(), source); + } + } + ); + + if (!doKeepAlive) { + scheduledThreadPoolExecutor.setKeepAliveTime(10L, TimeUnit.MILLISECONDS); + scheduledThreadPoolExecutor.allowCoreThreadTimeOut(true); + } + } + + @Override + public ScheduledFuture scheduleFuture(Runnable command, long millisecondDelay) { + return scheduledThreadPoolExecutor.schedule(new RunnableWrapper(command), millisecondDelay, TimeUnit.MILLISECONDS); + } + + @Override + public ScheduledFuture scheduleFutureWithFixedDelay(Runnable command, long initialMillisecondDelay, long millisecondDelay) { + return scheduledThreadPoolExecutor.scheduleWithFixedDelay(new RunnableWrapper(command), initialMillisecondDelay, millisecondDelay, TimeUnit.MILLISECONDS); + } + + @Override + public void teardown() { + scheduledThreadPoolExecutor.shutdownNow(); + } +} diff --git a/Adjust/sdk-core/src/main/java/com/adjust/sdk/scheduler/ThreadExecutor.java b/Adjust/sdk-core/src/main/java/com/adjust/sdk/scheduler/ThreadExecutor.java new file mode 100644 index 000000000..b7e46206a --- /dev/null +++ b/Adjust/sdk-core/src/main/java/com/adjust/sdk/scheduler/ThreadExecutor.java @@ -0,0 +1,13 @@ +package com.adjust.sdk.scheduler; + +import java.util.concurrent.Callable; +import java.util.concurrent.Future; + +/** + * Created by nonelse on 12.09.17. + */ + +public interface ThreadExecutor { + void submit(Runnable task); + void teardown(); +} diff --git a/Adjust/sdk-core/src/main/java/com/adjust/sdk/scheduler/ThreadFactoryWrapper.java b/Adjust/sdk-core/src/main/java/com/adjust/sdk/scheduler/ThreadFactoryWrapper.java new file mode 100644 index 000000000..c534092df --- /dev/null +++ b/Adjust/sdk-core/src/main/java/com/adjust/sdk/scheduler/ThreadFactoryWrapper.java @@ -0,0 +1,36 @@ +package com.adjust.sdk.scheduler; + +import android.os.Process; + +import com.adjust.sdk.AdjustFactory; +import com.adjust.sdk.Constants; + +import java.util.concurrent.Executors; +import java.util.concurrent.ThreadFactory; + +public class ThreadFactoryWrapper implements ThreadFactory { + private String source; + + public ThreadFactoryWrapper(String source) { + this.source = source; + } + + @Override + public Thread newThread(Runnable runnable) { + Thread thread = Executors.defaultThreadFactory().newThread(runnable); + + thread.setPriority(Process.THREAD_PRIORITY_BACKGROUND + Process.THREAD_PRIORITY_MORE_FAVORABLE); + thread.setName(Constants.THREAD_PREFIX + thread.getName() + "-" + source); + thread.setDaemon(true); + + thread.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() { + @Override + public void uncaughtException(Thread th, Throwable tr) { + AdjustFactory.getLogger().error("Thread [%s] with error [%s]", + th.getName(), tr.getMessage()); + } + }); + + return thread; + } +} diff --git a/Adjust/sdk-core/src/main/java/com/adjust/sdk/scheduler/ThreadScheduler.java b/Adjust/sdk-core/src/main/java/com/adjust/sdk/scheduler/ThreadScheduler.java new file mode 100644 index 000000000..f8e059767 --- /dev/null +++ b/Adjust/sdk-core/src/main/java/com/adjust/sdk/scheduler/ThreadScheduler.java @@ -0,0 +1,5 @@ +package com.adjust.sdk.scheduler; + +public interface ThreadScheduler extends ThreadExecutor { + void schedule(Runnable task, long millisecondsDelay); +} diff --git a/Adjust/adjust/src/main/java/com/adjust/sdk/TimerCycle.java b/Adjust/sdk-core/src/main/java/com/adjust/sdk/scheduler/TimerCycle.java similarity index 82% rename from Adjust/adjust/src/main/java/com/adjust/sdk/TimerCycle.java rename to Adjust/sdk-core/src/main/java/com/adjust/sdk/scheduler/TimerCycle.java index 23268f013..9d23dfb2a 100644 --- a/Adjust/adjust/src/main/java/com/adjust/sdk/TimerCycle.java +++ b/Adjust/sdk-core/src/main/java/com/adjust/sdk/scheduler/TimerCycle.java @@ -1,6 +1,9 @@ -package com.adjust.sdk; +package com.adjust.sdk.scheduler; + +import com.adjust.sdk.AdjustFactory; +import com.adjust.sdk.ILogger; +import com.adjust.sdk.Util; -import java.lang.ref.WeakReference; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; @@ -8,7 +11,7 @@ * Created by pfms on 08/05/15. */ public class TimerCycle { - private CustomScheduledExecutor executor; + private FutureScheduler scheduler; private ScheduledFuture waitingTask; private String name; @@ -19,7 +22,7 @@ public class TimerCycle { private ILogger logger; public TimerCycle(Runnable command, long initialDelay, long cycleDelay, String name) { - this.executor = new CustomScheduledExecutor(name, true); + this.scheduler = new SingleThreadFutureScheduler(name, true); this.name = name; this.command = command; @@ -43,13 +46,13 @@ public void start() { logger.verbose("%s starting", name); - waitingTask = executor.scheduleWithFixedDelay(new Runnable() { + waitingTask = scheduler.scheduleFutureWithFixedDelay(new Runnable() { @Override public void run() { logger.verbose("%s fired", name); command.run(); } - }, initialDelay, cycleDelay, TimeUnit.MILLISECONDS); + }, initialDelay, cycleDelay); isPaused = false; } @@ -84,13 +87,10 @@ private void cancel(boolean mayInterruptIfRunning) { public void teardown() { cancel(true); - if (executor != null) { - try { - executor.shutdownNow(); - } catch (SecurityException ignored) { - } + if (scheduler != null) { + scheduler.teardown(); } - executor = null; + scheduler = null; } } diff --git a/Adjust/adjust/src/main/java/com/adjust/sdk/TimerOnce.java b/Adjust/sdk-core/src/main/java/com/adjust/sdk/scheduler/TimerOnce.java similarity index 76% rename from Adjust/adjust/src/main/java/com/adjust/sdk/TimerOnce.java rename to Adjust/sdk-core/src/main/java/com/adjust/sdk/scheduler/TimerOnce.java index a5ec001c6..959cad751 100644 --- a/Adjust/adjust/src/main/java/com/adjust/sdk/TimerOnce.java +++ b/Adjust/sdk-core/src/main/java/com/adjust/sdk/scheduler/TimerOnce.java @@ -1,6 +1,9 @@ -package com.adjust.sdk; +package com.adjust.sdk.scheduler; + +import com.adjust.sdk.AdjustFactory; +import com.adjust.sdk.ILogger; +import com.adjust.sdk.Util; -import java.lang.ref.WeakReference; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; @@ -8,7 +11,7 @@ * Created by pfms on 08/05/15. */ public class TimerOnce { - private CustomScheduledExecutor executor; + private FutureScheduler scheduler; private ScheduledFuture waitingTask; private String name; @@ -17,7 +20,7 @@ public class TimerOnce { public TimerOnce(Runnable command, String name) { this.name = name; - this.executor = new CustomScheduledExecutor(name, true); + this.scheduler = new SingleThreadFutureScheduler(name, true); this.command = command; this.logger = AdjustFactory.getLogger(); } @@ -30,14 +33,14 @@ public void startIn(long fireIn) { logger.verbose("%s starting. Launching in %s seconds", name, fireInSeconds); - waitingTask = executor.schedule(new Runnable() { + waitingTask = scheduler.scheduleFuture(new Runnable() { @Override public void run() { logger.verbose("%s fired", name); command.run(); waitingTask = null; } - }, fireIn, TimeUnit.MILLISECONDS); + }, fireIn); } public long getFireIn() { @@ -63,6 +66,10 @@ public void cancel() { public void teardown() { cancel(true); - executor = null; + if (scheduler != null) { + scheduler.teardown(); + } + + scheduler = null; } } diff --git a/Adjust/adjust/src/main/res/values/strings.xml b/Adjust/sdk-core/src/main/res/values/strings.xml similarity index 100% rename from Adjust/adjust/src/main/res/values/strings.xml rename to Adjust/sdk-core/src/main/res/values/strings.xml diff --git a/Adjust/testapp-webbridge/.gitignore b/Adjust/sdk-plugin-criteo/.gitignore similarity index 100% rename from Adjust/testapp-webbridge/.gitignore rename to Adjust/sdk-plugin-criteo/.gitignore diff --git a/Adjust/sdk-plugin-criteo/build.gradle b/Adjust/sdk-plugin-criteo/build.gradle new file mode 100644 index 000000000..1faf46966 --- /dev/null +++ b/Adjust/sdk-plugin-criteo/build.gradle @@ -0,0 +1,177 @@ +apply plugin: 'com.android.library' +apply plugin: 'maven-publish' +apply plugin: 'signing' + +repositories { + maven { + url "https://oss.sonatype.org/content/repositories/staging/" + } +} + +android { + compileSdkVersion rootProject.ext.coreCompileSdkVersion + + defaultConfig { + minSdkVersion rootProject.ext.coreMinSdkVersion + targetSdkVersion rootProject.ext.coreTargetSdkVersion + versionName rootProject.ext.coreVersionName + versionCode rootProject.ext.defaultVersionCode + } +} + +dependencies { + implementation fileTree(dir: 'libs', include: ['*.jar']) + + // Add SDK via module. + implementation project(':sdk-core') + // Add SDK via Maven. + // implementation 'com.adjust.sdk:adjust-android:4.16.0' +} + +task adjustCriteoAndroidJar(type: Jar) { + dependsOn 'compileReleaseJavaWithJavac' + from('build/intermediates/javac/release/compileReleaseJavaWithJavac/classes/') + archiveName "${project.name}.jar" +} + +task androidJavadocs(type: Javadoc) { + source = android.sourceSets.main.java.srcDirs + classpath += project.files(android.getBootClasspath().join(File.pathSeparator)) + // JDK 1.8 is more strict then 1.7. Have JDK 1.8 behave like 1.7 for javadoc generation. + if (org.gradle.internal.jvm.Jvm.current().getJavaVersion() == JavaVersion.VERSION_1_8) { + options.addStringOption('Xdoclint:none', '-quiet') + } +} + +task adjustCriteoAndroidJavadocsJar(type: Jar) { + dependsOn 'androidJavadocs' + classifier = 'javadoc' + from androidJavadocs.destinationDir +} + +task adjustCriteoAndroidSourcesJar(type: Jar) { + classifier = 'sources' + from android.sourceSets.main.java.srcDirs +} + +artifacts { + archives adjustCriteoAndroidJar + archives adjustCriteoAndroidJavadocsJar + archives adjustCriteoAndroidSourcesJar +} + +publishing { + publications { + mavenAndroidCriteo(MavenPublication) { + customizePom(pom) + groupId rootProject.ext.adjustGroupId + artifactId 'adjust-android-criteo' + version rootProject.ext.coreVersionName + + // Create the signed POM artifact. + pom.withXml { + def pomFile = file("${project.buildDir}/generated-pom.xml") + writeTo(pomFile) + def pomAscFile = signing.sign(pomFile).signatureFiles[0] + artifact(pomAscFile) { + classifier = null + extension = 'pom.asc' + } + } + + // Create the signed artifacts. + project.tasks.signArchives.signatureFiles.each { + // exclude "usual" archive artifact .aar + def signFileName = it.toString() + if (signFileName.contains('aar')) { + return + } + // Create a Maven artifact for each asc signature + artifact(it) { + if (signFileName.contains('-sources')) { + classifier = 'sources' + extension = 'jar.asc' + } else if (signFileName.contains('-javadoc')) { + classifier = 'javadoc' + extension = 'jar.asc' + } else { + classifier = null + extension = 'jar.asc' + } + } + } + + artifact adjustCriteoAndroidJar + artifact adjustCriteoAndroidJavadocsJar + artifact adjustCriteoAndroidSourcesJar + } + } + + repositories { + maven { + url "https://oss.sonatype.org/service/local/staging/deploy/maven2" + if (project.hasProperty("sonatypeUsername")) { + credentials { + username sonatypeUsername + password sonatypePassword + } + } + } + } +} + +def customizePom(pom) { + pom.withXml { + def root = asNode() + + // Add all items necessary for maven central publication + root.children().last() + { + resolveStrategy = Closure.DELEGATE_FIRST + description 'The Criteo plugin for Adjust SDK for Android' + name 'Adjust Android SDK Criteo plugin' + url 'https://github.com/adjust/android_sdk' + + organization { + name 'adjust GmbH' + url 'http://www.adjust.com' + } + licenses { + license { + name 'MIT License' + url 'http://www.opensource.org/licenses/mit-license.php' + } + } + scm { + url 'git@github.com:adjust/android_sdk.git' + connection 'scm:git:git@github.com:adjust/android_sdk.git' + developerConnection 'scm:git:git@github.com:adjust/android_sdk.git' + } + developers { + developer { + name 'Pedro Silva' + email 'pedro@adjust.com' + } + developer { + name 'Ugljesa Erceg' + email 'ugljesa@adjust.com' + } + } + } + } +} + +model { + tasks.generatePomFileForMavenAndroidCriteoPublication { + destination = file("${project.buildDir}/generated-pom.xml") + } + tasks.publishMavenAndroidCriteoPublicationToMavenLocal { + dependsOn project.tasks.signArchives + } + tasks.publishMavenAndroidCriteoPublicationToMavenRepository { + dependsOn project.tasks.signArchives + } +} + +signing { + sign configurations.archives +} diff --git a/Adjust/webbridge/src/main/AndroidManifest.xml b/Adjust/sdk-plugin-criteo/src/main/AndroidManifest.xml similarity index 63% rename from Adjust/webbridge/src/main/AndroidManifest.xml rename to Adjust/sdk-plugin-criteo/src/main/AndroidManifest.xml index daa443752..f0fbb9deb 100644 --- a/Adjust/webbridge/src/main/AndroidManifest.xml +++ b/Adjust/sdk-plugin-criteo/src/main/AndroidManifest.xml @@ -1,2 +1,2 @@ + package="com.adjust.sdk.criteo" /> diff --git a/Adjust/sdk-plugin-criteo/src/main/java/com/adjust/sdk/criteo/AdjustCriteo.java b/Adjust/sdk-plugin-criteo/src/main/java/com/adjust/sdk/criteo/AdjustCriteo.java new file mode 100644 index 000000000..03b8f7fa1 --- /dev/null +++ b/Adjust/sdk-plugin-criteo/src/main/java/com/adjust/sdk/criteo/AdjustCriteo.java @@ -0,0 +1,236 @@ +package com.adjust.sdk.criteo; + +import android.net.Uri; + +import com.adjust.sdk.AdjustEvent; +import com.adjust.sdk.AdjustFactory; +import com.adjust.sdk.ILogger; + +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; + +/** + * Created by pfms on 24/02/15. + */ +public class AdjustCriteo { + private static ILogger logger = AdjustFactory.getLogger(); + private static int MAX_VIEW_LISTING_PRODUCTS = 3; + private static String hashEmailInternal; + private static String checkInDateInternal; + private static String checkOutDateInternal; + private static String partnerIdInternal; + private static String userSegmentInternal; + private static String customerIdInternal; + + public static void injectViewListingIntoEvent(AdjustEvent event, List productIds) { + String jsonProducts = createCriteoVLFromProducts(productIds); + event.addPartnerParameter("criteo_p", jsonProducts); + + injectOptionalParams(event); + } + + public static void injectViewProductIntoEvent(AdjustEvent event, String productId) { + event.addPartnerParameter("criteo_p", productId); + + injectOptionalParams(event); + } + + public static void injectCartIntoEvent(AdjustEvent event, List products) { + String jsonProducts = createCriteoVBFromProducts(products); + + event.addPartnerParameter("criteo_p", jsonProducts); + + injectOptionalParams(event); + } + + public static void injectTransactionConfirmedIntoEvent(AdjustEvent event, List products, String transactionId, String newCustomer) { + String jsonProducts = createCriteoVBFromProducts(products); + + event.addPartnerParameter("transaction_id", transactionId); + event.addPartnerParameter("criteo_p", jsonProducts); + event.addPartnerParameter("new_customer", newCustomer); + + injectOptionalParams(event); + } + + public static void injectUserLevelIntoEvent(AdjustEvent event, long uiLevel) { + event.addPartnerParameter("ui_level", String.valueOf(uiLevel)); + + injectOptionalParams(event); + } + + public static void injectUserStatusIntoEvent(AdjustEvent event, String uiStatus) { + event.addPartnerParameter("ui_status", uiStatus); + + injectOptionalParams(event); + } + + public static void injectAchievementUnlockedIntoEvent(AdjustEvent event, String uiAchievement) { + event.addPartnerParameter("ui_achievmnt", uiAchievement); + + injectOptionalParams(event); + } + + public static void injectCustomEventIntoEvent(AdjustEvent event, String uiData) { + event.addPartnerParameter("ui_data", uiData); + + injectOptionalParams(event); + } + + public static void injectCustomEvent2IntoEvent(AdjustEvent event, String uiData2, long uiData3) { + event.addPartnerParameter("ui_data2", uiData2); + event.addPartnerParameter("ui_data3", String.valueOf(uiData3)); + + injectOptionalParams(event); + } + + public static void injectHashedEmailIntoCriteoEvents(String hashEmail) { + hashEmailInternal = hashEmail; + } + + public static void injectViewSearchDatesIntoCriteoEvents(String checkInDate, String checkOutDate) { + checkInDateInternal = checkInDate; + checkOutDateInternal = checkOutDate; + } + + public static void injectPartnerIdIntoCriteoEvents(String partnerId) { + partnerIdInternal = partnerId; + } + + public static void injectUserSegmentIntoCriteoEvents(String userSegment) { + userSegmentInternal = userSegment; + } + + public static void injectCustomerIdIntoCriteoEvents(String customerId) { + customerIdInternal = customerId; + } + + public static void injectDeeplinkIntoEvent(AdjustEvent event, Uri url) { + if (url == null) { + return; + } + + event.addPartnerParameter("criteo_deeplink", url.toString()); + + injectOptionalParams(event); + } + + private static void injectOptionalParams(AdjustEvent event) { + injectHashEmail(event); + injectSearchDates(event); + injectPartnerId(event); + injectUserSegment(event); + injectCustomerId(event); + } + + private static void injectHashEmail(AdjustEvent event) { + if (hashEmailInternal == null || hashEmailInternal.isEmpty()) { + return; + } + + event.addPartnerParameter("criteo_email_hash", hashEmailInternal); + } + + private static void injectSearchDates(AdjustEvent event) { + if (checkInDateInternal == null || checkInDateInternal.isEmpty() || + checkOutDateInternal == null || checkOutDateInternal.isEmpty()) { + return; + } + + event.addPartnerParameter("din", checkInDateInternal); + event.addPartnerParameter("dout", checkOutDateInternal); + } + + private static void injectPartnerId(AdjustEvent event) { + if (partnerIdInternal == null || partnerIdInternal.isEmpty()) { + return; + } + + event.addPartnerParameter("criteo_partner_id", partnerIdInternal); + } + + private static void injectUserSegment(AdjustEvent event) { + if (userSegmentInternal == null || userSegmentInternal.isEmpty()) { + return; + } + + event.addPartnerParameter("user_segment", userSegmentInternal); + } + + private static void injectCustomerId(AdjustEvent event) { + if (customerIdInternal == null || customerIdInternal.isEmpty()) { + return; + } + event.addPartnerParameter("customer_id", customerIdInternal); + } + + private static String createCriteoVLFromProducts(List productIds) { + if (productIds == null) { + logger.warn("Criteo View Listing product ids list is null. It will sent as empty."); + productIds = new ArrayList(); + } + StringBuffer criteoVLValue = new StringBuffer("["); + int productIdsSize = productIds.size(); + + if (productIdsSize > MAX_VIEW_LISTING_PRODUCTS) { + logger.warn("Criteo View Listing should only have at most 3 product ids. The rest will be discarded."); + } + for (int i = 0; i < productIdsSize; ) { + String productID = productIds.get(i); + String productString = String.format(Locale.US, "\"%s\"", productID); + criteoVLValue.append(productString); + + i++; + + if (i == productIdsSize || i >= MAX_VIEW_LISTING_PRODUCTS) { + break; + } + + criteoVLValue.append(","); + } + criteoVLValue.append("]"); + String result = null; + try { + result = URLEncoder.encode(criteoVLValue.toString(),"UTF-8"); + } catch (UnsupportedEncodingException e) { + logger.error("error converting criteo product ids (%s)", e.getMessage()); + } + return result; + } + + private static String createCriteoVBFromProducts(List products) { + if (products == null) { + logger.warn("Criteo Event product list is empty. It will sent as empty."); + products = new ArrayList(); + } + StringBuffer criteoVBValue = new StringBuffer("["); + int productsSize = products.size(); + for (int i = 0; i < productsSize; ) { + CriteoProduct criteoProduct = products.get(i); + String productString = String.format(Locale.US, "{\"i\":\"%s\",\"pr\":%f,\"q\":%d}", + criteoProduct.productID, + criteoProduct.price, + criteoProduct.quantity); + criteoVBValue.append(productString); + + i++; + + if (i == productsSize) { + break; + } + + criteoVBValue.append(","); + } + criteoVBValue.append("]"); + String result = null; + try { + result = URLEncoder.encode(criteoVBValue.toString(),"UTF-8"); + } catch (UnsupportedEncodingException e) { + logger.error("error converting criteo products (%s)", e.getMessage()); + } + return result; + } +} diff --git a/Adjust/sdk-plugin-criteo/src/main/java/com/adjust/sdk/criteo/CriteoProduct.java b/Adjust/sdk-plugin-criteo/src/main/java/com/adjust/sdk/criteo/CriteoProduct.java new file mode 100644 index 000000000..519cc6826 --- /dev/null +++ b/Adjust/sdk-plugin-criteo/src/main/java/com/adjust/sdk/criteo/CriteoProduct.java @@ -0,0 +1,16 @@ +package com.adjust.sdk.criteo; + +/** + * Created by pfms on 24/02/15. + */ +public class CriteoProduct { + float price; + int quantity; + String productID; + + public CriteoProduct(float price, int quantity, String productID) { + this.price = price; + this.quantity = quantity; + this.productID = productID; + } +} diff --git a/Adjust/testapp/.gitignore b/Adjust/sdk-plugin-imei/.gitignore similarity index 100% rename from Adjust/testapp/.gitignore rename to Adjust/sdk-plugin-imei/.gitignore diff --git a/Adjust/sdk-plugin-imei/build.gradle b/Adjust/sdk-plugin-imei/build.gradle new file mode 100644 index 000000000..1952a2b7a --- /dev/null +++ b/Adjust/sdk-plugin-imei/build.gradle @@ -0,0 +1,182 @@ +apply plugin: 'com.android.library' +apply plugin: 'maven-publish' +apply plugin: 'signing' + +repositories { + maven { + url "https://oss.sonatype.org/content/repositories/staging/" + } +} + +android { + compileSdkVersion rootProject.ext.coreCompileSdkVersion + + defaultConfig { + minSdkVersion rootProject.ext.coreMinSdkVersion + targetSdkVersion rootProject.ext.coreTargetSdkVersion + versionName rootProject.ext.coreVersionName + versionCode rootProject.ext.defaultVersionCode + } +} + +dependencies { + implementation fileTree(dir: 'libs', include: ['*.jar']) + // Add SDK via module. + implementation project(':sdk-core') + // Add SDK via Maven. + // implementation 'com.adjust.sdk:adjust-android:4.16.0' +} + +task adjustImeiAndroidJar(type: Jar) { + dependsOn 'packageReleaseAssets' + dependsOn 'compileReleaseJavaWithJavac' + + from('build/intermediates/library_assets/release/packageReleaseAssets/out/') { + into('assets') + } + from('build/intermediates/javac/release/compileReleaseJavaWithJavac/classes/') + + archiveName "${project.name}.jar" +} + +task androidJavadocs(type: Javadoc) { + source = android.sourceSets.main.java.srcDirs + classpath += project.files(android.getBootClasspath().join(File.pathSeparator)) + // JDK 1.8 is more strict then 1.7. Have JDK 1.8 behave like 1.7 for javadoc generation. + if (org.gradle.internal.jvm.Jvm.current().getJavaVersion() == JavaVersion.VERSION_1_8) { + options.addStringOption('Xdoclint:none', '-quiet') + } +} + +task adjustImeiAndroidJavadocsJar(type: Jar) { + dependsOn 'androidJavadocs' + classifier = 'javadoc' + from androidJavadocs.destinationDir +} + +task adjustImeiAndroidSourcesJar(type: Jar) { + classifier = 'sources' + from android.sourceSets.main.java.srcDirs +} + +artifacts { + archives adjustImeiAndroidJar + archives adjustImeiAndroidJavadocsJar + archives adjustImeiAndroidSourcesJar +} + +publishing { + publications { + mavenAndroidImei(MavenPublication) { + customizePom(pom) + groupId rootProject.ext.adjustGroupId + artifactId 'adjust-android-imei' + version rootProject.ext.coreVersionName + + // Create the sign pom artifact. + pom.withXml { + def pomFile = file("${project.buildDir}/generated-pom.xml") + writeTo(pomFile) + def pomAscFile = signing.sign(pomFile).signatureFiles[0] + artifact(pomAscFile) { + classifier = null + extension = 'pom.asc' + } + } + + // Create the signed artifacts. + project.tasks.signArchives.signatureFiles.each { + // Exclude "usual" archive artifact .aar. + def signFileName = it.toString() + if (signFileName.contains('aar')) { + return + } + // Create a Maven artifact for each asc signature. + artifact(it) { + if (signFileName.contains('-sources')) { + classifier = 'sources' + extension = 'jar.asc' + } else if (signFileName.contains('-javadoc')) { + classifier = 'javadoc' + extension = 'jar.asc' + } else { + classifier = null + extension = 'jar.asc' + } + } + } + + artifact adjustImeiAndroidJar + artifact adjustImeiAndroidJavadocsJar + artifact adjustImeiAndroidSourcesJar + } + } + + repositories { + maven { + url "https://oss.sonatype.org/service/local/staging/deploy/maven2" + if (project.hasProperty("sonatypeUsername")) { + credentials { + username sonatypeUsername + password sonatypePassword + } + } + } + } +} + +def customizePom(pom) { + pom.withXml { + def root = asNode() + + // Add all items necessary for maven central publication. + root.children().last() + { + resolveStrategy = Closure.DELEGATE_FIRST + description 'The Imei plugin for Adjust SDK for Android' + name 'Adjust Android SDK Imei plugin' + url 'https://github.com/adjust/android_sdk' + + organization { + name 'adjust GmbH' + url 'http://www.adjust.com' + } + licenses { + license { + name 'MIT License' + url 'http://www.opensource.org/licenses/mit-license.php' + } + } + scm { + url 'git@github.com:adjust/android_sdk.git' + connection 'scm:git:git@github.com:adjust/android_sdk.git' + developerConnection 'scm:git:git@github.com:adjust/android_sdk.git' + } + developers { + developer { + name 'Pedro Silva' + email 'pedro@adjust.com' + } + developer { + name 'Ugljesa Erceg' + email 'ugljesa@adjust.com' + } + } + } + } +} + +model { + tasks.generatePomFileForMavenAndroidImeiPublication { + destination = file("${project.buildDir}/generated-pom.xml") + } + tasks.publishMavenAndroidImeiPublicationToMavenLocal { + dependsOn project.tasks.signArchives + } + tasks.publishMavenAndroidImeiPublicationToMavenRepository { + dependsOn project.tasks.signArchives + } +} + +signing { + sign configurations.archives +} diff --git a/Adjust/testapp-webbridge/proguard-rules.pro b/Adjust/sdk-plugin-imei/proguard-rules.pro similarity index 100% rename from Adjust/testapp-webbridge/proguard-rules.pro rename to Adjust/sdk-plugin-imei/proguard-rules.pro diff --git a/Adjust/sdk-plugin-imei/src/main/AndroidManifest.xml b/Adjust/sdk-plugin-imei/src/main/AndroidManifest.xml new file mode 100644 index 000000000..8d44fa9ad --- /dev/null +++ b/Adjust/sdk-plugin-imei/src/main/AndroidManifest.xml @@ -0,0 +1,9 @@ + + + + + + + + diff --git a/Adjust/sdk-plugin-imei/src/main/java/com/adjust/sdk/imei/AdjustImei.java b/Adjust/sdk-plugin-imei/src/main/java/com/adjust/sdk/imei/AdjustImei.java new file mode 100644 index 000000000..1dd49eb27 --- /dev/null +++ b/Adjust/sdk-plugin-imei/src/main/java/com/adjust/sdk/imei/AdjustImei.java @@ -0,0 +1,13 @@ +package com.adjust.sdk.imei; + +public class AdjustImei { + static boolean isImeiToBeRead = false; + + public static void readImei() { + AdjustImei.isImeiToBeRead = true; + } + + public static void doNotReadImei() { + AdjustImei.isImeiToBeRead = false; + } +} diff --git a/Adjust/sdk-plugin-imei/src/main/java/com/adjust/sdk/imei/TelephonyIdsUtil.java b/Adjust/sdk-plugin-imei/src/main/java/com/adjust/sdk/imei/TelephonyIdsUtil.java new file mode 100644 index 000000000..ffb6d0018 --- /dev/null +++ b/Adjust/sdk-plugin-imei/src/main/java/com/adjust/sdk/imei/TelephonyIdsUtil.java @@ -0,0 +1,137 @@ +package com.adjust.sdk.imei; + +import android.content.Context; +import android.os.Build; +import android.telephony.TelephonyManager; +import android.text.TextUtils; + +import com.adjust.sdk.ILogger; +import com.adjust.sdk.PackageBuilder; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +class TelephonyIdsUtil { + static void injectImei(Map parameters, Context context, ILogger logger) { + if (!AdjustImei.isImeiToBeRead) { + return; + } + + TelephonyManager telephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); + PackageBuilder.addString(parameters, "imei", getDefaultImei(telephonyManager, logger)); + PackageBuilder.addString(parameters, "meid", getDefaultMeid(telephonyManager, logger)); + PackageBuilder.addString(parameters, "device_id", getDefaultDeviceId(telephonyManager, logger)); + PackageBuilder.addString(parameters, "imeis", getImeis(telephonyManager, logger)); + PackageBuilder.addString(parameters, "meids", getMeids(telephonyManager, logger)); + PackageBuilder.addString(parameters, "device_ids", getDeviceIds(telephonyManager, logger)); + } + + private static String getDeviceIds(TelephonyManager telephonyManager, ILogger logger) { + List telephonyIdList = new ArrayList(); + for (int i = 0; i < 10; i++) { + String telephonyId = getDeviceIdByIndex(telephonyManager, i, logger); + if (!tryAddToStringList(telephonyIdList, telephonyId)) { + break; + } + } + return TextUtils.join(",", telephonyIdList); + } + + // Test difference mentioned here https://stackoverflow.com/a/35343531 + private static String getDefaultDeviceId(TelephonyManager telephonyManager, ILogger logger) { + try { + return telephonyManager.getDeviceId(); + } catch (SecurityException e) { + logger.debug("Couldn't read default Device Id: %s", e.getMessage()); + } + return null; + } + + private static String getDeviceIdByIndex(TelephonyManager telephonyManager, int index, ILogger logger) { + try { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + return telephonyManager.getDeviceId(index); + } + } catch (SecurityException e) { + logger.debug("Couldn't read Device Id in position %d: %s", index, e.getMessage()); + } + return null; + } + + private static String getImeis(TelephonyManager telephonyManager, ILogger logger) { + List imeiList = new ArrayList(); + for (int i = 0; i < 10; i++) { + String imei = getImeiByIndex(telephonyManager, i, logger); + if (!tryAddToStringList(imeiList, imei)) { + break; + } + } + return TextUtils.join(",", imeiList); + } + + private static String getDefaultImei(TelephonyManager telephonyManager, ILogger logger) { + try { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + return telephonyManager.getImei(); + } + } catch (SecurityException e) { + logger.debug("Couldn't read default IMEI: %s", e.getMessage()); + } + return null; + } + + private static String getImeiByIndex(TelephonyManager telephonyManager, int index, ILogger logger) { + try { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + return telephonyManager.getImei(index); + } + } catch (SecurityException e) { + logger.debug("Couldn't read IMEI in position %d: %s", index, e.getMessage()); + } + return null; + } + + public static String getMeids(TelephonyManager telephonyManager, ILogger logger) { + List meidList = new ArrayList(); + for (int i = 0; i < 10; i++) { + String meid = getMeidByIndex(telephonyManager, i, logger); + if (!tryAddToStringList(meidList, meid)) { + break; + } + } + return TextUtils.join(",", meidList); + } + + private static String getDefaultMeid(TelephonyManager telephonyManager, ILogger logger) { + try { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + return telephonyManager.getMeid(); + } + } catch (SecurityException e) { + logger.debug("Couldn't read default MEID: %s", e.getMessage()); + } + return null; + } + + private static String getMeidByIndex(TelephonyManager telephonyManager, int index, ILogger logger) { + try { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + return telephonyManager.getMeid(index); + } + } catch (SecurityException e) { + logger.debug("Couldn't read MEID in position %d: %s", index, e.getMessage()); + } + return null; + } + + private static boolean tryAddToStringList(List list, String value) { + if (value == null) { + return false; + } + if (list.contains(value)) { + return false; + } + return list.add(value); + } +} diff --git a/Adjust/sdk-plugin-imei/src/main/java/com/adjust/sdk/imei/Util.java b/Adjust/sdk-plugin-imei/src/main/java/com/adjust/sdk/imei/Util.java new file mode 100644 index 000000000..3ee3d7a0e --- /dev/null +++ b/Adjust/sdk-plugin-imei/src/main/java/com/adjust/sdk/imei/Util.java @@ -0,0 +1,18 @@ +package com.adjust.sdk.imei; + +import android.content.Context; + +import com.adjust.sdk.ILogger; + +import java.util.HashMap; +import java.util.Map; + +import static com.adjust.sdk.imei.TelephonyIdsUtil.injectImei; + +public class Util { + public static Map getImeiParameters(Context context, ILogger logger) { + Map parameters = new HashMap(); + injectImei(parameters, context, logger); + return parameters; + } +} diff --git a/Adjust/sdk-plugin-imei/src/main/res/values/strings.xml b/Adjust/sdk-plugin-imei/src/main/res/values/strings.xml new file mode 100644 index 000000000..831757748 --- /dev/null +++ b/Adjust/sdk-plugin-imei/src/main/res/values/strings.xml @@ -0,0 +1,3 @@ + + AdjustNonPlay + diff --git a/Adjust/testlibrary/.gitignore b/Adjust/sdk-plugin-play/.gitignore similarity index 100% rename from Adjust/testlibrary/.gitignore rename to Adjust/sdk-plugin-play/.gitignore diff --git a/Adjust/sdk-plugin-play/build.gradle b/Adjust/sdk-plugin-play/build.gradle new file mode 100644 index 000000000..35a0e4975 --- /dev/null +++ b/Adjust/sdk-plugin-play/build.gradle @@ -0,0 +1,20 @@ +apply plugin: 'com.android.library' + +android { + compileSdkVersion 28 + + defaultConfig { + minSdkVersion 14 + targetSdkVersion 28 + versionCode 1 + versionName "1.0" + testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" + } +} + +dependencies { + implementation fileTree(dir: 'libs', include: ['*.jar']) + implementation project(':sdk-core') + implementation 'com.google.android.gms:play-services-analytics:16.0.4' + implementation 'com.android.installreferrer:installreferrer:1.0' +} diff --git a/Adjust/testapp/proguard-rules.pro b/Adjust/sdk-plugin-play/proguard-rules.pro similarity index 100% rename from Adjust/testapp/proguard-rules.pro rename to Adjust/sdk-plugin-play/proguard-rules.pro diff --git a/Adjust/sdk-plugin-play/src/main/AndroidManifest.xml b/Adjust/sdk-plugin-play/src/main/AndroidManifest.xml new file mode 100644 index 000000000..ae7b9bf71 --- /dev/null +++ b/Adjust/sdk-plugin-play/src/main/AndroidManifest.xml @@ -0,0 +1,2 @@ + diff --git a/Adjust/sdk-plugin-play/src/main/java/com/adjust/sdk/play/InstallReferrer.java b/Adjust/sdk-plugin-play/src/main/java/com/adjust/sdk/play/InstallReferrer.java new file mode 100644 index 000000000..ff5408094 --- /dev/null +++ b/Adjust/sdk-plugin-play/src/main/java/com/adjust/sdk/play/InstallReferrer.java @@ -0,0 +1,185 @@ +package com.adjust.sdk.play; + +import android.content.Context; +import android.os.RemoteException; + +import com.adjust.sdk.AdjustFactory; +import com.adjust.sdk.ILogger; + +import com.adjust.sdk.InstallReferrerReadListener; +import com.adjust.sdk.scheduler.TimerOnce; +import com.android.installreferrer.api.InstallReferrerClient; +import com.android.installreferrer.api.InstallReferrerStateListener; +import com.android.installreferrer.api.ReferrerDetails; + +import java.util.concurrent.atomic.AtomicBoolean; + +import static com.adjust.sdk.Constants.ONE_SECOND; + + +public class InstallReferrer implements InstallReferrerStateListener { + private static final int MAX_INSTALL_REFERRER_RETRIES = 2; + private static final int RETRY_WAIT_TIME = ONE_SECOND * 3; + + private InstallReferrerClient client; + private int retryNumber; + + // injected at constructor time and final + private final ILogger logger; + private final Context context; + private final InstallReferrerReadListener referrerCallback; + private final AtomicBoolean hasInstallReferrerBeenRead; + private final TimerOnce retryTimer; + + + public InstallReferrer(Context context, InstallReferrerReadListener referrerCallback, ILogger logger) { + this.context = context; + this.logger = logger; + this.referrerCallback = referrerCallback; + this.hasInstallReferrerBeenRead = new AtomicBoolean(false); + this.retryTimer = new TimerOnce(new Runnable() { + @Override + public void run() { + startConnection(); + } + }, "InstallReferrer"); + + this.retryNumber = 0; + } + + public void startConnection() { + if (!AdjustFactory.getTryInstallReferrer()) { + return; + } + closeReferrerClient(); + + if (hasInstallReferrerBeenRead.get()) { + logger.debug("Install referrer has already been read"); + return; + } + + client = InstallReferrerClient.newBuilder(context).build(); + + client.startConnection(this); + } + + private void closeReferrerClient() { + if (client == null) { + return; + } + + client.endConnection(); + logger.debug("Install Referrer API connection closed"); + + client = null; + } + + /** + * Called to notify that setup is complete. + * + * @param responseCode The response code from {@link InstallReferrerClient.InstallReferrerResponse} which returns the + * status of the setup process. + */ + @Override + public void onInstallReferrerSetupFinished(int responseCode) { + boolean retryAtEnd = false; + switch (responseCode) { + /** Success. */ + case InstallReferrerClient.InstallReferrerResponse.OK: + // Connection established + try { + ReferrerDetails installReferrerDetails = client.getInstallReferrer(); + String installReferrer = installReferrerDetails.getInstallReferrer(); + long referrerClickTimestampSeconds = installReferrerDetails.getReferrerClickTimestampSeconds(); + long installBeginTimestampSeconds = installReferrerDetails.getInstallBeginTimestampSeconds(); + referrerCallback.onInstallReferrerRead(installReferrer, referrerClickTimestampSeconds, installBeginTimestampSeconds); + + hasInstallReferrerBeenRead.set(true); + logger.debug("Install Referrer read successfully. Closing connection"); + } catch (RemoteException e) { + logger.warn("Couldn't get install referrer from client (%s). Retrying...", e.getMessage()); + retryAtEnd = true; + } + break; + /** Install Referrer API not supported by the installed Play Store app. */ + case InstallReferrerClient.InstallReferrerResponse.FEATURE_NOT_SUPPORTED: + // API not available on the current Play Store app + logger.debug("Install Referrer API not supported by the installed Play Store app. Closing connection"); + break; + /** Could not initiate connection to the Install Referrer service. */ + case InstallReferrerClient.InstallReferrerResponse.SERVICE_UNAVAILABLE: + // Connection could not be established + logger.debug("Could not initiate connection to the Install Referrer service. Retrying..."); + retryAtEnd = true; + break; + /** + * Play Store service is not connected now - potentially transient state. + * + *

E.g. Play Store could have been updated in the background while your app was still + * running. So feel free to introduce your retry policy for such use case. It should lead to a + * call to {@link #startConnection(InstallReferrerStateListener)} right after or in some time + * after you received this code. + */ + case InstallReferrerClient.InstallReferrerResponse.SERVICE_DISCONNECTED: + // Connection could not be established + logger.debug("Play Store service is not connected now. Retrying ..."); + retryAtEnd = true; + break; + /** General errors caused by incorrect usage */ + case InstallReferrerClient.InstallReferrerResponse.DEVELOPER_ERROR: + logger.debug("Install Referrer API general errors caused by incorrect usage. Retrying..."); + retryAtEnd = true; + break; + default: + logger.debug("Unexpected response code of install referrer response: %d. Closing connection", responseCode); + break; + } + + if (retryAtEnd) { + retry(); + } else { + closeReferrerClient(); + } + } + + /** + * Called to notify that connection to install referrer service was lost. + * + *

Note: This does not remove install referrer service connection itself - this binding to the + * service will remain active, and you will receive a call to {@link + * #onInstallReferrerSetupFinished(int)} when install referrer service is next running and setup + * is complete. + */ + @Override + public void onInstallReferrerServiceDisconnected() { + // Try to restart the connection on the next request to + // Google Play by calling the startConnection() method. + logger.debug("Connection to install referrer service was lost. Retrying ..."); + retry(); + } + + private void retry() { + if (hasInstallReferrerBeenRead.get()) { + logger.debug("Install referrer has already been read"); + closeReferrerClient(); + return; + } + + // Check increase retry counter + if (retryNumber + 1 > MAX_INSTALL_REFERRER_RETRIES) { + logger.debug("Limit number of retry of %d for install referrer surpassed", MAX_INSTALL_REFERRER_RETRIES); + return; + } + + long firingIn = retryTimer.getFireIn(); + if (firingIn > 0) { + logger.debug("Already waiting to retry to read install referrer in %d milliseconds", firingIn); + return; + } + + retryNumber++; + logger.debug("Retry number %d to connect to install referrer API", retryNumber); + + retryTimer.startIn(RETRY_WAIT_TIME); + } +} diff --git a/Adjust/sdk-plugin-play/src/main/java/com/adjust/sdk/play/Util.java b/Adjust/sdk-plugin-play/src/main/java/com/adjust/sdk/play/Util.java new file mode 100644 index 000000000..c5ac898e9 --- /dev/null +++ b/Adjust/sdk-plugin-play/src/main/java/com/adjust/sdk/play/Util.java @@ -0,0 +1,45 @@ +package com.adjust.sdk.play; + +import android.content.Context; + +import com.adjust.sdk.ILogger; +import com.adjust.sdk.PackageBuilder; +import com.google.android.gms.ads.identifier.AdvertisingIdClient; +import com.google.android.gms.common.GooglePlayServicesNotAvailableException; +import com.google.android.gms.common.GooglePlayServicesRepairableException; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +public class Util { + public static Map getPlayParameters(Context context, ILogger logger) { + Map parameters = new HashMap(); + + injectPlayInfo(parameters, context, logger); + + return parameters; + } + + private static void injectPlayInfo(Map parameters, Context context, ILogger logger) { + AdvertisingIdClient.Info advertisingIdInfo = null; + try { + advertisingIdInfo = AdvertisingIdClient.getAdvertisingIdInfo(context); + } catch (IOException e) { + logger.error("IOException when trying to get Advertising Id Info: %s", e.getMessage()); + } catch (GooglePlayServicesNotAvailableException e) { + logger.error("GooglePlayServicesNotAvailableException when trying to get Advertising Id Info: %s", e.getMessage()); + } catch (GooglePlayServicesRepairableException e) { + logger.error("GooglePlayServicesRepairableException when trying to get Advertising Id Info: %s", e.getMessage()); + } + if (advertisingIdInfo == null) { + return; + } + + String id = advertisingIdInfo.getId(); + boolean limitAdTrackingEnabled = advertisingIdInfo.isLimitAdTrackingEnabled(); + + PackageBuilder.addString(parameters, "gps_adid", id); + PackageBuilder.addBoolean(parameters, "tracking_enabled", limitAdTrackingEnabled); + } +} diff --git a/Adjust/sdk-plugin-play/src/main/res/values/strings.xml b/Adjust/sdk-plugin-play/src/main/res/values/strings.xml new file mode 100644 index 000000000..cdbd9c06d --- /dev/null +++ b/Adjust/sdk-plugin-play/src/main/res/values/strings.xml @@ -0,0 +1,3 @@ + + Play + diff --git a/Adjust/webbridge/.gitignore b/Adjust/sdk-plugin-sociomantic/.gitignore similarity index 100% rename from Adjust/webbridge/.gitignore rename to Adjust/sdk-plugin-sociomantic/.gitignore diff --git a/Adjust/sdk-plugin-sociomantic/build.gradle b/Adjust/sdk-plugin-sociomantic/build.gradle new file mode 100644 index 000000000..7ea385873 --- /dev/null +++ b/Adjust/sdk-plugin-sociomantic/build.gradle @@ -0,0 +1,177 @@ +apply plugin: 'com.android.library' +apply plugin: 'maven-publish' +apply plugin: 'signing' + +repositories { + maven { + url "https://oss.sonatype.org/content/repositories/staging/" + } +} + +android { + compileSdkVersion rootProject.ext.coreCompileSdkVersion + + defaultConfig { + minSdkVersion rootProject.ext.coreMinSdkVersion + targetSdkVersion rootProject.ext.coreTargetSdkVersion + versionName rootProject.ext.coreVersionName + versionCode rootProject.ext.defaultVersionCode + } +} + +dependencies { + implementation fileTree(dir: 'libs', include: ['*.jar']) + // Add SDK via module. + implementation project(':sdk-core') + // Add SDK via Maven. + // implementation 'com.adjust.sdk:adjust-android:4.16.0' +} + +task adjustSociomanticAndroidJar(type: Jar) { + dependsOn 'compileReleaseJavaWithJavac' + from('build/intermediates/javac/release/compileReleaseJavaWithJavac/classes/') + archiveName "${project.name}.jar" +} + +task androidJavadocs(type: Javadoc) { + source = android.sourceSets.main.java.srcDirs + classpath += project.files(android.getBootClasspath().join(File.pathSeparator)) + // JDK 1.8 is more strict then 1.7. Have JDK 1.8 behave like 1.7 for javadoc generation. + if (org.gradle.internal.jvm.Jvm.current().getJavaVersion() == JavaVersion.VERSION_1_8) { + options.addStringOption('Xdoclint:none', '-quiet') + } +} + +task adjustSociomanticAndroidJavadocsJar(type: Jar) { + dependsOn 'androidJavadocs' + classifier = 'javadoc' + from androidJavadocs.destinationDir +} + +task adjustSociomanticAndroidSourcesJar(type: Jar) { + classifier = 'sources' + from android.sourceSets.main.java.srcDirs +} + +artifacts { + archives adjustSociomanticAndroidJar + archives adjustSociomanticAndroidJavadocsJar + archives adjustSociomanticAndroidSourcesJar +} + +publishing { + publications { + mavenAndroidSociomantic(MavenPublication) { + customizePom(pom) + groupId rootProject.ext.adjustGroupId + artifactId 'adjust-android-sociomantic' + version rootProject.ext.coreVersionName + + // Create the sign pom artifact. + pom.withXml { + def pomFile = file("${project.buildDir}/generated-pom.xml") + writeTo(pomFile) + def pomAscFile = signing.sign(pomFile).signatureFiles[0] + artifact(pomAscFile) { + classifier = null + extension = 'pom.asc' + } + } + + // Create the signed artifacts. + project.tasks.signArchives.signatureFiles.each { + // Exclude "usual" archive artifact .aar. + def signFileName = it.toString() + if (signFileName.contains('aar')) { + return + } + // Create a Maven artifact for each asc signature. + artifact(it) { + if (signFileName.contains('-sources')) { + classifier = 'sources' + extension = 'jar.asc' + } else if (signFileName.contains('-javadoc')) { + classifier = 'javadoc' + extension = 'jar.asc' + } else { + classifier = null + extension = 'jar.asc' + } + } + } + + artifact adjustSociomanticAndroidJar + artifact adjustSociomanticAndroidJavadocsJar + artifact adjustSociomanticAndroidSourcesJar + } + } + + repositories { + maven { + url "https://oss.sonatype.org/service/local/staging/deploy/maven2" + if (project.hasProperty("sonatypeUsername")) { + credentials { + username sonatypeUsername + password sonatypePassword + } + } + } + } +} + +def customizePom(pom) { + pom.withXml { + def root = asNode() + + // Add all items necessary for maven central publication + root.children().last() + { + resolveStrategy = Closure.DELEGATE_FIRST + description 'The Sociomantic plugin for Adjust SDK for Android' + name 'Adjust Android SDK Sociomantic plugin' + url 'https://github.com/adjust/android_sdk' + + organization { + name 'adjust GmbH' + url 'http://www.adjust.com' + } + licenses { + license { + name 'MIT License' + url 'http://www.opensource.org/licenses/mit-license.php' + } + } + scm { + url 'git@github.com:adjust/android_sdk.git' + connection 'scm:git:git@github.com:adjust/android_sdk.git' + developerConnection 'scm:git:git@github.com:adjust/android_sdk.git' + } + developers { + developer { + name 'Pedro Silva' + email 'pedro@adjust.com' + } + + developer { + name 'Ugljesa Erceg' + email 'ugljesa@adjust.com' + } + } + } + } +} + +model { + tasks.generatePomFileForMavenAndroidSociomanticPublication { + destination = file("${project.buildDir}/generated-pom.xml") + } + tasks.publishMavenAndroidSociomanticPublicationToMavenLocal { + dependsOn project.tasks.signArchives + } + tasks.publishMavenAndroidSociomanticPublicationToMavenRepository { + dependsOn project.tasks.signArchives + } +} + +signing { + sign configurations.archives +} diff --git a/Adjust/sdk-plugin-sociomantic/src/main/AndroidManifest.xml b/Adjust/sdk-plugin-sociomantic/src/main/AndroidManifest.xml new file mode 100644 index 000000000..5ed5b0542 --- /dev/null +++ b/Adjust/sdk-plugin-sociomantic/src/main/AndroidManifest.xml @@ -0,0 +1,2 @@ + diff --git a/Adjust/sdk-plugin-sociomantic/src/main/java/com/adjust/sdk/sociomantic/AdjustSociomantic.java b/Adjust/sdk-plugin-sociomantic/src/main/java/com/adjust/sdk/sociomantic/AdjustSociomantic.java new file mode 100644 index 000000000..0141861d6 --- /dev/null +++ b/Adjust/sdk-plugin-sociomantic/src/main/java/com/adjust/sdk/sociomantic/AdjustSociomantic.java @@ -0,0 +1,425 @@ +package com.adjust.sdk.sociomantic; + +import com.adjust.sdk.AdjustEvent; +import com.adjust.sdk.AdjustFactory; +import com.adjust.sdk.ILogger; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + +/** + * AdjustSociomantic Class + * Created by Nicolas Brugneaux nicolas.brugneaux@sociomantic.com on 01/04/15. + */ +public abstract class AdjustSociomantic { + + public final static String SCMCategory = "category"; + public final static String SCMProducts = "products"; + public final static String SCMProductName = "fn"; + public final static String SCMSalePrice = "price"; + public final static String SCMAmount = "amount"; + public final static String SCMCurrency = "currency"; + public final static String SCMProductURL = "url"; + public final static String SCMProductImageURL = "photo"; + public final static String SCMBrand = "brand"; + public final static String SCMDescription = "description"; + public final static String SCMTimestamp = "date"; + public final static String SCMValidityTimestamp = "valid"; + public final static String SCMQuantity = "quantity"; + public final static String SCMScore = "score"; + public final static String SCMProductID = "identifier"; + public final static String SCMActionConfirmed = "confirmed"; + public final static String SCMCustomerAgeGroup = "agegroup"; + public final static String SCMCustomerEducation = "education"; + public final static String SCMCustomerGender = "gender"; + public final static String SCMCustomerID = "identifier"; + public final static String SCMCustomerMHash = "mhash"; + public final static String SCMCustomerSegment = "segment"; + public final static String SCMCustomerTargeting = "targeting"; + public final static String SCMTransaction = "transaction"; + + private final static List productAliases = Arrays.asList( + SCMCategory, + SCMProductName, + SCMSalePrice, + SCMAmount, + SCMCurrency, + SCMProductURL, + SCMProductImageURL, + SCMBrand, + SCMDescription, + SCMTimestamp, + SCMValidityTimestamp, + SCMQuantity, + SCMScore + ); + + private final static List basketAliases = Arrays.asList( + SCMProductID, + SCMAmount, + SCMCurrency, + SCMQuantity + ); + + private final static List saleAliases = Arrays.asList( + SCMAmount, + SCMCurrency + ); + + private final static List customerAliases = Arrays.asList( + SCMCustomerAgeGroup, + SCMCustomerEducation, + SCMCustomerGender, + SCMCustomerID, + SCMCustomerMHash, + SCMCustomerSegment, + SCMCustomerTargeting + ); + + private static String adpanId; + + private static ILogger logger = AdjustFactory.getLogger(); + + public static void injectPartnerIdInSociomanticEvents(String newAdpanId) { + adpanId = newAdpanId; + } + + public static void injectCustomerDataIntoEvent(AdjustEvent event, Map customerData) { + if (null == event) { + logger.error("Event object is required."); + return; + } + if (null == customerData) { + logger.error("Customer data is required."); + return; + } + + Map data = new HashMap(); + + for (Entry entry: customerData.entrySet()) { + if (!customerAliases.contains(entry.getKey())) { + logger.warn("Key must belong to the customer Aliases, entry: %s was discarded", entry.getKey()); + } + else { + data.put(entry.getKey(), entry.getValue()); + } + } + + String dob = stringify(data); + + addPartnerParameter(event, "socio_dob", dob); + } + + public static void injectHomePageIntoEvent(AdjustEvent event) { + if (null == event) { + logger.error("Event object is required."); + } + addPartnerParameter(event); + } + + public static void injectViewListingIntoEvent(AdjustEvent event, List categories) { + injectViewListingIntoEvent(event, categories, null); + } + public static void injectViewListingIntoEvent(AdjustEvent event, List categories, String date) { + if (null == event) { + logger.error("Event object is required."); + return; + } + if (null == categories) { + logger.error("Categories list is required."); + return; + } + + Map co = new HashMap(); + + if (null != date) { + co.put(SCMTimestamp, date); + } + + co.put(SCMCategory, categories); + + addPartnerParameter(event, "socio_co", stringify(co)); + } + + public static void injectProductIntoEvent(AdjustEvent event, String productId) { + injectProductIntoEvent(event, productId, null); + } + public static void injectProductIntoEvent(AdjustEvent event, String productId, Map parameters) { + if (null == event) { + logger.error("Event object is required."); + return; + } + if (null == productId || "".equals(productId)) { + logger.error("Product ID is required."); + return; + } + + Map>> po = new HashMap>>(1); + List> productList; + Map product; + + if (null != parameters) { + product = filter(parameters, productAliases); + } + else { + product = new HashMap(); + } + + product.put(SCMProductID, productId); + productList = Arrays.asList(product); + po.put(SCMProducts, productList); + addPartnerParameter(event, "socio_po", stringify(po)); + } + + public static void injectCartIntoEvent(AdjustEvent event, List products) { + if (null == event) { + logger.error("Event object is required."); + return; + } + if (null == products) { + logger.error("Products list is required."); + return; + } + + Map>> po = new HashMap>>(1); + List> productList = new ArrayList>(); + + for (Object product: products) { + Map _product = new HashMap(); + + if (product instanceof String) { + _product.put(SCMProductID, product); + } + else if (product instanceof Map) { + _product = filter((Map) product, basketAliases); + } + + if (!_product.isEmpty()) { + productList.add(_product); + } + } + + if (!productList.isEmpty()) { + po.put(SCMProducts, productList); + addPartnerParameter(event, "socio_po", stringify(po)); + } + } + + public static void injectConfirmedTransactionIntoEvent(AdjustEvent event, String transactionID, List products) { + injectTransactionIntoEvent(event, transactionID, products, null, Boolean.TRUE); + } + public static void injectConfirmedTransactionIntoEvent(AdjustEvent event, String transactionID, List products, Map parameters) { + injectTransactionIntoEvent(event, transactionID, products, parameters, Boolean.TRUE); + } + + public static void injectTransactionIntoEvent(AdjustEvent event, String transactionID, List products) { + injectTransactionIntoEvent(event, transactionID, products, null, Boolean.FALSE); + } + public static void injectTransactionIntoEvent(AdjustEvent event, String transactionID, List products, Map parameters) { + injectTransactionIntoEvent(event, transactionID, products, parameters, Boolean.FALSE); + } + private static void injectTransactionIntoEvent(AdjustEvent event, String transactionID, List products, Map parameters, Boolean confirmed) { + if (null == event) { + logger.error("Event object is required."); + return; + } + if (null == transactionID || "".equals(transactionID)) { + logger.error("Transaction ID is required."); + return; + } + if (null == products) { + logger.error("Products list is required."); + return; + } + + Map> to = new HashMap>(1); + Map>> po = new HashMap>>(1); + List> productList = new ArrayList>(); + + for (Object product: products) { + Map _product = new HashMap(); + + if (product instanceof String) { + _product.put(SCMProductID, product); + } + else if (product instanceof Map) { + _product = filter((Map) product, basketAliases); + } + + if (!_product.isEmpty()) { + productList.add(_product); + } + } + + if (!productList.isEmpty()) { + po.put(SCMProducts, productList); + addPartnerParameter(event, "socio_po", stringify(po)); + } + + if (null != parameters) { + to.put(SCMTransaction, filter(parameters, saleAliases)); + } + else { + to.put(SCMTransaction, new HashMap()); + } + + if (confirmed) { + to.get(SCMTransaction).put(SCMActionConfirmed, "true"); + } + + to.get(SCMTransaction).put(SCMTransaction, transactionID); + + addPartnerParameter(event, "socio_to", stringify(to)); + } + + public static void injectLeadIntoEvent(AdjustEvent event, String leadID) { + injectLeadIntoEvent(event, leadID, Boolean.FALSE); + } + public static void injectLeadIntoEvent(AdjustEvent event, String leadID, Boolean confirmed) { + + if (null == event) { + logger.error("Event object is required."); + return; + } + if (null == leadID || "".equals(leadID)) { + logger.error("Lead ID is required."); + return; + } + + Map> to = new HashMap>(1); + to.put(SCMTransaction, new HashMap()); + + if (confirmed) { + to.get(SCMTransaction).put(SCMActionConfirmed, "true"); + } + + to.get(SCMTransaction).put(SCMTransaction, leadID); + + addPartnerParameter(event, "socio_to", stringify(to)); + } + + //////////////////////////////////////////////////////////////////////////////////////////////// + // private methods used internally + //////////////////////////////////////////////////////////////////////////////////////////////// + + private static void addPartnerParameter(AdjustEvent event) { + addPartnerParameter(event, null, null); + } + private static void addPartnerParameter(AdjustEvent event, String parameter, String json) { + if (null == adpanId) { + logger.error("The adpanId must be set before sending any sociomantic event. No parameter has been added."); + return; + } + + if (null != parameter && null != json) + { + event.addPartnerParameter(parameter, json); + } + + event.addPartnerParameter("socio_aid", adpanId); + } + + private static Map filter(Map parameters, List aliases) { + + Map filtered = new HashMap(); + + for(Entry entry: parameters.entrySet()) { + String key = entry.getKey(); + Object value = entry.getValue(); + if (!aliases.contains(key)) { + logger.error("Key must correspond to as Sociomantic alias => ".concat(key)); + } + else { + if (key.equals(SCMCategory)) { + if (value instanceof String || value instanceof String[]) { + filtered.put(key, Arrays.asList(value)); + } else if (value instanceof List) { + filtered.put(key, filterStringArray((List) value)); + } + } + else { + filtered.put(key, value); + } + } + } + return filtered; + } + + private static List filterStringArray(List list) { + + List filtered = new ArrayList(); + for (Object item: list) { + if (item instanceof String) { + filtered.add((String) item); + } + else { + logger.error("All values should be strings"); + } + } + return filtered; + } + + private static String stringify(Object o) { + if (o == null) { + return "null"; + } + + if (o instanceof String) { + return "\"".concat((String) o).concat("\""); + } + + if (o instanceof Integer || o instanceof Long || o instanceof Double) { + return o.toString(); + } + + if (o instanceof Boolean) { + return (Boolean) o ? "true" : "false"; + } + + if (o instanceof List) { + String res = "["; + List list = (List) o; + Iterator iterator = list.iterator(); + + while (iterator.hasNext()) { + Object item = iterator.next(); + res = res.concat(stringify(item)); + + if (iterator.hasNext()) { + res = res.concat(","); + } + } + + return res.concat("]"); + } + + if (o instanceof Map) { + String res = "{"; + Map map = (Map) o; + Iterator> iterator = map.entrySet().iterator(); + + while(iterator.hasNext()) { + Entry entry = iterator.next(); + + res = res.concat(stringify(entry.getKey())) + .concat(":") + .concat(stringify(entry.getValue())); + + if (iterator.hasNext()) { + res = res.concat(","); + } + } + + return res.concat("}"); + } + + logger.error("Could not parse the object ".concat(o.toString().concat(" into a JSON string, returned empty string."))); + return ""; + + } +} diff --git a/Adjust/sdk-plugin-trademob/.gitignore b/Adjust/sdk-plugin-trademob/.gitignore new file mode 100644 index 000000000..796b96d1c --- /dev/null +++ b/Adjust/sdk-plugin-trademob/.gitignore @@ -0,0 +1 @@ +/build diff --git a/Adjust/sdk-plugin-trademob/build.gradle b/Adjust/sdk-plugin-trademob/build.gradle new file mode 100644 index 000000000..39d1b61d5 --- /dev/null +++ b/Adjust/sdk-plugin-trademob/build.gradle @@ -0,0 +1,177 @@ +apply plugin: 'com.android.library' +apply plugin: 'maven-publish' +apply plugin: 'signing' + +repositories { + maven { + url "https://oss.sonatype.org/content/repositories/staging/" + } +} + +android { + compileSdkVersion rootProject.ext.coreCompileSdkVersion + + defaultConfig { + minSdkVersion rootProject.ext.coreMinSdkVersion + targetSdkVersion rootProject.ext.coreTargetSdkVersion + versionName rootProject.ext.coreVersionName + versionCode rootProject.ext.defaultVersionCode + } +} + +dependencies { + implementation fileTree(dir: 'libs', include: ['*.jar']) + // Add SDK via module. + implementation project(':sdk-core') + // Add SDK via Maven. + // implementation 'com.adjust.sdk:adjust-android:4.16.0' +} + +task adjustTrademobAndroidJar(type: Jar) { + dependsOn 'compileReleaseJavaWithJavac' + + from('build/intermediates/javac/release/compileReleaseJavaWithJavac/classes/') + archiveName "${project.name}.jar" +} + +task androidJavadocs(type: Javadoc) { + source = android.sourceSets.main.java.srcDirs + classpath += project.files(android.getBootClasspath().join(File.pathSeparator)) + // JDK 1.8 is more strict then 1.7. Have JDK 1.8 behave like 1.7 for javadoc generation. + if (org.gradle.internal.jvm.Jvm.current().getJavaVersion() == JavaVersion.VERSION_1_8) { + options.addStringOption('Xdoclint:none', '-quiet') + } +} + +task adjustTrademobAndroidJavadocsJar(type: Jar) { + dependsOn 'androidJavadocs' + classifier = 'javadoc' + from androidJavadocs.destinationDir +} + +task adjustTrademobAndroidSourcesJar(type: Jar) { + classifier = 'sources' + from android.sourceSets.main.java.srcDirs +} + +artifacts { + archives adjustTrademobAndroidJar + archives adjustTrademobAndroidJavadocsJar + archives adjustTrademobAndroidSourcesJar +} + +publishing { + publications { + mavenAndroidTrademob(MavenPublication) { + customizePom(pom) + groupId rootProject.ext.adjustGroupId + artifactId 'adjust-android-trademob' + version rootProject.ext.coreVersionName + + // Create the sign pom artifact. + pom.withXml { + def pomFile = file("${project.buildDir}/generated-pom.xml") + writeTo(pomFile) + def pomAscFile = signing.sign(pomFile).signatureFiles[0] + artifact(pomAscFile) { + classifier = null + extension = 'pom.asc' + } + } + + // Create the signed artifacts. + project.tasks.signArchives.signatureFiles.each { + // exclude "usual" archive artifact .aar + def signFileName = it.toString() + if (signFileName.contains('aar')) { + return + } + // Create a maven artifact for each asc signature. + artifact(it) { + if (signFileName.contains('-sources')) { + classifier = 'sources' + extension = 'jar.asc' + } else if (signFileName.contains('-javadoc')) { + classifier = 'javadoc' + extension = 'jar.asc' + } else { + classifier = null + extension = 'jar.asc' + } + } + } + + artifact adjustTrademobAndroidJar + artifact adjustTrademobAndroidJavadocsJar + artifact adjustTrademobAndroidSourcesJar + } + } + + repositories { + maven { + url "https://oss.sonatype.org/service/local/staging/deploy/maven2" + if (project.hasProperty("sonatypeUsername")) { + credentials { + username sonatypeUsername + password sonatypePassword + } + } + } + } +} + +def customizePom(pom) { + pom.withXml { + def root = asNode() + + // Add all items necessary for maven central publication. + root.children().last() + { + resolveStrategy = Closure.DELEGATE_FIRST + description 'The Trademob plugin for Adjust SDK for Android' + name 'Adjust Android SDK Trademob plugin' + url 'https://github.com/adjust/android_sdk' + + organization { + name 'adjust GmbH' + url 'http://www.adjust.com' + } + licenses { + license { + name 'MIT License' + url 'http://www.opensource.org/licenses/mit-license.php' + } + } + scm { + url 'git@github.com:adjust/android_sdk.git' + connection 'scm:git:git@github.com:adjust/android_sdk.git' + developerConnection 'scm:git:git@github.com:adjust/android_sdk.git' + } + developers { + developer { + name 'Pedro Silva' + email 'pedro@adjust.com' + } + developer { + name 'Ugljesa Erceg' + email 'ugljesa@adjust.com' + } + } + } + } +} + +model { + tasks.generatePomFileForMavenAndroidTrademobPublication { + destination = file("${project.buildDir}/generated-pom.xml") + } + tasks.publishMavenAndroidTrademobPublicationToMavenLocal { + dependsOn project.tasks.signArchives + } + tasks.publishMavenAndroidTrademobPublicationToMavenRepository { + dependsOn project.tasks.signArchives + } +} + +signing { + sign configurations.archives +} diff --git a/Adjust/sdk-plugin-trademob/src/main/AndroidManifest.xml b/Adjust/sdk-plugin-trademob/src/main/AndroidManifest.xml new file mode 100644 index 000000000..c8bf34d5e --- /dev/null +++ b/Adjust/sdk-plugin-trademob/src/main/AndroidManifest.xml @@ -0,0 +1,2 @@ + diff --git a/Adjust/sdk-plugin-trademob/src/main/java/com/adjust/sdk/trademob/AdjustTrademob.java b/Adjust/sdk-plugin-trademob/src/main/java/com/adjust/sdk/trademob/AdjustTrademob.java new file mode 100644 index 000000000..26867ca88 --- /dev/null +++ b/Adjust/sdk-plugin-trademob/src/main/java/com/adjust/sdk/trademob/AdjustTrademob.java @@ -0,0 +1,128 @@ +package com.adjust.sdk.trademob; + +import com.adjust.sdk.AdjustEvent; +import com.adjust.sdk.AdjustFactory; +import com.adjust.sdk.ILogger; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Locale; +import java.util.Map; + + +public class AdjustTrademob { + + private static int MAX_LISTING_ITEMS_COUNT = 5; + + private static ILogger logger = AdjustFactory.getLogger(); + + public static void injectViewItemIntoEvent(AdjustEvent event, String itemId, Map metadata) { + event.addPartnerParameter("tm_item", itemId); + String jsonMetadata = stringifyMetadata(metadata); + event.addPartnerParameter("tm_md", jsonMetadata); + } + + public static void injectViewListingIntoEvent(AdjustEvent event, List itemIds, Map metadata) { + String jsonItems = stringifyItemIds(itemIds); + event.addPartnerParameter("tm_item", jsonItems); + String jsonMetadata = stringifyMetadata(metadata); + event.addPartnerParameter("tm_md", jsonMetadata); + } + + public static void injectAddToBasketIntoEvent(AdjustEvent event, List items, Map metadata) { + String jsonMetadata = stringifyMetadata(metadata); + event.addPartnerParameter("tm_md", jsonMetadata); + String jsonItems = stringifyItems(items); + event.addPartnerParameter("tm_item", jsonItems); + } + + public static void injectCheckoutIntoEvent(AdjustEvent event, List items, Map metadata) { + String jsonMetadata = stringifyMetadata(metadata); + event.addPartnerParameter("tm_md", jsonMetadata); + String jsonItems = stringifyItems(items); + event.addPartnerParameter("tm_item", jsonItems); + } + + private static String stringifyItemIds(List itemIds) { + if (itemIds == null) { + logger.warn("TM View Listing item ids list is null. Empty ids array will be sent."); + itemIds = new ArrayList(); + } + StringBuffer tmViewList = new StringBuffer("["); + int itemsSize = itemIds.size(); + int i = 0; + + while (i < itemsSize) { + String itemId = itemIds.get(i); + String itemString = String.format(Locale.US, "\"%s\"", itemId); + tmViewList.append(itemString); + + i++; + + if (i == itemsSize || i >= MAX_LISTING_ITEMS_COUNT) { + break; + } + + tmViewList.append(","); + } + + tmViewList.append("]"); + + return tmViewList.toString(); + } + + private static String stringifyItems(List items) { + if (items == null) { + logger.warn("TM View Listing item ids list is empty. Empty items will be sent."); + items = new ArrayList(); + } + + StringBuffer itemsStrBuffer = new StringBuffer("["); + int itemsSize = items.size(); + + for (int i = 0; i < itemsSize; ) { + TrademobItem item = items.get(i); + String itemString = String.format(Locale.US, "{\"id\":\"%s\",\"price\":%f,\"quantity\":%d}", + item.itemId, + item.price, + item.quantity); + itemsStrBuffer.append(itemString); + + i++; + + if (i == itemsSize || i >= MAX_LISTING_ITEMS_COUNT) { + break; + } + + itemsStrBuffer.append(","); + } + + itemsStrBuffer.append("]"); + + return itemsStrBuffer.toString(); + } + + private static String stringifyMetadata(Map metadata) { + + if(null == metadata) { + return "{}"; + } + String res = "{"; + + Iterator> iterator = metadata.entrySet().iterator(); + + while(iterator.hasNext()) { + Map.Entry entry = iterator.next(); + String key = "\"".concat(entry.getKey()).concat("\""); + String value = "\"".concat(entry.getValue()).concat("\""); + res = res.concat(key).concat(":").concat(value); + + if (iterator.hasNext()) { + res = res.concat(","); + } + } + + return res.concat("}"); + } +} diff --git a/Adjust/sdk-plugin-trademob/src/main/java/com/adjust/sdk/trademob/TrademobItem.java b/Adjust/sdk-plugin-trademob/src/main/java/com/adjust/sdk/trademob/TrademobItem.java new file mode 100644 index 000000000..483c1a334 --- /dev/null +++ b/Adjust/sdk-plugin-trademob/src/main/java/com/adjust/sdk/trademob/TrademobItem.java @@ -0,0 +1,13 @@ +package com.adjust.sdk.trademob; + +public class TrademobItem { + float price; + int quantity; + String itemId; + + public TrademobItem(String itemId, int quantity, float price) { + this.price = price; + this.quantity = quantity; + this.itemId = itemId; + } +} diff --git a/Adjust/sdk-webbridge/.gitignore b/Adjust/sdk-webbridge/.gitignore new file mode 100644 index 000000000..796b96d1c --- /dev/null +++ b/Adjust/sdk-webbridge/.gitignore @@ -0,0 +1 @@ +/build diff --git a/Adjust/sdk-webbridge/build.gradle b/Adjust/sdk-webbridge/build.gradle new file mode 100644 index 000000000..5f9a8b3a3 --- /dev/null +++ b/Adjust/sdk-webbridge/build.gradle @@ -0,0 +1,182 @@ +apply plugin: 'com.android.library' +apply plugin: 'maven-publish' +apply plugin: 'signing' + +repositories { + maven { + url "https://oss.sonatype.org/content/repositories/staging/" + } +} + +android { + compileSdkVersion rootProject.ext.coreCompileSdkVersion + + defaultConfig { + minSdkVersion rootProject.ext.coreMinSdkVersion + targetSdkVersion rootProject.ext.coreTargetSdkVersion + versionName rootProject.ext.coreVersionName + versionCode rootProject.ext.defaultVersionCode + } +} + +dependencies { + implementation fileTree(dir: 'libs', include: ['*.jar']) + // Add SDK via module. + implementation project(':sdk-core') + // Add SDK via Maven. + // implementation 'com.adjust.sdk:adjust-android:4.16.0' +} + +task adjustWebBridgeAndroidJar(type: Jar) { + dependsOn 'packageReleaseAssets' + dependsOn 'compileReleaseJavaWithJavac' + + from('build/intermediates/library_assets/release/packageReleaseAssets/out/') { + into('assets') + } + from('build/intermediates/javac/release/compileReleaseJavaWithJavac/classes/') + + archiveName "${project.name}.jar" +} + +task androidJavadocs(type: Javadoc) { + source = android.sourceSets.main.java.srcDirs + classpath += project.files(android.getBootClasspath().join(File.pathSeparator)) + // JDK 1.8 is more strict then 1.7. Have JDK 1.8 behave like 1.7 for javadoc generation. + if (org.gradle.internal.jvm.Jvm.current().getJavaVersion() == JavaVersion.VERSION_1_8) { + options.addStringOption('Xdoclint:none', '-quiet') + } +} + +task adjustWebBridgeAndroidJavadocsJar(type: Jar) { + dependsOn 'androidJavadocs' + classifier = 'javadoc' + from androidJavadocs.destinationDir +} + +task adjustWebBridgeAndroidSourcesJar(type: Jar) { + classifier = 'sources' + from android.sourceSets.main.java.srcDirs +} + +artifacts { + archives adjustWebBridgeAndroidJar + archives adjustWebBridgeAndroidJavadocsJar + archives adjustWebBridgeAndroidSourcesJar +} + +publishing { + publications { + mavenAndroidWebBridge(MavenPublication) { + customizePom(pom) + groupId rootProject.ext.adjustGroupId + artifactId 'adjust-android-webbridge' + version rootProject.ext.coreVersionName + + // Create the sign pom artifact. + pom.withXml { + def pomFile = file("${project.buildDir}/generated-pom.xml") + writeTo(pomFile) + def pomAscFile = signing.sign(pomFile).signatureFiles[0] + artifact(pomAscFile) { + classifier = null + extension = 'pom.asc' + } + } + + // Create the signed artifacts. + project.tasks.signArchives.signatureFiles.each { + // Exclude "usual" archive artifact .aar. + def signFileName = it.toString() + if (signFileName.contains('aar')) { + return + } + // Create a Maven artifact for each asc signature. + artifact(it) { + if (signFileName.contains('-sources')) { + classifier = 'sources' + extension = 'jar.asc' + } else if (signFileName.contains('-javadoc')) { + classifier = 'javadoc' + extension = 'jar.asc' + } else { + classifier = null + extension = 'jar.asc' + } + } + } + + artifact adjustWebBridgeAndroidJar + artifact adjustWebBridgeAndroidJavadocsJar + artifact adjustWebBridgeAndroidSourcesJar + } + } + + repositories { + maven { + url "https://oss.sonatype.org/service/local/staging/deploy/maven2" + if (project.hasProperty("sonatypeUsername")) { + credentials { + username sonatypeUsername + password sonatypePassword + } + } + } + } +} + +def customizePom(pom) { + pom.withXml { + def root = asNode() + + // Add all items necessary for maven central publication. + root.children().last() + { + resolveStrategy = Closure.DELEGATE_FIRST + description 'The WebBridge plugin for Adjust SDK for Android' + name 'Adjust Android SDK WebBridge plugin' + url 'https://github.com/adjust/android_sdk' + + organization { + name 'adjust GmbH' + url 'http://www.adjust.com' + } + licenses { + license { + name 'MIT License' + url 'http://www.opensource.org/licenses/mit-license.php' + } + } + scm { + url 'git@github.com:adjust/android_sdk.git' + connection 'scm:git:git@github.com:adjust/android_sdk.git' + developerConnection 'scm:git:git@github.com:adjust/android_sdk.git' + } + developers { + developer { + name 'Pedro Silva' + email 'pedro@adjust.com' + } + developer { + name 'Ugljesa Erceg' + email 'ugljesa@adjust.com' + } + } + } + } +} + +model { + tasks.generatePomFileForMavenAndroidWebBridgePublication { + destination = file("${project.buildDir}/generated-pom.xml") + } + tasks.publishMavenAndroidWebBridgePublicationToMavenLocal { + dependsOn project.tasks.signArchives + } + tasks.publishMavenAndroidWebBridgePublicationToMavenRepository { + dependsOn project.tasks.signArchives + } +} + +signing { + sign configurations.archives +} diff --git a/Adjust/testlibrary/proguard-rules.pro b/Adjust/sdk-webbridge/proguard-rules.pro similarity index 100% rename from Adjust/testlibrary/proguard-rules.pro rename to Adjust/sdk-webbridge/proguard-rules.pro diff --git a/Adjust/sdk-webbridge/src/main/AndroidManifest.xml b/Adjust/sdk-webbridge/src/main/AndroidManifest.xml new file mode 100644 index 000000000..3dbcc23c2 --- /dev/null +++ b/Adjust/sdk-webbridge/src/main/AndroidManifest.xml @@ -0,0 +1,2 @@ + diff --git a/Adjust/webbridge/src/main/assets/adjust.js b/Adjust/sdk-webbridge/src/main/assets/adjust.js similarity index 100% rename from Adjust/webbridge/src/main/assets/adjust.js rename to Adjust/sdk-webbridge/src/main/assets/adjust.js diff --git a/Adjust/webbridge/src/main/assets/adjust_config.js b/Adjust/sdk-webbridge/src/main/assets/adjust_config.js similarity index 99% rename from Adjust/webbridge/src/main/assets/adjust_config.js rename to Adjust/sdk-webbridge/src/main/assets/adjust_config.js index 17944d4e2..f76c45f37 100644 --- a/Adjust/webbridge/src/main/assets/adjust_config.js +++ b/Adjust/sdk-webbridge/src/main/assets/adjust_config.js @@ -22,7 +22,7 @@ function AdjustConfig(appToken, environment, legacy) { this.eventBufferingEnabled = null; this.sendInBackground = null; this.logLevel = null; - this.sdkPrefix = 'web-bridge4.15.0'; + this.sdkPrefix = 'web-bridge4.16.0'; this.processName = null; this.defaultTracker = null; this.attributionCallbackName = null; diff --git a/Adjust/webbridge/src/main/assets/adjust_event.js b/Adjust/sdk-webbridge/src/main/assets/adjust_event.js similarity index 100% rename from Adjust/webbridge/src/main/assets/adjust_event.js rename to Adjust/sdk-webbridge/src/main/assets/adjust_event.js diff --git a/Adjust/webbridge/src/main/java/com/adjust/sdk/bridge/AdjustBridge.java b/Adjust/sdk-webbridge/src/main/java/com/adjust/sdk/webbridge/AdjustBridge.java similarity index 96% rename from Adjust/webbridge/src/main/java/com/adjust/sdk/bridge/AdjustBridge.java rename to Adjust/sdk-webbridge/src/main/java/com/adjust/sdk/webbridge/AdjustBridge.java index a843b9710..2e0b5922a 100644 --- a/Adjust/webbridge/src/main/java/com/adjust/sdk/bridge/AdjustBridge.java +++ b/Adjust/sdk-webbridge/src/main/java/com/adjust/sdk/webbridge/AdjustBridge.java @@ -1,4 +1,4 @@ -package com.adjust.sdk.bridge; +package com.adjust.sdk.webbridge; import android.webkit.WebView; import android.app.Application; diff --git a/Adjust/webbridge/src/main/java/com/adjust/sdk/bridge/AdjustBridgeInstance.java b/Adjust/sdk-webbridge/src/main/java/com/adjust/sdk/webbridge/AdjustBridgeInstance.java similarity index 99% rename from Adjust/webbridge/src/main/java/com/adjust/sdk/bridge/AdjustBridgeInstance.java rename to Adjust/sdk-webbridge/src/main/java/com/adjust/sdk/webbridge/AdjustBridgeInstance.java index 8990b206b..e8db625b3 100644 --- a/Adjust/webbridge/src/main/java/com/adjust/sdk/bridge/AdjustBridgeInstance.java +++ b/Adjust/sdk-webbridge/src/main/java/com/adjust/sdk/webbridge/AdjustBridgeInstance.java @@ -1,7 +1,6 @@ -package com.adjust.sdk.bridge; +package com.adjust.sdk.webbridge; import android.annotation.TargetApi; -import android.content.Context; import android.net.Uri; import android.os.Build; import android.os.Bundle; diff --git a/Adjust/webbridge/src/main/java/com/adjust/sdk/bridge/AdjustBridgeUtil.java b/Adjust/sdk-webbridge/src/main/java/com/adjust/sdk/webbridge/AdjustBridgeUtil.java similarity index 99% rename from Adjust/webbridge/src/main/java/com/adjust/sdk/bridge/AdjustBridgeUtil.java rename to Adjust/sdk-webbridge/src/main/java/com/adjust/sdk/webbridge/AdjustBridgeUtil.java index edb8d83a1..e56a04698 100644 --- a/Adjust/webbridge/src/main/java/com/adjust/sdk/bridge/AdjustBridgeUtil.java +++ b/Adjust/sdk-webbridge/src/main/java/com/adjust/sdk/webbridge/AdjustBridgeUtil.java @@ -1,4 +1,4 @@ -package com.adjust.sdk.bridge; +package com.adjust.sdk.webbridge; import android.net.Uri; import android.webkit.WebView; diff --git a/Adjust/webbridge/src/main/java/com/adjust/sdk/bridge/FacebookSDKJSInterface.java b/Adjust/sdk-webbridge/src/main/java/com/adjust/sdk/webbridge/FacebookSDKJSInterface.java similarity index 98% rename from Adjust/webbridge/src/main/java/com/adjust/sdk/bridge/FacebookSDKJSInterface.java rename to Adjust/sdk-webbridge/src/main/java/com/adjust/sdk/webbridge/FacebookSDKJSInterface.java index 218a65bf9..342ad194e 100644 --- a/Adjust/webbridge/src/main/java/com/adjust/sdk/bridge/FacebookSDKJSInterface.java +++ b/Adjust/sdk-webbridge/src/main/java/com/adjust/sdk/webbridge/FacebookSDKJSInterface.java @@ -1,4 +1,4 @@ -package com.adjust.sdk.bridge; +package com.adjust.sdk.webbridge; /** * Taken and adapted from * https://github.com/facebook/facebook-android-sdk/blob/8cb6f95df8d2763f67e136eb7b2a66d9ddfc5157/facebook-core/src/main/java/com/facebook/appevents/FacebookSDKJSInterface.java @@ -38,8 +38,6 @@ import java.util.Iterator; import java.util.Locale; import java.util.Map; -import java.util.SortedMap; -import java.util.TreeMap; public class FacebookSDKJSInterface { private static final String PROTOCOL = "fbmq-0.1"; diff --git a/Adjust/settings.gradle b/Adjust/settings.gradle index 74ae3c624..f9ae31850 100644 --- a/Adjust/settings.gradle +++ b/Adjust/settings.gradle @@ -1 +1 @@ -include ':adjust', ':test', ':example', ':example-tv', ':testlibrary', ':testapp', ':example-webbridge', ':webbridge', ':testapp-webbridge', ':example-fbpixel' +include ':sdk-core', ':test-unit', ':example-app-java', ':example-app-tv', ':test-library', ':test-app-core', ':example-app-webbridge', ':sdk-webbridge', ':test-app-webbridge', ':example-app-fbpixel', ':sdk-plugin-imei', ':sdk-plugin-play', ':sdk-plugin-criteo', ':sdk-plugin-trademob', ':sdk-plugin-sociomantic', ':test-kotlin' diff --git a/Adjust/test-app-core/.gitignore b/Adjust/test-app-core/.gitignore new file mode 100644 index 000000000..796b96d1c --- /dev/null +++ b/Adjust/test-app-core/.gitignore @@ -0,0 +1 @@ +/build diff --git a/Adjust/testapp/build.gradle b/Adjust/test-app-core/build.gradle similarity index 55% rename from Adjust/testapp/build.gradle rename to Adjust/test-app-core/build.gradle index f78ff29ea..b340646e1 100644 --- a/Adjust/testapp/build.gradle +++ b/Adjust/test-app-core/build.gradle @@ -1,23 +1,21 @@ apply plugin: 'com.android.application' android { - compileSdkVersion 25 - buildToolsVersion '27.0.3' + compileSdkVersion 28 defaultConfig { applicationId "com.adjust.testapp" - minSdkVersion 9 - targetSdkVersion 25 + minSdkVersion 14 + targetSdkVersion 28 versionCode 1 versionName "1.0" } } dependencies { - implementation project(":testlibrary") - implementation project(":adjust") - - implementation 'com.android.support:appcompat-v7:25.4.0' - implementation 'com.android.support.constraint:constraint-layout:1.0.2' + implementation project(':test-library') + implementation project(':sdk-core') + implementation 'com.android.support:appcompat-v7:28.0.0' + implementation 'com.android.support.constraint:constraint-layout:1.1.3' implementation 'com.android.installreferrer:installreferrer:1.0' } diff --git a/Adjust/webbridge/proguard-rules.pro b/Adjust/test-app-core/proguard-rules.pro similarity index 100% rename from Adjust/webbridge/proguard-rules.pro rename to Adjust/test-app-core/proguard-rules.pro diff --git a/Adjust/testapp/src/main/AndroidManifest.xml b/Adjust/test-app-core/src/main/AndroidManifest.xml similarity index 100% rename from Adjust/testapp/src/main/AndroidManifest.xml rename to Adjust/test-app-core/src/main/AndroidManifest.xml diff --git a/Adjust/testapp/src/main/java/com/adjust/testapp/AdjustCommandExecutor.java b/Adjust/test-app-core/src/main/java/com/adjust/testapp/AdjustCommandExecutor.java similarity index 100% rename from Adjust/testapp/src/main/java/com/adjust/testapp/AdjustCommandExecutor.java rename to Adjust/test-app-core/src/main/java/com/adjust/testapp/AdjustCommandExecutor.java diff --git a/Adjust/testapp/src/main/java/com/adjust/testapp/Command.java b/Adjust/test-app-core/src/main/java/com/adjust/testapp/Command.java similarity index 100% rename from Adjust/testapp/src/main/java/com/adjust/testapp/Command.java rename to Adjust/test-app-core/src/main/java/com/adjust/testapp/Command.java diff --git a/Adjust/testapp/src/main/java/com/adjust/testapp/CommandListener.java b/Adjust/test-app-core/src/main/java/com/adjust/testapp/CommandListener.java similarity index 96% rename from Adjust/testapp/src/main/java/com/adjust/testapp/CommandListener.java rename to Adjust/test-app-core/src/main/java/com/adjust/testapp/CommandListener.java index 9290145b9..b95b44f3d 100644 --- a/Adjust/testapp/src/main/java/com/adjust/testapp/CommandListener.java +++ b/Adjust/test-app-core/src/main/java/com/adjust/testapp/CommandListener.java @@ -3,7 +3,7 @@ import android.content.Context; import android.util.Log; -import com.adjust.testlibrary.ICommandListener; +import com.adjust.test.ICommandListener; import java.util.Arrays; import java.util.List; diff --git a/Adjust/testapp/src/main/java/com/adjust/testapp/MainActivity.java b/Adjust/test-app-core/src/main/java/com/adjust/testapp/MainActivity.java similarity index 92% rename from Adjust/testapp/src/main/java/com/adjust/testapp/MainActivity.java rename to Adjust/test-app-core/src/main/java/com/adjust/testapp/MainActivity.java index a2d4e7f51..574e32f60 100644 --- a/Adjust/testapp/src/main/java/com/adjust/testapp/MainActivity.java +++ b/Adjust/test-app-core/src/main/java/com/adjust/testapp/MainActivity.java @@ -6,7 +6,7 @@ import android.support.v7.app.AppCompatActivity; import com.adjust.sdk.Adjust; -import com.adjust.testlibrary.TestLibrary; +import com.adjust.test.TestLibrary; public class MainActivity extends AppCompatActivity { public static TestLibrary testLibrary; @@ -36,6 +36,6 @@ private void startTestSession() { // testLibrary.addTestDirectory("current/gdpr"); // testLibrary.addTest("current/gdpr/Test_GdprForgetMe_after_install_kill_before_install"); - testLibrary.startTestSession("android4.15.1"); + testLibrary.startTestSession("android4.16.0"); } } diff --git a/Adjust/testapp/src/main/java/com/adjust/testapp/Util.java b/Adjust/test-app-core/src/main/java/com/adjust/testapp/Util.java similarity index 100% rename from Adjust/testapp/src/main/java/com/adjust/testapp/Util.java rename to Adjust/test-app-core/src/main/java/com/adjust/testapp/Util.java diff --git a/Adjust/testapp-webbridge/src/main/res/drawable-v24/ic_launcher_foreground.xml b/Adjust/test-app-core/src/main/res/drawable-v24/ic_launcher_foreground.xml similarity index 100% rename from Adjust/testapp-webbridge/src/main/res/drawable-v24/ic_launcher_foreground.xml rename to Adjust/test-app-core/src/main/res/drawable-v24/ic_launcher_foreground.xml diff --git a/Adjust/testapp-webbridge/src/main/res/drawable/ic_launcher_background.xml b/Adjust/test-app-core/src/main/res/drawable/ic_launcher_background.xml similarity index 100% rename from Adjust/testapp-webbridge/src/main/res/drawable/ic_launcher_background.xml rename to Adjust/test-app-core/src/main/res/drawable/ic_launcher_background.xml diff --git a/Adjust/testapp/src/main/res/layout/activity_main.xml b/Adjust/test-app-core/src/main/res/layout/activity_main.xml similarity index 100% rename from Adjust/testapp/src/main/res/layout/activity_main.xml rename to Adjust/test-app-core/src/main/res/layout/activity_main.xml diff --git a/Adjust/testapp-webbridge/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/Adjust/test-app-core/src/main/res/mipmap-anydpi-v26/ic_launcher.xml similarity index 100% rename from Adjust/testapp-webbridge/src/main/res/mipmap-anydpi-v26/ic_launcher.xml rename to Adjust/test-app-core/src/main/res/mipmap-anydpi-v26/ic_launcher.xml diff --git a/Adjust/testapp-webbridge/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/Adjust/test-app-core/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml similarity index 100% rename from Adjust/testapp-webbridge/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml rename to Adjust/test-app-core/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml diff --git a/Adjust/testapp-webbridge/src/main/res/mipmap-hdpi/ic_launcher.png b/Adjust/test-app-core/src/main/res/mipmap-hdpi/ic_launcher.png similarity index 100% rename from Adjust/testapp-webbridge/src/main/res/mipmap-hdpi/ic_launcher.png rename to Adjust/test-app-core/src/main/res/mipmap-hdpi/ic_launcher.png diff --git a/Adjust/testapp-webbridge/src/main/res/mipmap-hdpi/ic_launcher_round.png b/Adjust/test-app-core/src/main/res/mipmap-hdpi/ic_launcher_round.png similarity index 100% rename from Adjust/testapp-webbridge/src/main/res/mipmap-hdpi/ic_launcher_round.png rename to Adjust/test-app-core/src/main/res/mipmap-hdpi/ic_launcher_round.png diff --git a/Adjust/testapp-webbridge/src/main/res/mipmap-mdpi/ic_launcher.png b/Adjust/test-app-core/src/main/res/mipmap-mdpi/ic_launcher.png similarity index 100% rename from Adjust/testapp-webbridge/src/main/res/mipmap-mdpi/ic_launcher.png rename to Adjust/test-app-core/src/main/res/mipmap-mdpi/ic_launcher.png diff --git a/Adjust/testapp-webbridge/src/main/res/mipmap-mdpi/ic_launcher_round.png b/Adjust/test-app-core/src/main/res/mipmap-mdpi/ic_launcher_round.png similarity index 100% rename from Adjust/testapp-webbridge/src/main/res/mipmap-mdpi/ic_launcher_round.png rename to Adjust/test-app-core/src/main/res/mipmap-mdpi/ic_launcher_round.png diff --git a/Adjust/testapp-webbridge/src/main/res/mipmap-xhdpi/ic_launcher.png b/Adjust/test-app-core/src/main/res/mipmap-xhdpi/ic_launcher.png similarity index 100% rename from Adjust/testapp-webbridge/src/main/res/mipmap-xhdpi/ic_launcher.png rename to Adjust/test-app-core/src/main/res/mipmap-xhdpi/ic_launcher.png diff --git a/Adjust/testapp-webbridge/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/Adjust/test-app-core/src/main/res/mipmap-xhdpi/ic_launcher_round.png similarity index 100% rename from Adjust/testapp-webbridge/src/main/res/mipmap-xhdpi/ic_launcher_round.png rename to Adjust/test-app-core/src/main/res/mipmap-xhdpi/ic_launcher_round.png diff --git a/Adjust/testapp-webbridge/src/main/res/mipmap-xxhdpi/ic_launcher.png b/Adjust/test-app-core/src/main/res/mipmap-xxhdpi/ic_launcher.png similarity index 100% rename from Adjust/testapp-webbridge/src/main/res/mipmap-xxhdpi/ic_launcher.png rename to Adjust/test-app-core/src/main/res/mipmap-xxhdpi/ic_launcher.png diff --git a/Adjust/testapp-webbridge/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/Adjust/test-app-core/src/main/res/mipmap-xxhdpi/ic_launcher_round.png similarity index 100% rename from Adjust/testapp-webbridge/src/main/res/mipmap-xxhdpi/ic_launcher_round.png rename to Adjust/test-app-core/src/main/res/mipmap-xxhdpi/ic_launcher_round.png diff --git a/Adjust/testapp-webbridge/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/Adjust/test-app-core/src/main/res/mipmap-xxxhdpi/ic_launcher.png similarity index 100% rename from Adjust/testapp-webbridge/src/main/res/mipmap-xxxhdpi/ic_launcher.png rename to Adjust/test-app-core/src/main/res/mipmap-xxxhdpi/ic_launcher.png diff --git a/Adjust/testapp-webbridge/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/Adjust/test-app-core/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png similarity index 100% rename from Adjust/testapp-webbridge/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png rename to Adjust/test-app-core/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png diff --git a/Adjust/testapp-webbridge/src/main/res/values/colors.xml b/Adjust/test-app-core/src/main/res/values/colors.xml similarity index 100% rename from Adjust/testapp-webbridge/src/main/res/values/colors.xml rename to Adjust/test-app-core/src/main/res/values/colors.xml diff --git a/Adjust/testapp/src/main/res/values/strings.xml b/Adjust/test-app-core/src/main/res/values/strings.xml similarity index 100% rename from Adjust/testapp/src/main/res/values/strings.xml rename to Adjust/test-app-core/src/main/res/values/strings.xml diff --git a/Adjust/testapp-webbridge/src/main/res/values/styles.xml b/Adjust/test-app-core/src/main/res/values/styles.xml similarity index 100% rename from Adjust/testapp-webbridge/src/main/res/values/styles.xml rename to Adjust/test-app-core/src/main/res/values/styles.xml diff --git a/Adjust/test-app-webbridge/.gitignore b/Adjust/test-app-webbridge/.gitignore new file mode 100644 index 000000000..796b96d1c --- /dev/null +++ b/Adjust/test-app-webbridge/.gitignore @@ -0,0 +1 @@ +/build diff --git a/Adjust/testapp-webbridge/build.gradle b/Adjust/test-app-webbridge/build.gradle similarity index 70% rename from Adjust/testapp-webbridge/build.gradle rename to Adjust/test-app-webbridge/build.gradle index da3106e46..ba5260ec1 100644 --- a/Adjust/testapp-webbridge/build.gradle +++ b/Adjust/test-app-webbridge/build.gradle @@ -1,19 +1,15 @@ apply plugin: 'com.android.application' android { - compileSdkVersion 25 - - + compileSdkVersion 28 defaultConfig { applicationId "com.example.testappwebbridge" - minSdkVersion 9 - targetSdkVersion 25 + minSdkVersion 14 + targetSdkVersion 28 versionCode 1 versionName "1.0" - testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" - } buildTypes { @@ -27,12 +23,10 @@ android { dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) - - implementation project(':adjust') - implementation project(':webbridge') - implementation project(":testlibrary") - - implementation 'com.android.support:appcompat-v7:25.4.0' - implementation 'com.android.support.constraint:constraint-layout:1.0.2' + implementation project(':sdk-core') + implementation project(':sdk-webbridge') + implementation project(':test-library') + implementation 'com.android.support:appcompat-v7:28.0.0' + implementation 'com.android.support.constraint:constraint-layout:1.1.3' implementation 'com.android.installreferrer:installreferrer:1.0' } diff --git a/Adjust/test-app-webbridge/proguard-rules.pro b/Adjust/test-app-webbridge/proguard-rules.pro new file mode 100644 index 000000000..f1b424510 --- /dev/null +++ b/Adjust/test-app-webbridge/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile diff --git a/Adjust/testapp-webbridge/src/main/AndroidManifest.xml b/Adjust/test-app-webbridge/src/main/AndroidManifest.xml similarity index 100% rename from Adjust/testapp-webbridge/src/main/AndroidManifest.xml rename to Adjust/test-app-webbridge/src/main/AndroidManifest.xml diff --git a/Adjust/testapp-webbridge/src/main/assets/AdjustTestApp-WebView.html b/Adjust/test-app-webbridge/src/main/assets/AdjustTestApp-WebView.html similarity index 94% rename from Adjust/testapp-webbridge/src/main/assets/AdjustTestApp-WebView.html rename to Adjust/test-app-webbridge/src/main/assets/AdjustTestApp-WebView.html index 1ec0c554d..696f30d7f 100755 --- a/Adjust/testapp-webbridge/src/main/assets/AdjustTestApp-WebView.html +++ b/Adjust/test-app-webbridge/src/main/assets/AdjustTestApp-WebView.html @@ -24,7 +24,7 @@

Adjust Web View SDK Test

window.onload = function() { // TestLibrary.addTestDirectory('current/user-agent'); // TestLibrary.addTest('current/deeplink-deferred/Test_DeferredDeeplink_callback_false'); - TestLibrary.startTestSession("web-bridge4.15.0@android4.15.1"); + TestLibrary.startTestSession("web-bridge4.16.0@android4.16.0"); }
diff --git a/Adjust/testapp-webbridge/src/main/assets/command_executor.js b/Adjust/test-app-webbridge/src/main/assets/command_executor.js similarity index 100% rename from Adjust/testapp-webbridge/src/main/assets/command_executor.js rename to Adjust/test-app-webbridge/src/main/assets/command_executor.js diff --git a/Adjust/testapp-webbridge/src/main/assets/test_library.js b/Adjust/test-app-webbridge/src/main/assets/test_library.js similarity index 100% rename from Adjust/testapp-webbridge/src/main/assets/test_library.js rename to Adjust/test-app-webbridge/src/main/assets/test_library.js diff --git a/Adjust/testapp-webbridge/src/main/java/com/example/testappwebbridge/MainActivity.java b/Adjust/test-app-webbridge/src/main/java/com/example/testappwebbridge/MainActivity.java similarity index 98% rename from Adjust/testapp-webbridge/src/main/java/com/example/testappwebbridge/MainActivity.java rename to Adjust/test-app-webbridge/src/main/java/com/example/testappwebbridge/MainActivity.java index 4a9cb179f..dcf732027 100644 --- a/Adjust/testapp-webbridge/src/main/java/com/example/testappwebbridge/MainActivity.java +++ b/Adjust/test-app-webbridge/src/main/java/com/example/testappwebbridge/MainActivity.java @@ -11,7 +11,7 @@ import android.webkit.WebViewClient; import com.adjust.sdk.Adjust; -import com.adjust.sdk.bridge.AdjustBridge; +import com.adjust.sdk.webbridge.AdjustBridge; public class MainActivity extends AppCompatActivity { WebView webView; diff --git a/Adjust/testapp-webbridge/src/main/java/com/example/testappwebbridge/TestLibraryBridge.java b/Adjust/test-app-webbridge/src/main/java/com/example/testappwebbridge/TestLibraryBridge.java similarity index 96% rename from Adjust/testapp-webbridge/src/main/java/com/example/testappwebbridge/TestLibraryBridge.java rename to Adjust/test-app-webbridge/src/main/java/com/example/testappwebbridge/TestLibraryBridge.java index b3a787cc7..78238ad22 100644 --- a/Adjust/testapp-webbridge/src/main/java/com/example/testappwebbridge/TestLibraryBridge.java +++ b/Adjust/test-app-webbridge/src/main/java/com/example/testappwebbridge/TestLibraryBridge.java @@ -3,8 +3,8 @@ import android.util.Log; import android.webkit.JavascriptInterface; import android.webkit.WebView; -import com.adjust.testlibrary.ICommandRawJsonListener; -import com.adjust.testlibrary.TestLibrary; +import com.adjust.test.ICommandRawJsonListener; +import com.adjust.test.TestLibrary; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; diff --git a/Adjust/testapp/src/main/res/drawable-v24/ic_launcher_foreground.xml b/Adjust/test-app-webbridge/src/main/res/drawable-v24/ic_launcher_foreground.xml similarity index 100% rename from Adjust/testapp/src/main/res/drawable-v24/ic_launcher_foreground.xml rename to Adjust/test-app-webbridge/src/main/res/drawable-v24/ic_launcher_foreground.xml diff --git a/Adjust/testapp/src/main/res/drawable/ic_launcher_background.xml b/Adjust/test-app-webbridge/src/main/res/drawable/ic_launcher_background.xml similarity index 100% rename from Adjust/testapp/src/main/res/drawable/ic_launcher_background.xml rename to Adjust/test-app-webbridge/src/main/res/drawable/ic_launcher_background.xml diff --git a/Adjust/testapp-webbridge/src/main/res/layout/activity_main.xml b/Adjust/test-app-webbridge/src/main/res/layout/activity_main.xml similarity index 100% rename from Adjust/testapp-webbridge/src/main/res/layout/activity_main.xml rename to Adjust/test-app-webbridge/src/main/res/layout/activity_main.xml diff --git a/Adjust/testapp/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/Adjust/test-app-webbridge/src/main/res/mipmap-anydpi-v26/ic_launcher.xml similarity index 100% rename from Adjust/testapp/src/main/res/mipmap-anydpi-v26/ic_launcher.xml rename to Adjust/test-app-webbridge/src/main/res/mipmap-anydpi-v26/ic_launcher.xml diff --git a/Adjust/testapp/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/Adjust/test-app-webbridge/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml similarity index 100% rename from Adjust/testapp/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml rename to Adjust/test-app-webbridge/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml diff --git a/Adjust/testapp/src/main/res/mipmap-hdpi/ic_launcher.png b/Adjust/test-app-webbridge/src/main/res/mipmap-hdpi/ic_launcher.png similarity index 100% rename from Adjust/testapp/src/main/res/mipmap-hdpi/ic_launcher.png rename to Adjust/test-app-webbridge/src/main/res/mipmap-hdpi/ic_launcher.png diff --git a/Adjust/testapp/src/main/res/mipmap-hdpi/ic_launcher_round.png b/Adjust/test-app-webbridge/src/main/res/mipmap-hdpi/ic_launcher_round.png similarity index 100% rename from Adjust/testapp/src/main/res/mipmap-hdpi/ic_launcher_round.png rename to Adjust/test-app-webbridge/src/main/res/mipmap-hdpi/ic_launcher_round.png diff --git a/Adjust/testapp/src/main/res/mipmap-mdpi/ic_launcher.png b/Adjust/test-app-webbridge/src/main/res/mipmap-mdpi/ic_launcher.png similarity index 100% rename from Adjust/testapp/src/main/res/mipmap-mdpi/ic_launcher.png rename to Adjust/test-app-webbridge/src/main/res/mipmap-mdpi/ic_launcher.png diff --git a/Adjust/testapp/src/main/res/mipmap-mdpi/ic_launcher_round.png b/Adjust/test-app-webbridge/src/main/res/mipmap-mdpi/ic_launcher_round.png similarity index 100% rename from Adjust/testapp/src/main/res/mipmap-mdpi/ic_launcher_round.png rename to Adjust/test-app-webbridge/src/main/res/mipmap-mdpi/ic_launcher_round.png diff --git a/Adjust/testapp/src/main/res/mipmap-xhdpi/ic_launcher.png b/Adjust/test-app-webbridge/src/main/res/mipmap-xhdpi/ic_launcher.png similarity index 100% rename from Adjust/testapp/src/main/res/mipmap-xhdpi/ic_launcher.png rename to Adjust/test-app-webbridge/src/main/res/mipmap-xhdpi/ic_launcher.png diff --git a/Adjust/testapp/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/Adjust/test-app-webbridge/src/main/res/mipmap-xhdpi/ic_launcher_round.png similarity index 100% rename from Adjust/testapp/src/main/res/mipmap-xhdpi/ic_launcher_round.png rename to Adjust/test-app-webbridge/src/main/res/mipmap-xhdpi/ic_launcher_round.png diff --git a/Adjust/testapp/src/main/res/mipmap-xxhdpi/ic_launcher.png b/Adjust/test-app-webbridge/src/main/res/mipmap-xxhdpi/ic_launcher.png similarity index 100% rename from Adjust/testapp/src/main/res/mipmap-xxhdpi/ic_launcher.png rename to Adjust/test-app-webbridge/src/main/res/mipmap-xxhdpi/ic_launcher.png diff --git a/Adjust/testapp/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/Adjust/test-app-webbridge/src/main/res/mipmap-xxhdpi/ic_launcher_round.png similarity index 100% rename from Adjust/testapp/src/main/res/mipmap-xxhdpi/ic_launcher_round.png rename to Adjust/test-app-webbridge/src/main/res/mipmap-xxhdpi/ic_launcher_round.png diff --git a/Adjust/testapp/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/Adjust/test-app-webbridge/src/main/res/mipmap-xxxhdpi/ic_launcher.png similarity index 100% rename from Adjust/testapp/src/main/res/mipmap-xxxhdpi/ic_launcher.png rename to Adjust/test-app-webbridge/src/main/res/mipmap-xxxhdpi/ic_launcher.png diff --git a/Adjust/testapp/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/Adjust/test-app-webbridge/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png similarity index 100% rename from Adjust/testapp/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png rename to Adjust/test-app-webbridge/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png diff --git a/Adjust/testapp/src/main/res/values/colors.xml b/Adjust/test-app-webbridge/src/main/res/values/colors.xml similarity index 100% rename from Adjust/testapp/src/main/res/values/colors.xml rename to Adjust/test-app-webbridge/src/main/res/values/colors.xml diff --git a/Adjust/testapp-webbridge/src/main/res/values/strings.xml b/Adjust/test-app-webbridge/src/main/res/values/strings.xml similarity index 100% rename from Adjust/testapp-webbridge/src/main/res/values/strings.xml rename to Adjust/test-app-webbridge/src/main/res/values/strings.xml diff --git a/Adjust/testapp/src/main/res/values/styles.xml b/Adjust/test-app-webbridge/src/main/res/values/styles.xml similarity index 100% rename from Adjust/testapp/src/main/res/values/styles.xml rename to Adjust/test-app-webbridge/src/main/res/values/styles.xml diff --git a/Adjust/testapp-webbridge/src/test/java/com/example/testappwebbridge/ExampleUnitTest.java b/Adjust/test-app-webbridge/src/test/java/com/example/testappwebbridge/ExampleUnitTest.java similarity index 100% rename from Adjust/testapp-webbridge/src/test/java/com/example/testappwebbridge/ExampleUnitTest.java rename to Adjust/test-app-webbridge/src/test/java/com/example/testappwebbridge/ExampleUnitTest.java diff --git a/Adjust/test-kotlin/.gitignore b/Adjust/test-kotlin/.gitignore new file mode 100644 index 000000000..796b96d1c --- /dev/null +++ b/Adjust/test-kotlin/.gitignore @@ -0,0 +1 @@ +/build diff --git a/Adjust/test-kotlin/build.gradle b/Adjust/test-kotlin/build.gradle new file mode 100644 index 000000000..3e59f1436 --- /dev/null +++ b/Adjust/test-kotlin/build.gradle @@ -0,0 +1,33 @@ +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply plugin: 'kotlin-android-extensions' +android { + compileSdkVersion 28 + + defaultConfig { + applicationId "com.adjust.sdk.test" + targetSdkVersion 28 + minSdkVersion 9 + + testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" + + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } + +} + +dependencies { + implementation fileTree(dir: 'libs', include: ['*.jar']) + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" + testImplementation 'junit:junit:4.12' + androidTestImplementation 'com.android.support.test:runner:1.0.2' + androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' + + testImplementation project(path: ':sdk-core') +} diff --git a/Adjust/test-kotlin/proguard-rules.pro b/Adjust/test-kotlin/proguard-rules.pro new file mode 100644 index 000000000..f1b424510 --- /dev/null +++ b/Adjust/test-kotlin/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile diff --git a/Adjust/test-kotlin/src/androidTest/java/com/adjust/sdk/test/ExampleInstrumentedTest.kt b/Adjust/test-kotlin/src/androidTest/java/com/adjust/sdk/test/ExampleInstrumentedTest.kt new file mode 100644 index 000000000..835fa8f15 --- /dev/null +++ b/Adjust/test-kotlin/src/androidTest/java/com/adjust/sdk/test/ExampleInstrumentedTest.kt @@ -0,0 +1,24 @@ +package com.adjust.sdk.test + +import android.support.test.InstrumentationRegistry +import android.support.test.runner.AndroidJUnit4 + +import org.junit.Test +import org.junit.runner.RunWith + +import org.junit.Assert.* + +/** + * Instrumented test, which will execute on an Android device. + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +@RunWith(AndroidJUnit4::class) +class ExampleInstrumentedTest { + @Test + fun useAppContext() { + // Context of the app under test. + val appContext = InstrumentationRegistry.getTargetContext() + assertEquals("com.adjust.sdk.test", appContext.packageName) + } +} diff --git a/Adjust/test-kotlin/src/main/AndroidManifest.xml b/Adjust/test-kotlin/src/main/AndroidManifest.xml new file mode 100644 index 000000000..c10afac2d --- /dev/null +++ b/Adjust/test-kotlin/src/main/AndroidManifest.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Adjust/test-kotlin/src/main/java/com/adjust/sdk/test/MainActivity.kt b/Adjust/test-kotlin/src/main/java/com/adjust/sdk/test/MainActivity.kt new file mode 100644 index 000000000..74176cd4b --- /dev/null +++ b/Adjust/test-kotlin/src/main/java/com/adjust/sdk/test/MainActivity.kt @@ -0,0 +1,11 @@ +package com.adjust.sdk.test + +import android.app.Activity +import android.os.Bundle + +class MainActivity : Activity() { + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + } +} diff --git a/Adjust/test-kotlin/src/main/res/drawable-v24/ic_launcher_foreground.xml b/Adjust/test-kotlin/src/main/res/drawable-v24/ic_launcher_foreground.xml new file mode 100644 index 000000000..1f6bb2906 --- /dev/null +++ b/Adjust/test-kotlin/src/main/res/drawable-v24/ic_launcher_foreground.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + diff --git a/Adjust/test-kotlin/src/main/res/drawable/ic_launcher_background.xml b/Adjust/test-kotlin/src/main/res/drawable/ic_launcher_background.xml new file mode 100644 index 000000000..0d025f9bf --- /dev/null +++ b/Adjust/test-kotlin/src/main/res/drawable/ic_launcher_background.xml @@ -0,0 +1,170 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Adjust/test-kotlin/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/Adjust/test-kotlin/src/main/res/mipmap-anydpi-v26/ic_launcher.xml new file mode 100644 index 000000000..eca70cfe5 --- /dev/null +++ b/Adjust/test-kotlin/src/main/res/mipmap-anydpi-v26/ic_launcher.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/Adjust/test-kotlin/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/Adjust/test-kotlin/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml new file mode 100644 index 000000000..eca70cfe5 --- /dev/null +++ b/Adjust/test-kotlin/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/Adjust/test-kotlin/src/main/res/mipmap-hdpi/ic_launcher.png b/Adjust/test-kotlin/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 000000000..898f3ed59 Binary files /dev/null and b/Adjust/test-kotlin/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/Adjust/test-kotlin/src/main/res/mipmap-hdpi/ic_launcher_round.png b/Adjust/test-kotlin/src/main/res/mipmap-hdpi/ic_launcher_round.png new file mode 100644 index 000000000..dffca3601 Binary files /dev/null and b/Adjust/test-kotlin/src/main/res/mipmap-hdpi/ic_launcher_round.png differ diff --git a/Adjust/test-kotlin/src/main/res/mipmap-mdpi/ic_launcher.png b/Adjust/test-kotlin/src/main/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 000000000..64ba76f75 Binary files /dev/null and b/Adjust/test-kotlin/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/Adjust/test-kotlin/src/main/res/mipmap-mdpi/ic_launcher_round.png b/Adjust/test-kotlin/src/main/res/mipmap-mdpi/ic_launcher_round.png new file mode 100644 index 000000000..dae5e0823 Binary files /dev/null and b/Adjust/test-kotlin/src/main/res/mipmap-mdpi/ic_launcher_round.png differ diff --git a/Adjust/test-kotlin/src/main/res/mipmap-xhdpi/ic_launcher.png b/Adjust/test-kotlin/src/main/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 000000000..e5ed46597 Binary files /dev/null and b/Adjust/test-kotlin/src/main/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/Adjust/test-kotlin/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/Adjust/test-kotlin/src/main/res/mipmap-xhdpi/ic_launcher_round.png new file mode 100644 index 000000000..14ed0af35 Binary files /dev/null and b/Adjust/test-kotlin/src/main/res/mipmap-xhdpi/ic_launcher_round.png differ diff --git a/Adjust/test-kotlin/src/main/res/mipmap-xxhdpi/ic_launcher.png b/Adjust/test-kotlin/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 000000000..b0907cac3 Binary files /dev/null and b/Adjust/test-kotlin/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/Adjust/test-kotlin/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/Adjust/test-kotlin/src/main/res/mipmap-xxhdpi/ic_launcher_round.png new file mode 100644 index 000000000..d8ae03154 Binary files /dev/null and b/Adjust/test-kotlin/src/main/res/mipmap-xxhdpi/ic_launcher_round.png differ diff --git a/Adjust/test-kotlin/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/Adjust/test-kotlin/src/main/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 000000000..2c18de9e6 Binary files /dev/null and b/Adjust/test-kotlin/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/Adjust/test-kotlin/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/Adjust/test-kotlin/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png new file mode 100644 index 000000000..beed3cdd2 Binary files /dev/null and b/Adjust/test-kotlin/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png differ diff --git a/Adjust/test-kotlin/src/main/res/values/colors.xml b/Adjust/test-kotlin/src/main/res/values/colors.xml new file mode 100644 index 000000000..69b22338c --- /dev/null +++ b/Adjust/test-kotlin/src/main/res/values/colors.xml @@ -0,0 +1,6 @@ + + + #008577 + #00574B + #D81B60 + diff --git a/Adjust/test-kotlin/src/main/res/values/strings.xml b/Adjust/test-kotlin/src/main/res/values/strings.xml new file mode 100644 index 000000000..7a6b55c64 --- /dev/null +++ b/Adjust/test-kotlin/src/main/res/values/strings.xml @@ -0,0 +1,3 @@ + + test-unit-kotlin + diff --git a/Adjust/test-kotlin/src/main/res/values/styles.xml b/Adjust/test-kotlin/src/main/res/values/styles.xml new file mode 100644 index 000000000..e84bc5ec1 --- /dev/null +++ b/Adjust/test-kotlin/src/main/res/values/styles.xml @@ -0,0 +1,8 @@ + + + + + + diff --git a/Adjust/test-kotlin/src/test/java/com/adjust/sdk/test/SchedulerTest.kt b/Adjust/test-kotlin/src/test/java/com/adjust/sdk/test/SchedulerTest.kt new file mode 100644 index 000000000..20d6d63c9 --- /dev/null +++ b/Adjust/test-kotlin/src/test/java/com/adjust/sdk/test/SchedulerTest.kt @@ -0,0 +1,105 @@ +package com.adjust.sdk.test + +import com.adjust.sdk.scheduler.* +import org.junit.Assert +import org.junit.Test +import java.util.concurrent.TimeUnit + +class SchedulerTest { + @Test + fun threadExecutor_submitsVarious_executesInOrder() { + val threadExecutor: ThreadExecutor = SingleThreadCachedScheduler("s") + var s = ""; + threadExecutor.submit { s += "a" } + threadExecutor.submit { s += "b" } + threadExecutor.submit { s += "c" } + Thread.sleep(1000) + Assert.assertEquals("abc", s) + } + + @Test + fun threadScheduler_schedulesVariousDelayed_executesInDelayedOrder() { + val threadScheduler: ThreadScheduler = SingleThreadCachedScheduler("s") + var s = ""; + threadScheduler.submit { s += "a" } + threadScheduler.schedule ({ s += "e"}, 500) + threadScheduler.submit { s += "b" } + threadScheduler.schedule ({ s += "d"}, 250) + threadScheduler.submit { s += "c" } + Thread.sleep(1000) + Assert.assertEquals("abcde", s) + } + + @Test + fun futureScheduler_ScheduleAndWaitWithKeepAlive() { + // arrange + val futureScheduler: FutureScheduler = SingleThreadFutureScheduler("s", true) + + // act + var s = ""; + val scheduledFuture = futureScheduler.scheduleFuture({ s += "a" }, 500) + + val withDelay = scheduledFuture.getDelay(TimeUnit.MILLISECONDS) + val isNotDone = scheduledFuture.isDone + val isNotCanceledBefore = scheduledFuture.isCancelled + // wait for finish + scheduledFuture.get() + + val noDelay = scheduledFuture.getDelay(TimeUnit.MILLISECONDS) + val isDone = scheduledFuture.isDone + val isNotCanceledBeforeAfter = scheduledFuture.isCancelled + + // assert + // before finish + Assert.assertTrue(withDelay > 0L) + Assert.assertTrue(withDelay < 500L) + Assert.assertTrue(noDelay <= 0L) + Assert.assertFalse(isNotDone) + + // after finish + Assert.assertEquals("a", s) + Assert.assertTrue(isDone) + Assert.assertFalse(isNotCanceledBefore) + Assert.assertFalse(isNotCanceledBeforeAfter) + } + + @Test + fun futureScheduler_ScheduleAndCancelWithKeepAlive() { + // arrange + val futureScheduler: FutureScheduler = SingleThreadFutureScheduler("s", true) + + // act + var s = ""; + val scheduledFuture = futureScheduler.scheduleFuture({ s += "a" }, 500) + + // cancel + scheduledFuture.cancel(false) + + val isDone = scheduledFuture.isDone + val isCancelled = scheduledFuture.isCancelled + + // assert + Assert.assertEquals("", s) + Assert.assertTrue(isDone) + Assert.assertTrue(isCancelled) + } + + @Test + fun futureScheduler_ScheduleWithFixedDelayWithKeepAlive() { + // arrange + val futureScheduler: FutureScheduler = SingleThreadFutureScheduler("s", true) + + // act + var s = ""; + val scheduledFuture = futureScheduler.scheduleFutureWithFixedDelay({ s += "a" }, 500, 500) + + Thread.sleep(650) + val s1 = s + Thread.sleep(650) + + // assert + Assert.assertEquals("a", s1) + Assert.assertEquals("aa", s) + } + +} \ No newline at end of file diff --git a/Adjust/test-library/.gitignore b/Adjust/test-library/.gitignore new file mode 100644 index 000000000..796b96d1c --- /dev/null +++ b/Adjust/test-library/.gitignore @@ -0,0 +1 @@ +/build diff --git a/Adjust/test-library/build.gradle b/Adjust/test-library/build.gradle new file mode 100644 index 000000000..bc98b40d9 --- /dev/null +++ b/Adjust/test-library/build.gradle @@ -0,0 +1,42 @@ +apply plugin: 'com.android.library' + +android { + compileSdkVersion 28 + + defaultConfig { + minSdkVersion 9 + targetSdkVersion 28 + versionCode 1 + versionName "1.0" + } +} + +dependencies { + implementation fileTree(dir: 'libs', include: ['*.jar']) + implementation 'com.google.code.gson:gson:2.8.5' +} + +task adjustClearJarDebug(type: Delete) { + delete "build/outputs/test-library-debug.jar" +} + +task adjustClearJarRelease(type: Delete) { + delete "build/outputs/test-library-release.jar" +} + +task adjustMakeJarDebug(type: Copy) { + from('build/intermediates/intermediate-jars/debug/') + into('build/libs/') + include('classes.jar') + rename('classes.jar', "test-library-debug.jar") +} + +task adjustMakeJarRelease(type: Copy) { + from('build/intermediates/intermediate-jars/release/') + into('build/libs/') + include('classes.jar') + rename('classes.jar', "test-library-release.jar") +} + +adjustMakeJarDebug.dependsOn(adjustClearJarDebug, build) +adjustMakeJarRelease.dependsOn(adjustClearJarRelease, build) diff --git a/Adjust/test-library/proguard-rules.pro b/Adjust/test-library/proguard-rules.pro new file mode 100644 index 000000000..f1b424510 --- /dev/null +++ b/Adjust/test-library/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile diff --git a/Adjust/testlibrary/src/main/AndroidManifest.xml b/Adjust/test-library/src/main/AndroidManifest.xml similarity index 100% rename from Adjust/testlibrary/src/main/AndroidManifest.xml rename to Adjust/test-library/src/main/AndroidManifest.xml diff --git a/Adjust/testlibrary/src/main/java/com/adjust/testlibrary/Constants.java b/Adjust/test-library/src/main/java/com/adjust/test/Constants.java similarity index 94% rename from Adjust/testlibrary/src/main/java/com/adjust/testlibrary/Constants.java rename to Adjust/test-library/src/main/java/com/adjust/test/Constants.java index 0d1b894a9..436ec1361 100644 --- a/Adjust/testlibrary/src/main/java/com/adjust/testlibrary/Constants.java +++ b/Adjust/test-library/src/main/java/com/adjust/test/Constants.java @@ -1,4 +1,4 @@ -package com.adjust.testlibrary; +package com.adjust.test; /** * Created by nonelse on 09.03.17. diff --git a/Adjust/testlibrary/src/main/java/com/adjust/testlibrary/ControlChannel.java b/Adjust/test-library/src/main/java/com/adjust/test/ControlChannel.java similarity index 90% rename from Adjust/testlibrary/src/main/java/com/adjust/testlibrary/ControlChannel.java rename to Adjust/test-library/src/main/java/com/adjust/test/ControlChannel.java index 3b8e50956..f54ba3302 100644 --- a/Adjust/testlibrary/src/main/java/com/adjust/testlibrary/ControlChannel.java +++ b/Adjust/test-library/src/main/java/com/adjust/test/ControlChannel.java @@ -1,13 +1,13 @@ -package com.adjust.testlibrary; +package com.adjust.test; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; -import static com.adjust.testlibrary.Constants.TEST_CANCELTEST_HEADER; -import static com.adjust.testlibrary.Constants.TEST_ENDWAIT_HEADER; -import static com.adjust.testlibrary.Utils.debug; -import static com.adjust.testlibrary.UtilsNetworking.sendPostI; +import static com.adjust.test.Constants.TEST_CANCELTEST_HEADER; +import static com.adjust.test.Constants.TEST_ENDWAIT_HEADER; +import static com.adjust.test.Utils.debug; +import static com.adjust.test.UtilsNetworking.sendPostI; /** * Created by nonelse on 21.03.17. diff --git a/Adjust/testlibrary/src/main/java/com/adjust/testlibrary/ICommandJsonListener.java b/Adjust/test-library/src/main/java/com/adjust/test/ICommandJsonListener.java similarity index 84% rename from Adjust/testlibrary/src/main/java/com/adjust/testlibrary/ICommandJsonListener.java rename to Adjust/test-library/src/main/java/com/adjust/test/ICommandJsonListener.java index 0ba75f5e1..b43d199b5 100644 --- a/Adjust/testlibrary/src/main/java/com/adjust/testlibrary/ICommandJsonListener.java +++ b/Adjust/test-library/src/main/java/com/adjust/test/ICommandJsonListener.java @@ -1,4 +1,4 @@ -package com.adjust.testlibrary; +package com.adjust.test; /** * Created by nonelse on 10.03.17. diff --git a/Adjust/testlibrary/src/main/java/com/adjust/testlibrary/ICommandListener.java b/Adjust/test-library/src/main/java/com/adjust/test/ICommandListener.java similarity index 87% rename from Adjust/testlibrary/src/main/java/com/adjust/testlibrary/ICommandListener.java rename to Adjust/test-library/src/main/java/com/adjust/test/ICommandListener.java index ea8f16590..f13fcb288 100644 --- a/Adjust/testlibrary/src/main/java/com/adjust/testlibrary/ICommandListener.java +++ b/Adjust/test-library/src/main/java/com/adjust/test/ICommandListener.java @@ -1,4 +1,4 @@ -package com.adjust.testlibrary; +package com.adjust.test; import java.util.List; import java.util.Map; diff --git a/Adjust/testlibrary/src/main/java/com/adjust/testlibrary/ICommandRawJsonListener.java b/Adjust/test-library/src/main/java/com/adjust/test/ICommandRawJsonListener.java similarity index 80% rename from Adjust/testlibrary/src/main/java/com/adjust/testlibrary/ICommandRawJsonListener.java rename to Adjust/test-library/src/main/java/com/adjust/test/ICommandRawJsonListener.java index c74e3e0d5..694eb08a9 100644 --- a/Adjust/testlibrary/src/main/java/com/adjust/testlibrary/ICommandRawJsonListener.java +++ b/Adjust/test-library/src/main/java/com/adjust/test/ICommandRawJsonListener.java @@ -1,4 +1,4 @@ -package com.adjust.testlibrary; +package com.adjust.test; /** * Created by nonelse on 10.03.17. diff --git a/Adjust/testlibrary/src/main/java/com/adjust/testlibrary/IOnExitListener.java b/Adjust/test-library/src/main/java/com/adjust/test/IOnExitListener.java similarity index 75% rename from Adjust/testlibrary/src/main/java/com/adjust/testlibrary/IOnExitListener.java rename to Adjust/test-library/src/main/java/com/adjust/test/IOnExitListener.java index 86126a9fd..579095cf3 100644 --- a/Adjust/testlibrary/src/main/java/com/adjust/testlibrary/IOnExitListener.java +++ b/Adjust/test-library/src/main/java/com/adjust/test/IOnExitListener.java @@ -1,4 +1,4 @@ -package com.adjust.testlibrary; +package com.adjust.test; /** * Created by nonelse on 09.03.17. diff --git a/Adjust/testlibrary/src/main/java/com/adjust/testlibrary/TestCommand.java b/Adjust/test-library/src/main/java/com/adjust/test/TestCommand.java similarity index 87% rename from Adjust/testlibrary/src/main/java/com/adjust/testlibrary/TestCommand.java rename to Adjust/test-library/src/main/java/com/adjust/test/TestCommand.java index ca53bed81..ec4d9036f 100644 --- a/Adjust/testlibrary/src/main/java/com/adjust/testlibrary/TestCommand.java +++ b/Adjust/test-library/src/main/java/com/adjust/test/TestCommand.java @@ -1,4 +1,4 @@ -package com.adjust.testlibrary; +package com.adjust.test; import java.util.List; import java.util.Map; diff --git a/Adjust/testlibrary/src/main/java/com/adjust/testlibrary/TestLibrary.java b/Adjust/test-library/src/main/java/com/adjust/test/TestLibrary.java similarity index 96% rename from Adjust/testlibrary/src/main/java/com/adjust/testlibrary/TestLibrary.java rename to Adjust/test-library/src/main/java/com/adjust/test/TestLibrary.java index e4ccca73b..1a4869585 100644 --- a/Adjust/testlibrary/src/main/java/com/adjust/testlibrary/TestLibrary.java +++ b/Adjust/test-library/src/main/java/com/adjust/test/TestLibrary.java @@ -1,4 +1,4 @@ -package com.adjust.testlibrary; +package com.adjust.test; import android.os.SystemClock; @@ -15,11 +15,11 @@ import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.TimeUnit; -import static com.adjust.testlibrary.Constants.TEST_LIBRARY_CLASSNAME; -import static com.adjust.testlibrary.Constants.WAIT_FOR_CONTROL; -import static com.adjust.testlibrary.Constants.WAIT_FOR_SLEEP; -import static com.adjust.testlibrary.Utils.debug; -import static com.adjust.testlibrary.UtilsNetworking.sendPostI; +import static com.adjust.test.Constants.TEST_LIBRARY_CLASSNAME; +import static com.adjust.test.Constants.WAIT_FOR_CONTROL; +import static com.adjust.test.Constants.WAIT_FOR_SLEEP; +import static com.adjust.test.Utils.debug; +import static com.adjust.test.UtilsNetworking.sendPostI; /** diff --git a/Adjust/testlibrary/src/main/java/com/adjust/testlibrary/Utils.java b/Adjust/test-library/src/main/java/com/adjust/test/Utils.java similarity index 69% rename from Adjust/testlibrary/src/main/java/com/adjust/testlibrary/Utils.java rename to Adjust/test-library/src/main/java/com/adjust/test/Utils.java index 524b7f697..050697581 100644 --- a/Adjust/testlibrary/src/main/java/com/adjust/testlibrary/Utils.java +++ b/Adjust/test-library/src/main/java/com/adjust/test/Utils.java @@ -1,20 +1,11 @@ -package com.adjust.testlibrary; +package com.adjust.test; import android.util.Log; -import java.io.IOException; -import java.io.UnsupportedEncodingException; -import java.net.URLEncoder; import java.util.Arrays; import java.util.Locale; -import java.util.Map; -import javax.net.ssl.HttpsURLConnection; - -import static com.adjust.testlibrary.Constants.LOGTAG; -import static com.adjust.testlibrary.UtilsNetworking.connectionOptions; -import static com.adjust.testlibrary.UtilsNetworking.createPOSTHttpsURLConnection; -import static com.adjust.testlibrary.UtilsNetworking.readHttpResponse; +import static com.adjust.test.Constants.LOGTAG; /** * Created by nonelse on 11.03.17. diff --git a/Adjust/testlibrary/src/main/java/com/adjust/testlibrary/UtilsNetworking.java b/Adjust/test-library/src/main/java/com/adjust/test/UtilsNetworking.java similarity index 97% rename from Adjust/testlibrary/src/main/java/com/adjust/testlibrary/UtilsNetworking.java rename to Adjust/test-library/src/main/java/com/adjust/test/UtilsNetworking.java index c12a878b4..ab622f9b9 100644 --- a/Adjust/testlibrary/src/main/java/com/adjust/testlibrary/UtilsNetworking.java +++ b/Adjust/test-library/src/main/java/com/adjust/test/UtilsNetworking.java @@ -1,4 +1,4 @@ -package com.adjust.testlibrary; +package com.adjust.test; import java.io.BufferedReader; import java.io.DataOutputStream; @@ -21,9 +21,9 @@ import javax.net.ssl.TrustManager; import javax.net.ssl.X509TrustManager; -import static com.adjust.testlibrary.Constants.ONE_MINUTE; -import static com.adjust.testlibrary.Utils.debug; -import static com.adjust.testlibrary.Utils.error; +import static com.adjust.test.Constants.ONE_MINUTE; +import static com.adjust.test.Utils.debug; +import static com.adjust.test.Utils.error; /** * Created by uerceg on 03/04/2017. diff --git a/Adjust/testlibrary/src/main/res/values/strings.xml b/Adjust/test-library/src/main/res/values/strings.xml similarity index 100% rename from Adjust/testlibrary/src/main/res/values/strings.xml rename to Adjust/test-library/src/main/res/values/strings.xml diff --git a/Adjust/test/build.gradle b/Adjust/test-unit/build.gradle similarity index 51% rename from Adjust/test/build.gradle rename to Adjust/test-unit/build.gradle index ba075580c..d4ba50de1 100644 --- a/Adjust/test/build.gradle +++ b/Adjust/test-unit/build.gradle @@ -1,12 +1,11 @@ apply plugin: 'com.android.library' android { - compileSdkVersion 25 - buildToolsVersion '27.0.3' + compileSdkVersion 28 defaultConfig { minSdkVersion 9 - targetSdkVersion 25 + targetSdkVersion 28 } defaultConfig { testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" @@ -18,11 +17,10 @@ repositories { } dependencies { - implementation 'com.google.code.gson:gson:2.4' - implementation 'com.google.android.gms:play-services-analytics:9.8.0' + implementation 'com.google.code.gson:gson:2.8.5' + implementation 'com.google.android.gms:play-services-analytics:16.0.4' implementation fileTree(dir: 'libs', include: ['*.jar']) - implementation project(':adjust') - androidTestImplementation 'com.android.support.test:runner:0.5' - // Set this dependency to use JUnit 4 rules - androidTestImplementation 'com.android.support.test:rules:0.5' + implementation project(':sdk-core') + androidTestImplementation 'com.android.support.test:runner:1.0.2' + androidTestImplementation 'com.android.support.test:rules:1.0.2' } diff --git a/Adjust/test/src/androidTest/java/com/adjust/sdk/ApplicationTest.java b/Adjust/test-unit/src/androidTest/java/com/adjust/sdk/ApplicationTest.java similarity index 100% rename from Adjust/test/src/androidTest/java/com/adjust/sdk/ApplicationTest.java rename to Adjust/test-unit/src/androidTest/java/com/adjust/sdk/ApplicationTest.java diff --git a/Adjust/test/src/androidTest/java/com/adjust/sdk/AssertUtil.java b/Adjust/test-unit/src/androidTest/java/com/adjust/sdk/AssertUtil.java similarity index 100% rename from Adjust/test/src/androidTest/java/com/adjust/sdk/AssertUtil.java rename to Adjust/test-unit/src/androidTest/java/com/adjust/sdk/AssertUtil.java diff --git a/Adjust/test/src/androidTest/java/com/adjust/sdk/MockActivityHandler.java b/Adjust/test-unit/src/androidTest/java/com/adjust/sdk/MockActivityHandler.java similarity index 100% rename from Adjust/test/src/androidTest/java/com/adjust/sdk/MockActivityHandler.java rename to Adjust/test-unit/src/androidTest/java/com/adjust/sdk/MockActivityHandler.java diff --git a/Adjust/test/src/androidTest/java/com/adjust/sdk/MockAttributionHandler.java b/Adjust/test-unit/src/androidTest/java/com/adjust/sdk/MockAttributionHandler.java similarity index 100% rename from Adjust/test/src/androidTest/java/com/adjust/sdk/MockAttributionHandler.java rename to Adjust/test-unit/src/androidTest/java/com/adjust/sdk/MockAttributionHandler.java diff --git a/Adjust/test/src/androidTest/java/com/adjust/sdk/MockHttpsURLConnection.java b/Adjust/test-unit/src/androidTest/java/com/adjust/sdk/MockHttpsURLConnection.java similarity index 100% rename from Adjust/test/src/androidTest/java/com/adjust/sdk/MockHttpsURLConnection.java rename to Adjust/test-unit/src/androidTest/java/com/adjust/sdk/MockHttpsURLConnection.java diff --git a/Adjust/test/src/androidTest/java/com/adjust/sdk/MockLogger.java b/Adjust/test-unit/src/androidTest/java/com/adjust/sdk/MockLogger.java similarity index 100% rename from Adjust/test/src/androidTest/java/com/adjust/sdk/MockLogger.java rename to Adjust/test-unit/src/androidTest/java/com/adjust/sdk/MockLogger.java diff --git a/Adjust/test/src/androidTest/java/com/adjust/sdk/MockPackageHandler.java b/Adjust/test-unit/src/androidTest/java/com/adjust/sdk/MockPackageHandler.java similarity index 100% rename from Adjust/test/src/androidTest/java/com/adjust/sdk/MockPackageHandler.java rename to Adjust/test-unit/src/androidTest/java/com/adjust/sdk/MockPackageHandler.java diff --git a/Adjust/test/src/androidTest/java/com/adjust/sdk/MockRequestHandler.java b/Adjust/test-unit/src/androidTest/java/com/adjust/sdk/MockRequestHandler.java similarity index 100% rename from Adjust/test/src/androidTest/java/com/adjust/sdk/MockRequestHandler.java rename to Adjust/test-unit/src/androidTest/java/com/adjust/sdk/MockRequestHandler.java diff --git a/Adjust/test/src/androidTest/java/com/adjust/sdk/MockSdkClickHandler.java b/Adjust/test-unit/src/androidTest/java/com/adjust/sdk/MockSdkClickHandler.java similarity index 100% rename from Adjust/test/src/androidTest/java/com/adjust/sdk/MockSdkClickHandler.java rename to Adjust/test-unit/src/androidTest/java/com/adjust/sdk/MockSdkClickHandler.java diff --git a/Adjust/test/src/androidTest/java/com/adjust/sdk/ResponseType.java b/Adjust/test-unit/src/androidTest/java/com/adjust/sdk/ResponseType.java similarity index 100% rename from Adjust/test/src/androidTest/java/com/adjust/sdk/ResponseType.java rename to Adjust/test-unit/src/androidTest/java/com/adjust/sdk/ResponseType.java diff --git a/Adjust/test/src/androidTest/java/com/adjust/sdk/StateActivityHandlerConstructor.java b/Adjust/test-unit/src/androidTest/java/com/adjust/sdk/StateActivityHandlerConstructor.java similarity index 100% rename from Adjust/test/src/androidTest/java/com/adjust/sdk/StateActivityHandlerConstructor.java rename to Adjust/test-unit/src/androidTest/java/com/adjust/sdk/StateActivityHandlerConstructor.java diff --git a/Adjust/test/src/androidTest/java/com/adjust/sdk/StateActivityHandlerInit.java b/Adjust/test-unit/src/androidTest/java/com/adjust/sdk/StateActivityHandlerInit.java similarity index 100% rename from Adjust/test/src/androidTest/java/com/adjust/sdk/StateActivityHandlerInit.java rename to Adjust/test-unit/src/androidTest/java/com/adjust/sdk/StateActivityHandlerInit.java diff --git a/Adjust/test/src/androidTest/java/com/adjust/sdk/StateDelegates.java b/Adjust/test-unit/src/androidTest/java/com/adjust/sdk/StateDelegates.java similarity index 100% rename from Adjust/test/src/androidTest/java/com/adjust/sdk/StateDelegates.java rename to Adjust/test-unit/src/androidTest/java/com/adjust/sdk/StateDelegates.java diff --git a/Adjust/test/src/androidTest/java/com/adjust/sdk/StateEndSession.java b/Adjust/test-unit/src/androidTest/java/com/adjust/sdk/StateEndSession.java similarity index 100% rename from Adjust/test/src/androidTest/java/com/adjust/sdk/StateEndSession.java rename to Adjust/test-unit/src/androidTest/java/com/adjust/sdk/StateEndSession.java diff --git a/Adjust/test/src/androidTest/java/com/adjust/sdk/StateEvent.java b/Adjust/test-unit/src/androidTest/java/com/adjust/sdk/StateEvent.java similarity index 100% rename from Adjust/test/src/androidTest/java/com/adjust/sdk/StateEvent.java rename to Adjust/test-unit/src/androidTest/java/com/adjust/sdk/StateEvent.java diff --git a/Adjust/test/src/androidTest/java/com/adjust/sdk/StateSession.java b/Adjust/test-unit/src/androidTest/java/com/adjust/sdk/StateSession.java similarity index 100% rename from Adjust/test/src/androidTest/java/com/adjust/sdk/StateSession.java rename to Adjust/test-unit/src/androidTest/java/com/adjust/sdk/StateSession.java diff --git a/Adjust/test/src/androidTest/java/com/adjust/sdk/TestActivityHandler.java b/Adjust/test-unit/src/androidTest/java/com/adjust/sdk/TestActivityHandler.java similarity index 100% rename from Adjust/test/src/androidTest/java/com/adjust/sdk/TestActivityHandler.java rename to Adjust/test-unit/src/androidTest/java/com/adjust/sdk/TestActivityHandler.java diff --git a/Adjust/test/src/androidTest/java/com/adjust/sdk/TestActivityPackage.java b/Adjust/test-unit/src/androidTest/java/com/adjust/sdk/TestActivityPackage.java similarity index 99% rename from Adjust/test/src/androidTest/java/com/adjust/sdk/TestActivityPackage.java rename to Adjust/test-unit/src/androidTest/java/com/adjust/sdk/TestActivityPackage.java index 7ed5f8b57..4035c6307 100644 --- a/Adjust/test/src/androidTest/java/com/adjust/sdk/TestActivityPackage.java +++ b/Adjust/test-unit/src/androidTest/java/com/adjust/sdk/TestActivityPackage.java @@ -53,7 +53,7 @@ public TestActivityPackage(ActivityPackage activityPackage) { // default values appToken = "123456789012"; environment = "sandbox"; - clientSdk = "android4.15.1"; + clientSdk = "android4.16.0"; suffix = ""; attribution = new AdjustAttribution(); playServices = true; diff --git a/Adjust/test/src/androidTest/java/com/adjust/sdk/TestAttributionHandler.java b/Adjust/test-unit/src/androidTest/java/com/adjust/sdk/TestAttributionHandler.java similarity index 100% rename from Adjust/test/src/androidTest/java/com/adjust/sdk/TestAttributionHandler.java rename to Adjust/test-unit/src/androidTest/java/com/adjust/sdk/TestAttributionHandler.java diff --git a/Adjust/test/src/androidTest/java/com/adjust/sdk/TestPackageHandler.java b/Adjust/test-unit/src/androidTest/java/com/adjust/sdk/TestPackageHandler.java similarity index 100% rename from Adjust/test/src/androidTest/java/com/adjust/sdk/TestPackageHandler.java rename to Adjust/test-unit/src/androidTest/java/com/adjust/sdk/TestPackageHandler.java diff --git a/Adjust/test/src/androidTest/java/com/adjust/sdk/TestRequestHandler.java b/Adjust/test-unit/src/androidTest/java/com/adjust/sdk/TestRequestHandler.java similarity index 100% rename from Adjust/test/src/androidTest/java/com/adjust/sdk/TestRequestHandler.java rename to Adjust/test-unit/src/androidTest/java/com/adjust/sdk/TestRequestHandler.java diff --git a/Adjust/test/src/androidTest/java/com/adjust/sdk/TestSdkClickHandler.java b/Adjust/test-unit/src/androidTest/java/com/adjust/sdk/TestSdkClickHandler.java similarity index 100% rename from Adjust/test/src/androidTest/java/com/adjust/sdk/TestSdkClickHandler.java rename to Adjust/test-unit/src/androidTest/java/com/adjust/sdk/TestSdkClickHandler.java diff --git a/Adjust/test/src/main/AndroidManifest.xml b/Adjust/test-unit/src/main/AndroidManifest.xml similarity index 100% rename from Adjust/test/src/main/AndroidManifest.xml rename to Adjust/test-unit/src/main/AndroidManifest.xml diff --git a/Adjust/test/src/main/java/com/adjust/sdk/test/UnitTestActivity.java b/Adjust/test-unit/src/main/java/com/adjust/sdk/test/UnitTestActivity.java similarity index 100% rename from Adjust/test/src/main/java/com/adjust/sdk/test/UnitTestActivity.java rename to Adjust/test-unit/src/main/java/com/adjust/sdk/test/UnitTestActivity.java diff --git a/Adjust/test/src/main/res/drawable-hdpi/ic_launcher.png b/Adjust/test-unit/src/main/res/drawable-hdpi/ic_launcher.png similarity index 100% rename from Adjust/test/src/main/res/drawable-hdpi/ic_launcher.png rename to Adjust/test-unit/src/main/res/drawable-hdpi/ic_launcher.png diff --git a/Adjust/test/src/main/res/drawable-mdpi/ic_launcher.png b/Adjust/test-unit/src/main/res/drawable-mdpi/ic_launcher.png similarity index 100% rename from Adjust/test/src/main/res/drawable-mdpi/ic_launcher.png rename to Adjust/test-unit/src/main/res/drawable-mdpi/ic_launcher.png diff --git a/Adjust/test/src/main/res/drawable-xhdpi/ic_launcher.png b/Adjust/test-unit/src/main/res/drawable-xhdpi/ic_launcher.png similarity index 100% rename from Adjust/test/src/main/res/drawable-xhdpi/ic_launcher.png rename to Adjust/test-unit/src/main/res/drawable-xhdpi/ic_launcher.png diff --git a/Adjust/test/src/main/res/drawable-xxhdpi/ic_launcher.png b/Adjust/test-unit/src/main/res/drawable-xxhdpi/ic_launcher.png similarity index 100% rename from Adjust/test/src/main/res/drawable-xxhdpi/ic_launcher.png rename to Adjust/test-unit/src/main/res/drawable-xxhdpi/ic_launcher.png diff --git a/Adjust/test/src/main/res/layout/activity_unit_test.xml b/Adjust/test-unit/src/main/res/layout/activity_unit_test.xml similarity index 100% rename from Adjust/test/src/main/res/layout/activity_unit_test.xml rename to Adjust/test-unit/src/main/res/layout/activity_unit_test.xml diff --git a/Adjust/test/src/main/res/menu/menu_unit_test.xml b/Adjust/test-unit/src/main/res/menu/menu_unit_test.xml similarity index 100% rename from Adjust/test/src/main/res/menu/menu_unit_test.xml rename to Adjust/test-unit/src/main/res/menu/menu_unit_test.xml diff --git a/Adjust/test/src/main/res/values-w820dp/dimens.xml b/Adjust/test-unit/src/main/res/values-w820dp/dimens.xml similarity index 100% rename from Adjust/test/src/main/res/values-w820dp/dimens.xml rename to Adjust/test-unit/src/main/res/values-w820dp/dimens.xml diff --git a/Adjust/test/src/main/res/values/dimens.xml b/Adjust/test-unit/src/main/res/values/dimens.xml similarity index 100% rename from Adjust/test/src/main/res/values/dimens.xml rename to Adjust/test-unit/src/main/res/values/dimens.xml diff --git a/Adjust/test/src/main/res/values/strings.xml b/Adjust/test-unit/src/main/res/values/strings.xml similarity index 100% rename from Adjust/test/src/main/res/values/strings.xml rename to Adjust/test-unit/src/main/res/values/strings.xml diff --git a/Adjust/testlibrary/build.gradle b/Adjust/testlibrary/build.gradle deleted file mode 100644 index 8f77598ee..000000000 --- a/Adjust/testlibrary/build.gradle +++ /dev/null @@ -1,31 +0,0 @@ -apply plugin: 'com.android.library' - -android { - compileSdkVersion 27 - buildToolsVersion '27.0.3' - - defaultConfig { - minSdkVersion 9 - targetSdkVersion 27 - versionCode 1 - versionName "1.0" - } -} - -dependencies { - implementation fileTree(dir: 'libs', include: ['*.jar']) - implementation 'com.google.code.gson:gson:2.8.0' -} - -task clearJar(type: Delete) { - delete "build/outputs/adjust-testing.jar" -} - -task makeJar(type: Copy) { - from('build/intermediates/intermediate-jars/debug/') - into('build/outputs/jar/') - include('classes.jar') - rename('classes.jar', "adjust-testing.jar") -} - -makeJar.dependsOn(clearJar, build) diff --git a/Adjust/webbridge/build.gradle b/Adjust/webbridge/build.gradle deleted file mode 100644 index 3bc57762b..000000000 --- a/Adjust/webbridge/build.gradle +++ /dev/null @@ -1,31 +0,0 @@ -apply plugin: 'com.android.library' - -android { - compileSdkVersion 26 - - defaultConfig { - minSdkVersion 9 - targetSdkVersion 26 - versionCode 1 - versionName "1.0" - } - - buildTypes { - release { - postprocessing { - removeUnusedCode false - removeUnusedResources false - obfuscate false - optimizeCode false - proguardFile 'proguard-rules.pro' - } - } - } - -} - -dependencies { - implementation fileTree(dir: 'libs', include: ['*.jar']) - - implementation project(":adjust") -} diff --git a/Adjust/webbridge/src/main/res/values/strings.xml b/Adjust/webbridge/src/main/res/values/strings.xml deleted file mode 100644 index 2b8293688..000000000 --- a/Adjust/webbridge/src/main/res/values/strings.xml +++ /dev/null @@ -1,3 +0,0 @@ - - webBridge - diff --git a/CHANGELOG.md b/CHANGELOG.md index 6580543c4..7d6255394 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,16 @@ +### Version 4.16.0 (7th November 2018) +#### Added +- Added `README` localisation in Chinese, Korean and Japanese. +- Added sending of `android_uuid` with each attribution request. +- Added Gradle tasks for usage in Adjust non native SDKs. + +#### Changed +- Refactored scheduler. +- Started to catch potential exceptions in case of `checkCallingOrSelfPermission` method call. +- Renamed Android project modules. + +--- + ### Version 4.15.1 (19th September 2018) #### Changed - Changed way how `AdjustAttribution` object is being passed to Unity layer. diff --git a/README.md b/README.md index 3eb2afd4f..0d40ed617 100644 --- a/README.md +++ b/README.md @@ -2,8 +2,9 @@ This is the Android SDK of Adjust™. You can read more about Adjust™ at [adjust.com]. -If your app is an app which uses web views and you would like to use Adjust tracking from Javascript code, please consult -our [Android web views SDK guide](doc/english/web_views.md). +If your app is an app which uses web views and you would like to use Adjust tracking from Javascript code, please consult our [Android web views SDK guide](doc/english/web_views.md). + +Read this in other languages: [English][en-readme], [中文][zh-readme], [日本語][ja-readme], [한국어][ko-readme]. ## Table of contents @@ -62,7 +63,7 @@ our [Android web views SDK guide](doc/english/web_views.md). ## Example apps -There are example apps for Android inside the [`example` directory][example] and Android TV inside the [`example-tv` directory][example-tv]. You can open the Android project to see these examples on how the Adjust SDK can be integrated. +There are example apps for Android inside the [`example-app-java` directory][example-java] and Android TV inside the [`example-tv` directory][example-tv]. You can open the Android project to see these examples on how the Adjust SDK can be integrated. ## Basic integration @@ -73,42 +74,23 @@ These are the minimal steps required to integrate the Adjust SDK into your Andro If you are using Maven, add the following to your `build.gradle` file: ``` -compile 'com.adjust.sdk:adjust-android:4.15.1' -compile 'com.android.installreferrer:installreferrer:1.0' -``` - -**Note**: If you are using `Gradle 3.0.0 or above`, make sure to use the `implementation` keyword instead of `compile` as follows: - -``` -implementation 'com.adjust.sdk:adjust-android:4.15.1' +implementation 'com.adjust.sdk:adjust-android:4.16.0' implementation 'com.android.installreferrer:installreferrer:1.0' ``` -This applies when adding the Google Play Services dependency to your `build.gradle` file. - ---- - -You can also add the Adjust SDK to your project as a JAR library. The latest SDK version's JAR library can be found on our [releases page][releases]. - ### Add Google Play Services Since the 1st of August of 2014, apps in the Google Play Store must use the [Google Advertising ID][google_ad_id] to uniquely identify devices. To allow the Adjust SDK to use the Google Advertising ID, you must integrate the [Google Play Services][google_play_services]. If you haven't done this yet, follow these steps: -1. Open the `build.gradle` file of your app and find the `dependencies` block. Add the following line: +- Open the `build.gradle` file of your app and find the `dependencies` block. Add the following line: ``` - compile 'com.google.android.gms:play-services-analytics:11.8.0' + implementation 'com.google.android.gms:play-services-analytics:16.0.4' ``` - ![][gradle_gps] - - **Note**: The Adjust SDK is not tied to any specific version of the `play-services-analytics` part of the Google Play Services - library, so feel free to always use the latest version of it (or whichever you might need) + **Note**: The Adjust SDK is not tied to any specific version of the `play-services-analytics` part of the Google Play Services library, so feel free to always use the latest version of it (or whichever you might need). -2. **Skip this step if you are using version 7 or later of Google Play Services**: - In the Package Explorer open the `AndroidManifest.xml` of your Android - project. Add the following `meta-data` tag inside the `` - element. +- **Skip this step if you are using version 7 or later of Google Play Services**: In the Package Explorer open the `AndroidManifest.xml` of your Android project. Add the following `meta-data` tag inside the `` element. ```xml ``` -![][receiver] - We use this broadcast receiver to retrieve the install referrer and pass it to our backend. If you are already using a different broadcast receiver for the `INSTALL_REFERRER` intent, follow [these instructions][referrer] to add the Adjust broadcast receiver. @@ -202,24 +182,19 @@ To start with, we'll set up basic session tracking. We recommend using a global android [Application][android_application] class to initialize the SDK. If you don't have one in your app already, follow these steps: -1. Create a class that extends `Application`. - ![][application_class] - -2. Open the `AndroidManifest.xml` file of your app and locate the `` element. -3. Add the attribute `android:name` and set it to the name of your new application class pefixed by a dot. +- Create a class that extends `Application`. +- Open the `AndroidManifest.xml` file of your app and locate the `` element. +- Add the attribute `android:name` and set it to the name of your new application class pefixed by a dot. In our example app we use an `Application` class named `GlobalApplication`, so the manifest file is configured as: ```xml - ... + ``` - ![][manifest_application] - -4. In your `Application` class find or create the `onCreate` method and add the following code to initialize the Adjust SDK: +- In your `Application` class find or create the `onCreate` method and add the following code to initialize the Adjust SDK: ```java import com.adjust.sdk.Adjust; @@ -238,20 +213,18 @@ We recommend using a global android [Application][android_application] class to } ``` - ![][application_config] - - Replace `{YourAppToken}` with your app token. You can find this in your [dashboard]. +Replace `{YourAppToken}` with your app token. You can find this in your [dashboard]. - Depending on whether you are building your app for testing or for production, you must set `environment` with one of these values: +Depending on whether you are building your app for testing or for production, you must set `environment` with one of these values: - ```java - String environment = AdjustConfig.ENVIRONMENT_SANDBOX; - String environment = AdjustConfig.ENVIRONMENT_PRODUCTION; - ``` +```java +String environment = AdjustConfig.ENVIRONMENT_SANDBOX; +String environment = AdjustConfig.ENVIRONMENT_PRODUCTION; +``` - **Important:** This value should be set to `AdjustConfig.ENVIRONMENT_SANDBOX` if and only if you or someone else is testing your app. Make sure to set the environment to `AdjustConfig.ENVIRONMENT_PRODUCTION` before you publish the app. Set it back to `AdjustConfig.ENVIRONMENT_SANDBOX` when you start developing and testing it again. +**Important:** This value should be set to `AdjustConfig.ENVIRONMENT_SANDBOX` if and only if you or someone else is testing your app. Make sure to set the environment to `AdjustConfig.ENVIRONMENT_PRODUCTION` before you publish the app. Set it back to `AdjustConfig.ENVIRONMENT_SANDBOX` when you start developing and testing it again. - We use this environment to distinguish between real traffic and test traffic from test devices. It is imperative that you keep this value meaningful at all times, especially if you are tracking revenue. +We use this environment to distinguish between real traffic and test traffic from test devices. It is imperative that you keep this value meaningful at all times. ### Session tracking @@ -259,16 +232,10 @@ We recommend using a global android [Application][android_application] class to ### API level 14 and higher -1. Add a private class that implements the `ActivityLifecycleCallbacks` interface. If you don't have access to this interface, your app is targeting an Android API level inferior to 14. You will have to update manually each Activity by following these [instructions](#session-tracking-api9). If you had `Adjust.onResume` and `Adjust.onPause` calls on each Activity of your app before, you should remove them. - - ![][activity_lifecycle_class] - -2. Edit the `onActivityResumed(Activity activity)` method and add a call to `Adjust.onResume()`. Edit the +- Add a private class that implements the `ActivityLifecycleCallbacks` interface. If you don't have access to this interface, your app is targeting an Android API level inferior to 14. You will have to update manually each Activity by following these [instructions](#session-tracking-api9). If you had `Adjust.onResume` and `Adjust.onPause` calls on each Activity of your app before, you should remove them. +- Edit the `onActivityResumed(Activity activity)` method and add a call to `Adjust.onResume()`. Edit the `onActivityPaused(Activity activity)` method and add a call to `Adjust.onPause()`. - - ![][activity_lifecycle_methods] - -3. Add on the `onCreate()` method where the Adjust SDK is configured and add call `registerActivityLifecycleCallbacks` with an instance of the created `ActivityLifecycleCallbacks` class. +- Add on the `onCreate()` method where the Adjust SDK is configured and add call `registerActivityLifecycleCallbacks` with an instance of the created `ActivityLifecycleCallbacks` class. ```java import com.adjust.sdk.Adjust; @@ -305,18 +272,16 @@ We recommend using a global android [Application][android_application] class to } ``` - ![][activity_lifecycle_register] - ### API level between 9 and 13 If your app `minSdkVersion` in gradle is between `9` and `13`, consider updating it to at least `14` to simplify the integration process in the long term. Consult the official Android [dashboard][android-dashboard] to know the latest market share of the major versions. To provide proper session tracking it is required to call certain Adjust SDK methods every time any Activity resumes or pauses. Otherwise the SDK might miss a session start or session end. In order to do so you should **follow these steps for each Activity of your app**: -1. Open the source file of your Activity. -2. Add the `import` statement at the top of the file. -3. In your Activity's `onResume` method call `Adjust.onResume()`. Create the method if needed. -4. In your Activity's `onPause` method call `Adjust.onPause()`. Create the method if needed. +- Open the source file of your Activity. +- Add the `import` statement at the top of the file. +- In your Activity's `onResume` method call `Adjust.onResume()`. Create the method if needed. +- In your Activity's `onPause` method call `Adjust.onPause()`. Create the method if needed. After these steps your activity should look like this: @@ -336,8 +301,6 @@ public class YourActivity extends Activity { } ``` -![][activity] - Repeat these steps for **every** Activity of your app. Don't forget these steps when you create new Activities in the future. Depending on your coding style you might want to implement this in a common superclass of all your Activities. ### Adjust Logging @@ -368,9 +331,7 @@ Adjust.onCreate(config); ### Build your app -Build and run your Android app. In your `LogCat` viewer you can set the filter `tag:Adjust` to hide all other logs. After your app has launched you should see the following Adjust log: `Install tracked` - -![][log_message] +Build and run your Android app. In your `LogCat` viewer you can set the filter `tag:Adjust` to hide all other logs. After your app has launched you should see the following Adjust log: `Install tracked`. ## Additional Features @@ -409,10 +370,8 @@ If you want to track in-app purchases, please make sure to call `trackEvent` onl ```java AdjustEvent event = new AdjustEvent("abc123"); - event.setRevenue(0.01, "EUR"); event.setOrderId("{OrderId}"); - Adjust.trackEvent(event); ``` @@ -428,10 +387,8 @@ For example, suppose you have registered the URL `http://www.adjust.com/callback ```java AdjustEvent event = new AdjustEvent("abc123"); - event.addCallbackParameter("key", "value"); event.addCallbackParameter("foo", "bar"); - Adjust.trackEvent(event); ``` @@ -453,10 +410,8 @@ This works similarly to the callback parameters mentioned above, but can be adde ```java AdjustEvent event = new AdjustEvent("abc123"); - event.addPartnerParameter("key", "value"); event.addPartnerParameter("foo", "bar"); - Adjust.trackEvent(event); ``` @@ -468,9 +423,7 @@ You can also add custom string identifier to each event you want to track. This ```java AdjustEvent event = new AdjustEvent("abc123"); - event.setCallbackId("Your-Custom-Id"); - Adjust.trackEvent(event); ``` @@ -675,9 +628,7 @@ If your app makes heavy use of event tracking, you might want to delay some HTTP ```java AdjustConfig config = new AdjustConfig(this, appToken, environment); - config.setEventBufferingEnabled(true); - Adjust.onCreate(config); ``` @@ -701,9 +652,7 @@ An App Secret is set by calling `setAppSecret` on your `AdjustConfig` instance: ```java AdjustConfig config = new AdjustConfig(this, appToken, environment); - config.setAppSecret(secretId, info1, info2, info3, info4); - Adjust.onCreate(config); ``` @@ -713,9 +662,7 @@ The default behaviour of the Adjust SDK is to pause sending HTTP requests while ```java AdjustConfig config = new AdjustConfig(this, appToken, environment); - config.setSendInBackground(true); - Adjust.onCreate(config); ``` @@ -794,8 +741,8 @@ Adjust.setPushToken(pushNotificationsToken); If you want to use the Adjust SDK to recognize users whose devices came with your app pre-installed, follow these steps. -1. Create a new tracker in your [dashboard]. -2. Open your app delegate and add set the default tracker of your `AdjustConfig`: +- Create a new tracker in your [dashboard]. +- Open your app delegate and add set the default tracker of your `AdjustConfig`: ```java AdjustConfig config = new AdjustConfig(this, appToken, environment); @@ -803,10 +750,9 @@ If you want to use the Adjust SDK to recognize users whose devices came with you Adjust.onCreate(config); ``` - Replace `{TrackerToken}` with the tracker token you created in step 1. Please note that the Dashboard displays a tracker URL (including `http://app.adjust.com/`). In your source code, you should specify only the six-character token and not the - entire URL. + Replace `{TrackerToken}` with the tracker token you created in step 1. Please note that the Dashboard displays a tracker URL (including `http://app.adjust.com/`). In your source code, you should specify only the six-character token and not the entire URL. -3. Build and run your app. You should see a line like the following in your LogCat: +- Build and run your app. You should see a line like the following in your LogCat: ``` Default tracker: 'abc123' @@ -853,7 +799,7 @@ After clicking this tracker URL, and with the app set as described above, your a Depending on the `android:launchMode` setting of your Activity in the `AndroidManifest.xml` file, information about the `deep_link` parameter content will be delivered to the appropriate place in the Activity file. For more information about the possible values of the `android:launchMode` property, check [the official Android documentation][android-launch-modes]. -There are two places within your desired Activity where information about the deep link content will be delivered via the `Intent` object--either in the Activity's `onCreate` or `onNewIntent` methods. Once your app has launched and one of these methods has been triggered, you will be able to get the actual deep link passed in the `deep_link` parameter in the click URL. You can then use this information to conduct some additional logic in your app. +There are two places within your desired Activity where information about the deep link content will be delivered via the `Intent` object - either in the Activity's `onCreate` or `onNewIntent` methods. Once your app has launched and one of these methods has been triggered, you will be able to get the actual deep link passed in the `deep_link` parameter in the click URL. You can then use this information to conduct some additional logic in your app. You can extract the deep link content from these two methods like this: @@ -865,7 +811,6 @@ protected void onCreate(Bundle savedInstanceState) { Intent intent = getIntent(); Uri data = intent.getData(); - // data.toString() -> This is your deep_link parameter value. } ``` @@ -876,7 +821,6 @@ protected void onNewIntent(Intent intent) { super.onNewIntent(intent); Uri data = intent.getData(); - // data.toString() -> This is your deep_link parameter value. } ``` @@ -928,7 +872,6 @@ protected void onCreate(Bundle savedInstanceState) { Intent intent = getIntent(); Uri data = intent.getData(); - Adjust.appWillOpenUrl(data, getApplicationContext()); } ``` @@ -939,7 +882,6 @@ protected void onNewIntent(Intent intent) { super.onNewIntent(intent); Uri data = intent.getData(); - Adjust.appWillOpenUrl(data, getApplicationContext()); } ``` @@ -1047,12 +989,16 @@ If you want to trigger an event after the install, use the [attribution callback If you want to trigger an event when the app is launched, use the `onCreate` method of the Activity which is started. -[dashboard]: http://adjust.com -[adjust.com]: http://adjust.com +[dashboard]: http://adjust.com +[adjust.com]: http://adjust.com +[en-readme]: README.md +[zh-readme]: doc/chinese/README.md +[ja-readme]: doc/japanese/README.md +[ko-readme]: doc/korean/README.md [maven]: http://maven.org -[example]: https://github.com/adjust/android_sdk/tree/master/Adjust/example -[example-tv]: https://github.com/adjust/android_sdk/tree/master/Adjust/example-tv +[example-java]: Adjust/example-app-java +[example-tv]: Adjust/example-app-tv [releases]: https://github.com/adjust/adjust_android_sdk/releases [referrer]: doc/english/referrer.md [google_ad_id]: https://support.google.com/googleplay/android-developer/answer/6048248?hl=en @@ -1071,24 +1017,6 @@ If you want to trigger an event when the app is launched, use the `onCreate` met [reattribution-with-deeplinks]: https://docs.adjust.com/en/deeplinking/#manually-appending-attribution-data-to-a-deep-link [android-purchase-verification]: https://github.com/adjust/android_purchase_sdk -[activity]: https://raw.github.com/adjust/sdks/master/Resources/android/v4/14_activity.png -[proguard]: https://raw.github.com/adjust/sdks/master/Resources/android/v4/08_proguard_new.png -[receiver]: https://raw.github.com/adjust/sdks/master/Resources/android/v4/09_receiver.png -[gradle_gps]: https://raw.github.com/adjust/sdks/master/Resources/android/v4/05_gradle_gps.png -[log_message]: https://raw.github.com/adjust/sdks/master/Resources/android/v4/15_log_message.png -[manifest_gps]: https://raw.github.com/adjust/sdks/master/Resources/android/v4/06_manifest_gps.png -[gradle_adjust]: https://raw.github.com/adjust/sdks/master/Resources/android/v4/04_gradle_adjust.png -[import_module]: https://raw.github.com/adjust/sdks/master/Resources/android/v4/01_import_module.png -[select_module]: https://raw.github.com/adjust/sdks/master/Resources/android/v4/02_select_module.png -[imported_module]: https://raw.github.com/adjust/sdks/master/Resources/android/v4/03_imported_module.png -[application_class]: https://raw.github.com/adjust/sdks/master/Resources/android/v4/11_application_class.png -[application_config]: https://raw.github.com/adjust/sdks/master/Resources/android/v4/13_application_config.png -[manifest_permissions]: https://raw.github.com/adjust/sdks/master/Resources/android/v4/07_manifest_permissions.png -[manifest_application]: https://raw.github.com/adjust/sdks/master/Resources/android/v4/12_manifest_application.png -[activity_lifecycle_class]: https://raw.github.com/adjust/sdks/master/Resources/android/v4/16_activity_lifecycle_class.png -[activity_lifecycle_methods]: https://raw.github.com/adjust/sdks/master/Resources/android/v4/17_activity_lifecycle_methods.png -[activity_lifecycle_register]: https://raw.github.com/adjust/sdks/master/Resources/android/v4/18_activity_lifecycle_register.png - ## License The Adjust SDK is licensed under the MIT License. diff --git a/VERSION b/VERSION index fb0557132..ecbc3b030 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -4.15.1 +4.16.0 diff --git a/doc/chinese/README.md b/doc/chinese/README.md new file mode 100644 index 000000000..126037c43 --- /dev/null +++ b/doc/chinese/README.md @@ -0,0 +1,1042 @@ +## 摘要 + +这是Adjust™的安卓SDK包。您可以访问[adjust.com]了解更多有关Adjust™的信息。 + +如果您的应用正在使用web views,您希望Adjust通过Javascript代码跟踪,请参照我们的[安卓web views SDK指南](doc/english/web_views.md)。 + +Read this in other languages: [English][en-readme], [中文][zh-readme], [日本語][ja-readme], [한국어][ko-readme]. + +## 目录 + +* [应用示例](#example-apps) +* [基本集成](#basic-integration) + * [添加SDK至您的项目](#sdk-add) + * [添加Google Play服务](#sdk-gps) + * [添加权限](#sdk-permissions) + * [Proguard设置](#sdk-proguard) + * [Install referrer](#install-referrer) + * [Google Play Referrer API](#gpr-api) + * [Google Play Store intent](#gps-intent) + * [集成SDK至您的应用](#sdk-integrate) + * [基本设置](#basic-setup) + * [会话跟踪](#session-tracking) + * [API level 14及以上版本](#session-tracking-api14) + * [API level 9-13版本](#session-tracking-api9) + * [Adjust日志](#adjust-logging) + * [构建您的应用](#build-the-app) +* [附加功能](#additional-features) + * [事件跟踪](#event-tracking) + * [收入跟踪](#revenue-tracking) + * [收入重复数据删除](#revenue-deduplication) + * [应用收入验证](#iap-verification) + * [回调参数](#callback-parameters) + * [合作伙伴参数](#partner-parameters) + * [回调ID](#callback-id) + * [会话参数](#session-parameters) + * [会话回调参数](#session-callback-parameters) + * [会话合作伙伴参数](#session-partner-parameters) + * [延迟启动](#delay-start) + * [归因回传](#attribution-callback) + * [会话和事件回传](#session-event-callbacks) + * [禁用跟踪](#disable-tracking) + * [离线模式](#offline-mode) + * [事件缓冲](#event-buffering) + * [GDPR 的被遗忘权](#gdpr-forget-me) + * [SDK签名](#sdk-signature) + * [后台跟踪](#background-tracking) + * [设备ID](#device-ids) + * [Google Play服务广告ID](#di-gps-adid) + * [Amazon广告ID](#di-amz-adid) + * [Adjust设备ID](#di-adid) + * [用户归因](#user-attribution) + * [推送标签(Push token)](#push-token) + * [预安装跟踪码](#pre-installed-trackers) + * [深度链接](#deeplinking) + * [标准深度链接场景](#deeplinking-standard) + * [延迟深度链接场景](#deeplinking-deferred) + * [通过深度链接的再归因](#deeplinking-reattribution) +* [故障排查](#troubleshooting) + * [显示 "Session failed (Ignoring too frequent session. ...)" 出错信息](#ts-session-failed) + * [我的广播接收器是否能成功获取install referrer?](#ts-broadcast-receiver) + * [我是否可以在应用激活时触发事件?](#ts-event-at-launch) +* [许可协议](#license) + +## 应用示例 + +[`example-app-java`目录][example-java]内有安卓应用示例,[`example-tv` 目录][example-tv]内有安卓 TV 应用示例。您可以打开安卓项目查看如何集成Adjust SDK的示例。 + +## 基本集成 + +我们将向您介绍把Adjust SDK集成到安卓项目的最基本步骤。我们假定您将Android Studio用于安卓开发,并以安卓API level 9(Gingerbread)及以上版本为目标对象。 + +### 添加SDK至您的项目 + +如果您正在使用Maven,请添加下行至您的`build.gradle`文件: + +``` +implementation 'com.adjust.sdk:adjust-android:4.16.0' +implementation 'com.android.installreferrer:installreferrer:1.0' +``` + +### 添加Google Play服务 + +自2014年8月1日起,在Google Play商店中的应用必须使用[Google广告ID][google_ad_id]]以唯一标识每个设备。为了让Adjust SDK能够使用Google广告ID,您必须集成[Google Play服务][google_play_services]。如果您还未完成该集成,请遵循以下步骤进行设置: + +- 打开您应用中的`build.gradle`文件,找到`dependencies`程序块。添加如下代码行: + + ``` + implementation 'com.google.android.gms:play-services-analytics:16.0.4' + ``` + + **注意**:Adjust SDK未与Google Play服务库中`play-services-analytics`的任何特定版本绑定,因此您可自由选择使用最新版本(或您需要的任何版本)。 + +- **如果您正在使用Google Play服务7或者以上版本,请跳过该步骤**: + 在Package Explorer中,打开安卓项目的`AndroidManifest.xml`。在``元素中添加以下 `meta-data` 标签。 + + ```xml + + ``` + +### 添加权限 + +如果您还未在`AndroidManifest.xml`文件中添加Adjust需要的如下权限,请进行添加: + +```xml + + +``` + +如果您的**发布目标非Google Play商店**, 请同时添加以下权限: + +```xml + +``` + +### Proguard设置 + +如果您正在使用Proguard,请添加如下代码行至您的Proguard文件: + +``` +-keep public class com.adjust.sdk.** { *; } +-keep class com.google.android.gms.common.ConnectionResult { + int SUCCESS; +} +-keep class com.google.android.gms.ads.identifier.AdvertisingIdClient { + com.google.android.gms.ads.identifier.AdvertisingIdClient$Info getAdvertisingIdInfo(android.content.Context); +} +-keep class com.google.android.gms.ads.identifier.AdvertisingIdClient$Info { + java.lang.String getId(); + boolean isLimitAdTrackingEnabled(); +} +-keep public class com.android.installreferrer.** { *; } +``` + +如果您的**发布目标非Google Play商店**,请删除 `com.google.android.gms`规则。 + +### Install referrer + +为了将应用安装正确地归因到其来源,Adjust需要关于**install referrer(安装引荐来源)**的信息。这可以通过**Google Play Referrer API** 或使用广播接收器(broadcast receiver)捕捉**Google Play Store intent**来获得。 + +**重要**: Google Play Referrer API是Google近期推出的,旨在提供更加可靠和安全地获取install referrer信息的方法,并帮助归因提供商更有效地对抗点击劫持(click injection)。我们**强烈建议**在您的应用中支持它。相比之下,通过Google Play Store intent获取install referrer的方法则安全性较低。目前该方式与新的Google Play Referrer API并行可用,但未来将被弃用。 + +#### Google Play Referrer API + +为了让您的应用支持Google Play Referrer API,请确保已经遵循[添加SDK至您的项目](#sdk-add)章节进行了正确设置,并在`build.gradle`文件中添加了如下代码行: + +``` +implementation 'com.android.installreferrer:installreferrer:1.0' +``` + +同时,请确保您已经添加了[Proguard设置](#sdk-proguard)章节中所提及的全部规则,尤其是该功能必需的规则: + +``` +-keep public class com.android.installreferrer.** { *; } +``` + +**Adjust SDK 4.12.0或以上版本** 已支持该功能。 + +#### Google Play Store intent + +Google Play Store `INSTALL_REFERRER` intent应该由广播接收器(broadcast receiver)来接收。如果您**未使用自己的广播接收器**来接收 `INSTALL_REFERRER` intent,请在`AndroidManifest.xml`的`application`标签中添加如下`receiver`标签: + +```xml + + + + + +``` + +我们使用这个广播接收器来检索install referrer,并将其传送给后端。 + +如果您已经为`INSTALL_REFERRER`intent使用了不同的广播接收器,请遵循[此说明][referrer]来添加Adjust广播接收器。 + +### 集成SDK至您的应用 + +我们从设置基本会话跟踪开始。 + +### 基本设置 + +我们推荐使用全局安卓[应用程序][android_application]类来初始化SDK。如果您的应用中还没有此类,请按照以下步骤设置: + +- 创建一个扩展`Application`的类。 +- 打开应用中的`AndroidManifest.xml`文件并找到 `` 元素。 +- 添加`android:name`属性,将其设置为您的新应用程序类的名称,并带一个点为前缀。 + + 在此应用示例中,我们将`Application`类命名为`GlobalApplication`,因此manifest文件被设置为: + + ```xml + + + + ``` + +- 在您的`Application`类中找到或者创建`onCreate`方法,并添加如下代码来初始化Adjust SDK: + + ```java + import com.adjust.sdk.Adjust; + import com.adjust.sdk.AdjustConfig; + + public class GlobalApplication extends Application { + @Override + public void onCreate() { + super.onCreate(); + + String appToken = "{YourAppToken}"; + String environment = AdjustConfig.ENVIRONMENT_SANDBOX; + AdjustConfig config = new AdjustConfig(this, appToken, environment); + Adjust.onCreate(config); + } + } + ``` + + 将`{YourAppToken}`替换为您的应用识别码(app token)。您可以在[控制面板][dashboard]中找到该应用识别码。 + + 取决于您的应用制作是用于测试或产品开发目的,您必须将`environment`(环境模式)设为以下值之一: + + ```java + String environment = AdjustConfig.ENVIRONMENT_SANDBOX; + String environment = AdjustConfig.ENVIRONMENT_PRODUCTION; + ``` + +**重要:** 仅当您或其他人测试您的应用时,该值应设为 `AdjustConfig.ENVIRONMENT_SANDBOX`。在您发布应用之前,请确保将环境改设为 `AdjustConfig.ENVIRONMENT_PRODUCTION`。再次研发和测试时,请将其设回为 `AdjustConfig.ENVIRONMENT_SANDBOX`。 + +我们按照设置的环境来区分真实流量和来自测试设备的测试流量。非常重要的是,您必须始终让该值保持有意义! + +### 会话跟踪 + +**注意**:此步骤**非常重要**,请**确保您在应用中正确设置它**。设置之后,Adjust SDK将对您的应用进行会话跟踪。 + +### API level 14及以上版本 + +- 添加一个私有类(private class)以实现`ActivityLifecycleCallbacks`接口。如果您不能访问该接口,则表示您的应用仅支持安卓API level 14以下版本。在此种情况下,请按照此[说明](#session-tracking-api9)手动更新每项Activity。如果您在之前已经对应用的每个Activity调用了`Adjust.onResume`和`Adjust.onPause`,请将其全部删除。 + +- 编辑`onActivityResumed(Activity activity)`方法,添加对`Adjust.onResume()`的调用。编辑`onActivityPaused(Activity activity)`方法,添加对`Adjust.onPause()`的调用。 + +- 在设置Adjust SDK的位置添加`onCreate()` 方法,并添加调用 `registerActivityLifecycleCallbacks`以及被创建的`ActivityLifecycleCallbacks`类实例。 + + ```java + import com.adjust.sdk.Adjust; + import com.adjust.sdk.AdjustConfig; + + public class GlobalApplication extends Application { + @Override + public void onCreate() { + super.onCreate(); + + String appToken = "{YourAppToken}"; + String environment = AdjustConfig.ENVIRONMENT_SANDBOX; + AdjustConfig config = new AdjustConfig(this, appToken, environment); + Adjust.onCreate(config); + + registerActivityLifecycleCallbacks(new AdjustLifecycleCallbacks()); + + //... + } + + private static final class AdjustLifecycleCallbacks implements ActivityLifecycleCallbacks { + @Override + public void onActivityResumed(Activity activity) { + Adjust.onResume(); + } + + @Override + public void onActivityPaused(Activity activity) { + Adjust.onPause(); + } + + //... + } + } + ``` + +### API level 9-13版本 + +如果您的应用gradle中的`minSdkVersion`是在9至13版本之间,您应当考虑至少升级至版本14以简化集成流程。请咨询官方安卓[控制面板][android-dashboard]了解目前市场上广泛使用的主要版本。 + +为了进行准确的会话跟踪,每当任一Activity重新开始或者暂停时都需要调用某个Adjust SDK方法。否则SDK可能会错过一个会话开始或者会话结束。**请遵循以下步骤对您的应用中的每个 +Activity**进行正确设置: + +- 打开Activity的源文件。 +- 在文件顶部添加`import`语句。 +- 在Activity的`onResume`方法中调用 Adjust.onResume`。必要时创建该方法。 +- 在Activity的`onPause`方法中调用`Adjust.onPause`。必要时创建该方法。 + +完成以上步骤后,您的Activity应如下: + +```java +import com.adjust.sdk.Adjust; +// ... +public class YourActivity extends Activity { + protected void onResume() { + super.onResume(); + Adjust.onResume(); + } + protected void onPause() { + super.onPause(); + Adjust.onPause(); + } + // ... +} +``` + +对您的应用中的**每个**Activity重复以上步骤。如果您在之后创建新的Activity,也请按照以上步骤设置。取决于您的编码方式,您也可通过设置所有Activitiy的通用超类来实现它。 + +### Adjust日志 + +您可以增加或减少在测试中看到的日志数量,方法是用以下参数之一来调用`AdjustConfig`实例上的`setLogLevel`: + +```java +config.setLogLevel(LogLevel.VERBOSE); // enable all logging +config.setLogLevel(LogLevel.DEBUG); // enable more logging +config.setLogLevel(LogLevel.INFO); // the default +config.setLogLevel(LogLevel.WARN); // disable info logging +config.setLogLevel(LogLevel.ERROR); // disable warnings as well +config.setLogLevel(LogLevel.ASSERT); // disable errors as well +config.setLogLevel(LogLevel.SUPRESS); // disable all log output +``` +如果您希望禁用所有日志输出,除了将日志级别设置为抑制以外,您还应该对`AdjustConfig`对象使用构建函数,它将获取boolean参数来显示是否应该支持抑制日志级别: + +```java +String appToken = "{YourAppToken}"; +String environment = AdjustConfig.ENVIRONMENT_SANDBOX; + +AdjustConfig config = new AdjustConfig(this, appToken, environment, true); +config.setLogLevel(LogLevel.SUPRESS); + +Adjust.onCreate(config); +``` + +### 构建您的应用 + +构建并运行您的安卓应用。在`LogCat`查看工具中,您可以设置筛选`tag:Adjust`来隐藏所有其他日志。应用启动后,您可看到以下Adjust日志:`Install tracked`(安装已跟踪)。 + +## 附加功能 + +一旦您已经成功将Adjust SDK集成到您的项目中,您便可以使用以下功能。 + +### 事件跟踪 + +您可以使用Adjust来跟踪应用中的任何事件。假设您想要跟踪具体按钮的每次点击,您必须在[控制面板][dashboard]中创建一个新的事件识别码(Event Token)。例如事件识别码是`abc123`,在按钮的`onClick`方法中,您可以添加以下代码行来跟踪点击: + +```java +AdjustEvent event = new AdjustEvent("abc123"); +Adjust.trackEvent(event); +``` + +### 收入跟踪 + +如果您的用户可以通过点击广告或应用内购为您带来收入,您可以按照事件来跟踪这些收入。假设一次点击值一欧分,那么您可以这样来跟踪收入事件: + +```java +AdjustEvent event = new AdjustEvent("abc123"); +event.setRevenue(0.01, "EUR"); +Adjust.trackEvent(event); +``` + +当然,这也可以和回调参数相结合。 + +您设置货币类型后,Adjust将自动把收入转换为您选择的货币类型。阅读这里了解有关[货币转换][currency-conversion]的更多信息。 + +您可以在[事件跟踪指南][event-tracking]中了解更多有关收入和事件跟踪的内容。 + +### 收入重复数据删除 + +您也可以输入可选的交易ID,以避免跟踪重复收入。最近的十个交易ID将被记录下来,重复交易ID的收入事件将被跳过。这对于应用内购跟踪尤其有用。参见以下例子。 + +如果您想要跟踪应用内购,请确保只有交易完成以及产品被购买后调用`trackEvent`。这样您可以避免跟踪实际未产生的收入。 + +```java +AdjustEvent event = new AdjustEvent("abc123"); +event.setRevenue(0.01, "EUR"); +event.setOrderId("{OrderId}"); +Adjust.trackEvent(event); +``` + +### 应用收入验证 + +如果您想要验证应用内购,您可以使用Adjust的收入验证产品——我们的服务器端收据验证工具。请查看我们的安卓购买SDK并在[这里][android-purchase-verification]了解更多。 + +### 回调参数 + +您可以在[控制面板][dashboard]中为您的事件登记回调URL。跟踪到事件时,我们会向该URL发送GET请求。您可以在跟踪事件之前调用事件实例的`addCallbackParameter`,向该事件添加回调参数。然后我们会将这些参数添加至您的回调URL。 + +假设您已经登记URL为`http://www.adjust.com/callback` ,然后如下行跟踪事件: + +```java +AdjustEvent event = new AdjustEvent("abc123"); +event.addCallbackParameter("key", "value"); +event.addCallbackParameter("foo", "bar"); +Adjust.trackEvent(event); +``` + +在这种情况下,我们会跟踪该事件并发送请求至: + +``` +http://www.adjust.com/callback?key=value&foo=bar +``` + +值得注意的是,我们支持各种可以用作参数值的占位符,例如 `{gps_adid}`。在接下来的回调中,该占位符将被当前设备的Google Play服务ID所替代。同时请注意,我们不保存您的任何定制参数,而只是将它们添加到您的回调中。如果您没有为事件输入回调地址,这些参数甚至不会被读取。 + +您可以在我们的[回调指南][callbacks-guide]中了解到有关使用URL回调的更多信息,包括可用值的完整列表。 + +### 合作伙伴参数 + +您还可以针对您已在Adjust控制面板中激活的渠道合作伙伴添加被发送至合作伙伴的参数。 + +方式和上述提及的回调参数类似,可以通过调用您的`AdjustEvent`实例上的`addPartnerParameter`方法来添加。 + +```java +AdjustEvent event = new AdjustEvent("abc123"); +event.addPartnerParameter("key", "value"); +event.addPartnerParameter("foo", "bar"); +Adjust.trackEvent(event); +``` +您可在我们的[特殊合作伙伴指南][special-partners]中了解到有关特殊合作伙伴和集成的更多信息。 + +### 回调ID +您还可为想要跟踪的每个事件添加自定义字符串ID。此ID将在之后的事件成功和/或事件失败回调中被报告,以便您了解哪些事件跟踪成功或者失败。您可通过调用`AdjustEvent`实例上的`setCallbackId`方法来设置此ID: + + ```java +AdjustEvent event = new AdjustEvent("abc123"); +event.setCallbackId("Your-Custom-Id"); +Adjust.trackEvent(event); +``` + +### 会话参数 + +一些参数被保存发送到Adjust SDK的每一个**事件**和**会话**中。一旦您已经添加任一这些参数,您无需再每次添加它们,因为这些参数已经被保存至本地。如果您添加同样参数两次,也不会有任何影响。 + +这些会话参数在Adjust SDK上线之前可以被调用,以确保它们即使在安装时也可被发送。如果您需要在安装同时发送参数,但只有在SDK上线后才能获取所需的值,您可以通过[延迟](#delay-start)Adjust SDK第一次上线以允许该行为。 + +### 会话回调参数 + +注册在[事件](#callback-parameters)中的相同回调参数也可以被保存发送至Adjust SDK的每一个事件和会话中。 + +会话回调参数拥有与事件回调参数类似的接口。该参数是通过调用`Adjust.addSessionCallbackParameter(String key, String value)`被添加,而不是通过添加Key和值至事件: + +```java +Adjust.addSessionCallbackParameter("foo", "bar"); +``` + +会话回调参数将与被添加至事件的回调参数合并。被添加至事件的回调参数拥有高于会话回调参数的优先级。这意味着,当被添加至事件的回调参数拥有与会话回调参数同样Key时,以被添加至事件的回调参数值为准。 + +您可以通过传递Key至`Adjust.removeSessionCallbackParameter(String key)`的方式来删除特定会话回调参数。 + +```java +Adjust.removeSessionCallbackParameter("foo"); +``` + +如果您希望删除会话回调参数中所有的Key及相应值,您可以通过`Adjust.resetSessionCallbackParameters()`方式重置: + +```java +Adjust.resetSessionCallbackParameters(); +``` + +### 会话合作伙伴参数 + +与[会话回调参数](#session-callback-parameters)的方式一样,会话合作伙伴参数也将被发送至Adjust SDK的每一个事件和会话中。 + +它们将被传送至渠道合作伙伴,以集成您在Adjust[控制面板][dashboard]上已经激活的模块。 + +会话合作伙伴参数具有与事件合作伙伴参数类似的接口。该参数是通过调用`Adjust.addSessionPartnerParameter(String key, String value)`被添加,而不是通过添加Key和值至事件: + +```java +Adjust.addSessionPartnerParameter("foo", "bar"); +``` + +会话合作伙伴参数将与被添加至事件的合作伙伴参数合并。被添加至事件的合作伙伴参数具有高于会话合作伙伴参数的优先级。这意味着,当被添加至事件的合作伙伴参数拥有与会话合作伙伴参数同样Key时,以被添加至事件的合作伙伴参数值为准。 + +您可以通过传递Key至`Adjust.removeSessionPartnerParameter(String key)`方式来删除特定的会话合作伙伴参数: + +```java +Adjust.removeSessionPartnerParameter("foo"); +``` + +如果您希望删除会话合作伙伴参数中所有的Key及其相应值,您可以通过`Adjust.resetSessionPartnerParameters()`方式重置: + +```java +Adjust.resetSessionPartnerParameters(); +``` + +### 延迟启动 + +延迟Adjust的SDK启动可以给您的应用一些时间获取被发送至安装的会话参数,如唯一识别码(unique identifiers)等。 + +通过在`AdjustConfig` 实例中的`setDelayStart`(设置延迟启动)方式以秒为单位设置初始延迟时间: + +```java +adjustConfig.setDelayStart(5.5); +``` + +在此种情况下,Adjust SDK不会在5.5秒内发送初始安装会话以及创建任何事件。在该时间过期后或您同时调用`Adjust.sendFirstPackages()`,每个会话参数将被添加至延迟安装的会话和事件中,Adjust SDK将恢复正常。 + +**Adjust SDK最长的延迟启动时间为10秒。** + +### 归因回传 + +您可以注册一个监听器(listener),以获取跟踪链接归因变化的通知。由于考虑到归因的不同来源,归因信息无法被同步提供。最简单的方式是创建一个单一的匿名监听器: + +请您务必考虑我们的[适用归因数据政策][attribution-data]。 + +使用`AdjustConfig` 实例,在启动SDK之前添加匿名监听器: + +```java +AdjustConfig config = new AdjustConfig(this, appToken, environment); + +config.setOnAttributionChangedListener(new OnAttributionChangedListener() { + @Override + public void onAttributionChanged(AdjustAttribution attribution) { + } +}); + +Adjust.onCreate(config); +``` + +或者,您可以在`Application`类中执行`OnAttributionChangedListener`接口,并设置其为监听器: + +```java +AdjustConfig config = new AdjustConfig(this, appToken, environment); +config.setOnAttributionChangedListener(this); +Adjust.onCreate(config); +``` + +监听器函数将在SDK接收到最终归因数据后被调用。在监听器函数中,您可以访问`attribution`(归因)参数。这里是其属性的快捷摘要: + +- `String trackerToken` 目前归因的跟踪码token +- `String trackerName` 目前归因的跟踪码名称 +- `String network` 目前归因的渠道分组级别 +- `String campaign` 目前归因的推广分组级别 +- `String adgroup` 目前归因的广告组分组级别 +- `String creative` 目前归因的创意分组级别 +- `String clickLabel` 目前归因的点击标签 +- `String adid` Adjust设备ID + +当值不可用时,则默认为`null`。 + +### 会话和事件回传 + +您可以注册一个监听器,以在事件或者会话被跟踪时获取通知。共有四个监听器:一个是用来跟踪成功事件,一个跟踪失败事件,一个跟踪成功会话,一个跟踪失败会话。您可以在创建`AdjustConfig`对象后添加任意数量的监听器: + +```java +AdjustConfig config = new AdjustConfig(this, appToken, environment); + +// Set event success tracking delegate. +config.setOnEventTrackingSucceededListener(new OnEventTrackingSucceededListener() { + @Override + public void onFinishedEventTrackingSucceeded(AdjustEventSuccess eventSuccessResponseData) { + // ... + } +}); + +// Set event failure tracking delegate. +config.setOnEventTrackingFailedListener(new OnEventTrackingFailedListener() { + @Override + public void onFinishedEventTrackingFailed(AdjustEventFailure eventFailureResponseData) { + // ... + } +}); + +// Set session success tracking delegate. +config.setOnSessionTrackingSucceededListener(new OnSessionTrackingSucceededListener() { + @Override + public void onFinishedSessionTrackingSucceeded(AdjustSessionSuccess sessionSuccessResponseData) { + // ... + } +}); + +// Set session failure tracking delegate. +config.setOnSessionTrackingFailedListener(new OnSessionTrackingFailedListener() { + @Override + public void onFinishedSessionTrackingFailed(AdjustSessionFailure sessionFailureResponseData) { + // ... + } +}); + +Adjust.onCreate(config); +``` +监听器函数将于SDK发送包(package)到服务器后调用。在监听器函数中,您可以访问专为监听器所设的响应数据对象。成功会话的响应数据对象字段摘要如下: + +- `String message` 服务器信息或者SDK纪录的错误信息 +- `String timestamp` 服务器的时间戳 +- `String adid` Adjust提供的设备唯一识别码 +- `JSONObject jsonResponse` JSON对象及服务器响应 + +两个事件响应数据对象均包含: + +- 如果跟踪的包是一个事件,`String eventToken`代表事件识别码。 +- `String callbackId` 为事件对象设置的自定义回调ID。 + +当值不可用时,则默认为`null`。 + +事件和会话跟踪不成功的对象也均包含: + +- `boolean willRetry`表示稍后将再尝试发送数据包。 + +### 禁用跟踪 + +您可以通过调用`setEnabled`,启用参数为`false`,来禁用Adjust SDK的跟踪功能。**该设置在会话间保存**。 + +```java +Adjust.setEnabled(false); +``` + +您可以通过调用`isEnabled`函数来查看Adjust SDK目前是否被启用。您始终可以通过调用`setEnabled`,启用参数为`true`,来激活Adjust SDK。 + +### 离线模式 + +您可以把Adjust SDK设置离线模式,以暂停发送数据到我们的服务器,但仍然继续跟踪及保存数据并在之后发送。当设为离线模式时,所有数据将存放于一个文件中,所以请注意不要于离线模式触发太多事件。 + +您可以调用`setOfflineMode`,启用参数为`true`,以激活离线模式。 + +```java +Adjust.setOfflineMode(true); +``` + +相反地,您可以调用`setOfflineMode`,启用参数为`false`,以终止离线模式。当Adjust SDK回到在线模式时,所有被保存的数据将被发送到我们的服务器,并保留正确的时间信息。 + +跟禁用跟踪设置不同的是,此设置在会话之间将*不被保存*。这意味着,即使应用在离线模式时被终止,每当SDK启动时都必定处于在线模式。 + +### 事件缓冲 + +如果您的应用大量使用事件跟踪,您可能想要延迟部分HTTP请求,以便按分钟成批发送这些请求。您可以调用`AdjustConfig`实例启用事件缓冲: + +```java +AdjustConfig config = new AdjustConfig(this, appToken, environment); +config.setEventBufferingEnabled(true); +Adjust.onCreate(config); +``` + +### GDPR 的被遗忘权 + +根据欧盟的《一般数据保护条例》(GDPR) 第 17 条规定,用户行使被遗忘权时,您可以通知 Adjust。调用以下方法,Adjust SDK 将会收到指示向 Adjust 后端传达用户选择被遗忘的信息: + +```java +Adjust.gdprForgetMe(context); +``` + +收到此信息后,Adjust 将清除该用户数据,并且 Adjust SDK 将停止跟踪该用户。以后不会再向 Adjust 发送来自此设备的请求。 + +### SDK签名 + +账户管理员必须启用SDK签名。如果您希望使用该功能,请联系Adjust技术支持(support@adjust.com)。 + +如果您已经在账户中启用了SDK签名,并可访问Adjust控制面板的应用密钥,请使用以下方法来集成SDK签名到您的应用。 + +在您的`AdjustConfig`实例中调用`setAppSecret`来设置应用密钥。 + +```java +AdjustConfig config = new AdjustConfig(this, appToken, environment); +config.setAppSecret(secretId, info1, info2, info3, info4); +Adjust.onCreate(config); +``` + +### 后台跟踪 + +Adjust SDK的默认行为是当应用处于后台时暂停发送HTTP请求。您可以调用`AdjustConfig`实例更改该设置: + +```java +AdjustConfig config = new AdjustConfig(this, appToken, environment); +config.setSendInBackground(true); +Adjust.onCreate(config); +``` + +### 设备ID + +Adjust SDK支持您获取一些设备ID。 + +### Google Play服务广告ID + +某些服务(如Google Analytics)要求您协调设备及客户ID以避免重复报告。 + +如果您需要获取Google 广告ID,则仅限于在后台线程里读取。如您调用带有背景关系(context)的`getGoogleAdId`函数及`OnDeviceIdsRead`实例,那么在任何情况下都可成功获取ID: + +```java +Adjust.getGoogleAdId(this, new OnDeviceIdsRead() { + @Override + public void onGoogleAdIdRead(String googleAdId) { + // ... + } +}); +``` + +您可在`OnDeviceIdsRead`实例中的`onGoogleAdIdRead`方法内,以`googleAdId`变数来访问Google广告ID。 + +### Amazon广告ID + +如果您需要获取Amazon广告ID,请在`Adjust`实例上调用以下方法: + +```java +String amazonAdId = Adjust.getAmazonAdId(context); +``` + +### Adjust设备ID + +Adjust后台将为每一台安装了您应用的设备生成一个唯一的**Adjust设备ID** (**adid**)。您可在`Adjust`实例上调用以下方法来获取该ID: + +```java +String adid = Adjust.getAdid(); +``` + +**注意**: 此调用只能在Adjust SDK 4.11.0和以上版本中进行。 + +**注意**: 只有在Adjust后台跟踪到应用安装后,您才能获取**adid**的相关信息。自此之后,Adjust SDK已经拥有关于设备**adid**的信息,您可以使用此方法来访问它。因此,在SDK被初始化以及您的应用安装被成功跟踪之前,您将**无法访问adid**。 + +### 用户归因 + +归因回传通过[归因回传章节](#attribution-callback)所描述的方法被触发,以向您提供关于用户归因值的任何更改信息。如果您想要在任何其他时间访问用户当前归因值的信息,您可以通过对`Adjust`实例调用如下属性来实现: + +```java +AdjustAttribution attribution = Adjust.getAttribution(); +``` + +**注意**: 此调用只能在Adjust SDK 4.11.0和以上版本中进行。 + +**注意**: 只有在Adjust后台跟踪到应用安装以及归因回传被触发后,您才能获取有关当前归因的信息。自此之后,Adjust SDK已经拥有用户归因信息,您可以使用此方法来访问它。因此,在SDK被初始化以及归因回传被触发之前,您将**无法访问用户归因值**。 + +### 推送标签(Push token) + +推送标签适用于Adjust受众分群工具(Audience Builder)和客户回传,是卸载跟踪功能的必需信息。 + +每当您获取或更新识别码时,请添加以下调用至Adjust,以发送推送标签给我们: + +```java +Adjust.setPushToken(pushNotificationsToken, context); +``` + +以上添加了`context`的更新后签名让SDK可以涵盖更多的场景,以确保推送标签被发送。因此,我们建议您使用以上签名方式。 + +我们仍支持之前的签名方式: + +```java +Adjust.setPushToken(pushNotificationsToken); +``` + +### 预安装跟踪码 + +如果您希望使用Adjust SDK来识别已在设备中预安装您的应用的用户,请执行以下步骤。 + +- 在[控制面板][dashboard]中创建一个新的跟踪码。 +- 打开应用委托,并在`AdjustConfig`实例中添加设置默认跟踪码: + + ```java + AdjustConfig config = new AdjustConfig(this, appToken, environment); + config.setDefaultTracker("{TrackerToken}"); + Adjust.onCreate(config); + ``` + + 用您在步骤1中创建的跟踪码替换`{TrackerToken}`(跟踪码)。请注意,控制面板中显示的是跟踪URL(包括 `http://app.adjust.com/`)。在源代码中,您应该仅指定六个字符的识别码,而不是整个URL。 + +- 创建并运行您的应用。您应该可以在应用日志输出中看到如下行: + + ``` + Default tracker: 'abc123' + ``` + +### 深度链接 + +如果您正在使用可从网址(URL)深度链接至您应用的Adjust跟踪URL,您将有机会获取深度链接URL及其内容的相关信息。点击URL的情况发生在用户已经安装了您的应用(标准深度链接场景),或用户尚未在其设备上安装您的应用(延迟深度链接场景)。在标准深度链接场景中,安卓平台原生支持您获取关于深度链接内容的信息。但是,安卓平台不提供对延迟深度链接场景的支持。在此情况下,Adjust SDK可以帮助您获取有关深度链接内容的信息。 + +### 标准深度链接场景 + +如果用户已经安装了您的应用,您希望在用户点击带有`deep_link`(深度链接)参数的Adjust跟踪链接后打开应用,您必须在应用中启用深度链接。请定义*唯一方案名称(unique scheme name)*,并将其分配至您希望在用户点击链接后应用打开时启动的Activity中。这可以通过设置在深度链接被点击应用被打开后您希望启动的Activity类的某个属性来实现。您可在`AndroidManifest.xml`中设置它。请在manifest文件中添加`intent-filter`至您指定的Activity定义,并分配指定的方案名至`android:scheme`属性值: + +```xml + + + + + + + + + + + + + + +``` + +以上设置完成后,如果您希望在跟踪链接被点击后打开应用,请在Adjust跟踪链接的`deep_link`参数中使用指定的方案名称。未添加任何深度链接信息的跟踪链接将如下所示: + +``` +https://app.adjust.com/abc123?deep_link=adjustExample%3A%2F%2F +``` + +请记住,在URL中的`deep_link`参数值**必须采用URL编码形式**。 + +如上所述完成应用设置,当您点击跟踪链接后,您的应用将连带`MainActivity`intent(意图)打开。在`MainActivity`类中,您将自动获取关于`deep_link`参数的内容信息。虽然该内容在URL中已编码,但是它在发送给您后**不会被编码**。 + +取决于`AndroidManifest.xml`文件中Activity的`android:launchMode`设置,`deep_link`参数内容的相关信息将被传递至Activity文件的合适位置。请查看[官方安卓文档][android-launch-modes]了解关于`android:launchMode`属性值的更多信息。 + +通过`Intent`对象发送至您指定的Activity的深度链接内容信息将可能被传递至两个位置 —— Activity的`onCreate`或者`onNewIntent`方式。一旦应用被打开,方式被触发后,您将获得在点击URL中被传递至`deep_link`参数中的实际深度链接。您可以使用这些信息为应用增加一些附加逻辑。 + +您可以按以下两种方式提取深度链接内容: + +```java +@Override +protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_main); + + Intent intent = getIntent(); + Uri data = intent.getData(); + // data.toString() -> This is your deep_link parameter value. +} +``` + +```java +@Override +protected void onNewIntent(Intent intent) { + super.onNewIntent(intent); + + Uri data = intent.getData(); + // data.toString() -> This is your deep_link parameter value. +} +``` + +### 延迟深度链接场景 + +延迟深度链接场景发生在当用户点击了带有`deep_link`参数的Adjust跟踪链接,但用户在点击时还未在其设备中安装应用。点击链接后,用户将被重定向至Google Play商店下载和安装您的应用。用户首次打开该应用后,`deep_link`参数将被发送至应用。 + +为了在延迟深度链接场景下获取关于`deep_link`参数内容的相关信息,您需要在`AdjustConfig`对象中设置一个监听器。一旦Adjust SDK从后台获取到关于深度链接内容的信息,该监听器将被触发。 + +```java +AdjustConfig config = new AdjustConfig(this, appToken, environment); + +// Evaluate the deeplink to be launched. +config.setOnDeeplinkResponseListener(new OnDeeplinkResponseListener() { + @Override + public boolean launchReceivedDeeplink(Uri deeplink) { + // ... + if (shouldAdjustSdkLaunchTheDeeplink(deeplink)) { + return true; + } else { + return false; + } + } +}); + +Adjust.onCreate(config); +``` + +一旦Adjust SDK从后台接收到关于深度链接内容的信息,将在监听器内向您传递相关内容信息,并等待您的`boolean`返回值。该返回值决定是否由Adjust SDK启动您从深度链接已分配方案名称的Activity(如标准深度链接场景一样)。 + +如果您的返回值为`true`,我们将启动该Activity, 这和[标准深度链接场景章节](#deeplinking-standard)所描述的情况一样。如果您不希望SDK启动Activity,您可以从监听器返回`false`值,并根据深度链接内容自行决定下一步动作。 + +### 通过深度链接的再归因 + +Adjust能够让您使用深度链接来运行再参与推广活动。您可查看我们的[官方文档][reattribution-with-deeplinks],了解更多相关信息。 + +如果您正在使用该功能,为了准确地再归因您的用户,您需要在应用中作一个额外回传至Adjust SDK。 + +一旦您已经在应用中收到深度链接内容信息,请添加回传至 `Adjust.appWillOpenUrl(Uri, Context)` 方式。添加该回传后,Adjust SDK将尝试查找在深度链接中是否有任何新的归因信息,一旦找到,该信息将被发送至Adjust后台。如果您的用户因为点击带有深度链接内容的Adjust 跟踪链接,而应该被再归因,您将会看到应用中的[归因回传](#attribution-callback)被该用户的新归因信息触发。 + +请如下示添加至`Adjust.appWillOpenUrl(Uri, Context)`的回传: + +```java +@Override +protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_main); + + Intent intent = getIntent(); + Uri data = intent.getData(); + Adjust.appWillOpenUrl(data, getApplicationContext()); +} +``` + +```java +@Override +protected void onNewIntent(Intent intent) { + super.onNewIntent(intent); + + Uri data = intent.getData(); + Adjust.appWillOpenUrl(data, getApplicationContext()); +} +``` + +**注意**: `Adjust.appWillOpenUrl(Uri)` 方法从 Android SDK v4.14.0 起已被标记为 **deprecated**,请使用 `Adjust.appWillOpenUrl(Uri, Context)` 方法。 + +## 故障排查 + +### 显示"Session failed (Ignoring too frequent session. ...)" 出错信息 + +该错误信息一般于测试安装时出现的。单单卸载然后再安装应用并不足以触发新的安装。由于我们服务器已经有该设备的纪录,服务器只会判断为SDK失去了本地的会话数据而忽视该错误信息。 + +虽然该行为可能在测试阶段比较麻烦,但确是必须的,目的是为了让测试(sandbox)流程尽量等同于真实(production)流程。 + +您可以清除该设备在我们服务器中的会话数据。请查看日志显示的错误信息: + +``` +Session failed (Ignoring too frequent session. Last session: YYYY-MM-DDTHH:mm:ss, this session: YYYY-MM-DDTHH:mm:ss, interval: XXs, min interval: 20m) (app_token: {yourAppToken}, adid: {adidValue}) +``` + +输入`{yourAppToken}`和`{adidValue}`/`{gps_adidValue}`/`{androidIDValue}` 值后,打开下列其中一个链接: + +``` +http://app.adjust.com/forget_device?app_token={yourAppToken}&adid={adidValue} +``` + +``` +http://app.adjust.com/forget_device?app_token={yourAppToken}&gps_adid={gps_adidValue} +``` + +``` +http://app.adjust.com/forget_device?app_token={yourAppToken}&android_id={androidIDValue} +``` + +当成功清除该设备的记录后,链接将返回`Forgot device`信息。如果设备在启用以上链接前已经被清除了,或者填写的设备值有任何错误,返回的信息将会是`Device not found`。 + +### 我的广播接收器是否能成功获取install referrer? + +如果您按照[指南](#broadcast_receiver)描述的步骤来设置, 广播接收器就应该可以将install referrer发送到SDK以及我们的服务器。 + +为了测试设置是否正确,您可以手动触发一个install referrer测试。用您的应用ID替换`com.your.appid`,然后使用Android Studio包括的[adb](http://developer.android.com/tools/help/adb.html)工具,执行以下命令。 + +``` +adb shell am broadcast -a com.android.vending.INSTALL_REFERRER -n com.your.appid/com.adjust.sdk.AdjustReferrerReceiver --es "referrer" "adjust_reftag%3Dabc1234%26tracking_id%3D123456789%26utm_source%3Dnetwork%26utm_medium%3Dbanner%26utm_campaign%3Dcampaign" +``` + +如果您已经按照该指南设置了另一个广播接收器使用`INSTALL_REFERRER`intent,请用`com.adjust.sdk.AdjustReferrerReceiver`替换您设置的广播接收器。 + +您也可以删除`-n com.your.appid/com.adjust.sdk.AdjustReferrerReceiver`参数,以让设备上的所有应用接收`INSTALL_REFERRER`intent。 + +如果您将日志量设置为`verbose`,您应该可以通过读取referrer查看日志: + +``` +V/Adjust: Reading query string (adjust_reftag=abc1234&tracking_id=123456789&utm_source=network&utm_medium=banner&utm_campaign=campaign) from reftag +``` + +以及添加点击包(click package)到SDK包: + +``` +V/Adjust: Path: /sdk_click + ClientSdk: android4.6.0 + Parameters: + app_token abc123abc123 + click_time yyyy-MM-dd'T'HH:mm:ss.SSS'Z'Z + created_at yyyy-MM-dd'T'HH:mm:ss.SSS'Z'Z + environment sandbox + gps_adid 12345678-0abc-de12-3456-7890abcdef12 + needs_attribution_data 1 + referrer adjust_reftag=abc1234&tracking_id=123456789&utm_source=network&utm_medium=banner&utm_campaign=campaign + reftag abc1234 + source reftag + tracking_enabled 1 +``` + +如果您在启动应用前执行以上测试,软件包将不会被发送。以上软件包将于应用启动后被发送。 + +**重要:** 请注意,使用`adb`工具来测试该特定功能并不是最佳的方式。为了测试完整的referrer内容(在由`&`分隔多个参数的情况下),如使用`adb`工具您需要对内容进行编码以便发送给广播接收器。如未编码,`adb`将在第一个`&`符号后剪切referrer,并向您的广播接收器发送错误内容。 + +如果您希望查看应用如何接收未编码的referrer值,您可使用我们的示例应用,并更改传递的内容,以便被`MainActivity.java`文件内`onFireIntentClick`方法中的意图触发: + + ```java +public void onFireIntentClick(View v) { + Intent intent = new Intent("com.android.vending.INSTALL_REFERRER"); + intent.setPackage("com.adjust.examples"); + intent.putExtra("referrer", "utm_source=test&utm_medium=test&utm_term=test&utm_content=test&utm_campaign=test"); + sendBroadcast(intent); +} +``` + +您可随意使用自选内容更改`putExtra`方法的第二个参数。 + +### 我是否可以在应用激活时触发事件? + +和您想象的可能不一样,在`Application`全局类上的`onCreate`方法不仅在应用激活时被调用,而且每当应用记录到系统或应用事件时也被调用。 + +此时,我们的SDK已经准备初始化了,但是还没有正式启动。只有当activity开始时,即当用户真正激活应用时,SDK才会正式启动。 + +因此,此时的触发事件将不会达到您期望的结果。即使当用户并没有激活应用,这样调用将会启动Adjust SDK以及发送事件——具体时间取决于应用的外部因素。 + +在应用激活时触发事件将会导致被跟踪的安装及会话数量的不准确。 + +如果您希望在安装后触发事件,请使用[归因变化监听器](#attribution_changed_listener)。 + +如果您希望在应用激活后触发事件,请使用被启动的Activity的`onCreate`方法。 + +[dashboard]: http://adjust.com +[adjust.com]: http://adjust.com +[en-readme]: ../../README.md +[zh-readme]: ../chinese/README.md +[ja-readme]: ../japanese/README.md +[ko-readme]: ../korean/README.md + +[maven]: http://maven.org +[example-java]: ../../Adjust/example-app-java +[example-tv]: ../../Adjust/example-app-tv +[releases]: https://github.com/adjust/adjust_android_sdk/releases +[referrer]: doc/english/referrer.md +[google_ad_id]: https://support.google.com/googleplay/android-developer/answer/6048248?hl=en +[event-tracking]: https://docs.adjust.com/zh/event-tracking +[callbacks-guide]: https://docs.adjust.com/zh/callbacks +[new-referrer-api]: https://developer.android.com/google/play/installreferrer/library.html +[application_name]: http://developer.android.com/guide/topics/manifest/application-element.html#nm +[special-partners]: https://docs.adjust.com/zh/special-partners +[attribution-data]: https://github.com/adjust/sdks/blob/master/doc/attribution-data.md +[android-dashboard]: http://developer.android.com/about/dashboards/index.html +[currency-conversion]: https://docs.adjust.com/zh/event-tracking/#tracking-purchases-in-different-currencies +[android_application]: http://developer.android.com/reference/android/app/Application.html +[android-launch-modes]: https://developer.android.com/guide/topics/manifest/activity-element.html +[google_play_services]: http://developer.android.com/google/play-services/setup.html +[activity_resume_pause]: doc/activity_resume_pause.md +[reattribution-with-deeplinks]: https://docs.adjust.com/zh/deeplinking/#manually-appending-attribution-data-to-a-deep-link +[android-purchase-verification]: https://github.com/adjust/android_purchase_sdk + + +## 许可协议 + +The Adjust SDK is licensed under the MIT License. + +Copyright (c) 2012-2018 Adjust GmbH, http://www.adjust.com + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/doc/chinese/fb_pixel_zh.md b/doc/chinese/fb_pixel_zh.md new file mode 100644 index 000000000..3fd503537 --- /dev/null +++ b/doc/chinese/fb_pixel_zh.md @@ -0,0 +1,115 @@ +## Facebook像素集成 + +[Facebook像素](https://www.facebook.com/business/help/952192354843755)是由Facebook提供的仅限于Web的分析工具。在过去,我们无法使用Facebook SDK来跟踪应用网页视图(Webview)中的像素事件。[FB SDK](https://developers.facebook.com/docs/analytics)4.34版本的发布使之成为可能,并通过[混合移动应用事件(Hybrid Mobile App Events)](https://developers.facebook.com/docs/app-events/hybrid-app-events)将Facebook像素事件转化为Facebook应用事件。 + +您现在还可通过Adjust SDK跟踪Facebook像素,而无需集成FB SDK。 + +## Facebook集成 + +### 示例应用 + +[`example-fbpixel`目录][example-fbpixel]中的示例应用向您演示了如何使用Adjust网页视图SDK跟踪Facebook像素事件。 + +### Facebook应用ID + +虽然无需集成FB SDK,但您必须遵循与FB SDK相同的一些集成步骤以将Facebook像素集成到Adjust SDK中。 + +如[FB SDK安卓SDK指南](https://developers.facebook.com/docs/android/getting-started/#app_id)中所述,您须将Facebook应用ID添加到应用中。 您可按照该指南中的步骤操作,同时我们将步骤复制如下: + +- 打开`strings.xml`文件。示例路径:`/app/src/main/res/values/strings.xml`。 +- 添加新的字符串(名称为`facebook_app_id`,值为Facebook应用ID)。 +- 打开`AndroidManifest.xml`。 +- 将`uses-permission`元素添加到清单: + + ```xml + + ``` + +- 将`meta-data`元素添加到`application`元素中: + +```xml + + ... + + ... + + ``` + +### Facebook像素配置 + +请参考Facebook指南了解如何集成Facebook像素。Javascript代码应如下所示: + +```js + + +... + +``` + +现在,如[混合移动应用事件指南](https://developers.facebook.com/docs/app-events/hybrid-app-events)`Update Your Pixel(更新您的像素)`部分所述,您须更新Facebook像素代码如下: + +```js +fbq('init', ); +fbq('set', 'mobileBridge', , ); +``` + +**注意**:**非常重要**的一点是您必须首先调用''init'`并且之后立即调用`'set'`方法。Facebook提供给您需粘贴到HTML网页的代码片段(如上所示)包含调用`'init'`方法后的页面视图事件的`'track'`方法。为了正确跟踪此页面视图事件,请务必在两者之间调用`'set'`方法! + +## Adjust集成 + +### 注册Facebook SDK Javascript界面 + +请按照[安卓Web视图SDK](web_views.md)应用的集成指南进行操作。如下文注册和获取Adjust bridge默认实例: + +```java +AdjustBridge.registerAndGetInstance(getApplication(), webview); +``` + +保存返回实例,如`adjustBridgeInstance`,然后添加以下行: + +```java +adjustBridgeInstance.registerFacebookSDKJSInterface(); +``` + +### 事件名称配置 + +Adjust网桥SDK将Facebook像素事件转化为Adjust事件。 + +因此,您必须将Facebook像素映射到特定的Adjust事件,或者在启动Adjust SDK和跟踪任意Facebook像素事件***之前***配置默认的Adjust事件识别码,包括从Facebook像素配置中复制粘贴的`fbq('track', 'PageView');`。 + +为了将Facebook像素事件映射到Adjust事件,请在初始化Adjust SDK之前在`adjustConfig`实例中调用`addFbPixelMapping(fbEventNameKey,adjEventTokenValue)`。应类似以下示例: + +```js +adjustConfig.addFbPixelMapping('fb_mobile_search', adjustEventTokenForSearch); +adjustConfig.addFbPixelMapping('fb_mobile_purchase', adjustEventTokenForPurchase); +``` + +请注意,在跟踪Facebook像素事件:`fbq('track', 'Search', ...);` 和 `fbq('track', 'Purchase', ...);` 时应可实现匹配。但遗憾的是我们无法访问Javascript中跟踪的事件名称与FB SDK使用的事件名称之间的完整映射方案。 + +以下为到目前为止我们收集的事件名称信息,供您参考: + +| 像素事件名称 | 对应Facebook应用事件名称 +| ---------------- | ------------------------------------- +| ViewContent | fb_mobile_content_view +| Search | fb_mobile_search +| AddToCart | fb_mobile_add_to_cart +| AddToWishlist | fb_mobile_add_to_wishlist +| InitiateCheckout | fb_mobile_initiated_checkout +| AddPaymentInfo | fb_mobile_add_payment_info +| Purchase | fb_mobile_purchase +| CompleteRegistration | fb_mobile_complete_registration + +以上列表也许还不完整;Facebook也可能添加或更新当前列表。在测试时,请查看Adjust日志以获取提示信息,例如: + +``` +未就名称为:'fb_mobile_search'的事件配置默认事件识别码或找到匹配。它将不会被Adjust作为事件来跟踪。 +``` + +如果您未配置映射,还可以选择使用默认的Adjust事件。您只需在初始化Adjust SDK之前调用`adjustConfig.setFbPixelDefaultEventToken(defaultEventToken);`。 + +[example-fbpixel]: ../../Adjust/example-fbpixel diff --git a/doc/chinese/imei_plugin.md b/doc/chinese/imei_plugin.md new file mode 100644 index 000000000..5b49abffd --- /dev/null +++ b/doc/chinese/imei_plugin.md @@ -0,0 +1,970 @@ +## 摘要 + +这是Adjust™的安卓SDK包。您可以访问[adjust.com]了解更多有关Adjust™的信息。 + +**重要:** 本指南仅适用于**非Google Play商店**中发布的应用。如果您的应用需在Google Play商店发布,请移步至[另一指南](README.md)。 + +## 目录 + +* [应用示例](#example-apps) +* [基本集成](#basic-integration) + * [添加SDK至您的项目](#sdk-add) + * [添加权限](#sdk-permissions) + * [Proguard设置](#sdk-proguard) + * [集成SDK至您的应用](#sdk-integrate) + * [基本设置](#basic-setup) + * [会话跟踪](#session-tracking) + * [API level 14及以上版本](#session-tracking-api14) + * [API level 9-13版本](#session-tracking-api9) + * [Adjust日志](#adjust-logging) + * [IMEI 插件](#imei-plugin) + * [构建您的应用](#build-the-app) +* [附加功能](#additional-features) + * [事件跟踪](#event-tracking) + * [收入跟踪](#revenue-tracking) + * [收入重复数据删除](#revenue-deduplication) + * [回调参数](#callback-parameters) + * [合作伙伴参数](#partner-parameters) + * [回调ID](#callback-id) + * [会话参数](#session-parameters) + * [会话回调参数](#session-callback-parameters) + * [会话合作伙伴参数](#session-partner-parameters) + * [延迟启动](#delay-start) + * [归因回传](#attribution-callback) + * [会话和事件回传](#session-event-callbacks) + * [禁用跟踪](#disable-tracking) + * [离线模式](#offline-mode) + * [事件缓冲](#event-buffering) + * [GDPR 的被遗忘权](#gdpr-forget-me) + * [SDK签名](#sdk-signature) + * [后台跟踪](#background-tracking) + * [设备ID](#device-ids) + * [Amazon广告ID](#di-amz-adid) + * [Adjust设备ID](#di-adid) + * [用户归因](#user-attribution) + * [推送标签(Push token)](#push-token) + * [预安装跟踪码](#pre-installed-trackers) + * [深度链接](#deeplinking) + * [标准深度链接场景](#deeplinking-standard) + * [延迟深度链接场景](#deeplinking-deferred) + * [通过深度链接的再归因](#deeplinking-reattribution) +* [故障排查](#troubleshooting) + * [显示 "Session failed (Ignoring too frequent session. ...)" 出错信息](#ts-session-failed) + * [我是否可以在应用激活时触发事件?](#ts-event-at-launch) +* [许可协议](#license) + +## 应用示例 + +[`example`目录][example]内有安卓应用示例,[`example-tv` directory][example-tv]内有安卓 TV 应用示例。您可以打开安卓项目查看如何集成Adjust SDK的示例。 + +## 基本集成 + +我们将向您介绍把Adjust SDK集成到安卓项目的最基本步骤。我们假定您将Android Studio用于安卓开发,并以安卓API level 9(Gingerbread)及以上版本为目标对象。 + +### 添加SDK至您的项目 + +如果您正在使用Maven,请添加下行至您的`build.gradle`文件: + +``` +compile 'com.adjust.sdk:adjust-android:4.16.0' +``` + +**注意**:如果您正在使用`Gradle 3.0.0 or above`,请确保使用的是`implementation`关键词而不是`compile`,如下所示: + +``` +implementation 'com.adjust.sdk:adjust-android:4.16.0' +``` + +--- + +您还可将Adjust SDK作为JAR库添加到项目中。最新SDK版本的JAR库可从我们的[发布专页][releases]中获取。 + +### 添加权限 + +如果您还未在`AndroidManifest.xml`文件中添加Adjust需要的如下权限,请进行添加: + +```xml + + + +``` + +### Proguard设置 + +如果您正在使用Proguard,请添加如下代码行至您的Proguard文件: + +``` +-keep public class com.adjust.sdk.** { *; } +``` + +### 集成SDK至您的应用 + +我们从设置基本会话跟踪开始。 + +### 基本设置 + +我们推荐使用全局安卓[应用程序][android_application]类来初始化SDK。如果您的应用中还没有此类,请按照以下步骤设置: + +1. 创建一个扩展`Application`的类。 + ![][application_class] + +2. 打开应用中的`AndroidManifest.xml`文件并找到 `` 元素。 +3. 添加`android:name`属性,将其设置为您的新应用程序类的名称,并带一个点为前缀。 + + 在此应用示例中,我们将`Application`类命名为`GlobalApplication`,因此manifest文件被设置为: + + ```xml + + ... + + ``` + + ![][manifest_application] + +4. 在您的`Application`类中找到或者创建`onCreate`方法,并添加如下代码来初始化Adjust SDK: + + ```java + import com.adjust.sdk.Adjust; + import com.adjust.sdk.AdjustConfig; + + public class GlobalApplication extends Application { + @Override + public void onCreate() { + super.onCreate(); + + String appToken = "{YourAppToken}"; + String environment = AdjustConfig.ENVIRONMENT_SANDBOX; + AdjustConfig config = new AdjustConfig(this, appToken, environment); + Adjust.onCreate(config); + } + } + ``` + + ![][application_config] + + 将`{YourAppToken}`替换为您的应用识别码(app token)。您可以在[控制面板][dashboard]中找到该应用识别码。 + + 取决于您的应用制作是用于测试或产品开发目的,您必须将`environment`(环境模式)设为以下值之一: + + ```java + String environment = AdjustConfig.ENVIRONMENT_SANDBOX; + String environment = AdjustConfig.ENVIRONMENT_PRODUCTION; + ``` + + **重要:** 仅当您或其他人测试您的应用时,该值应设为 `AdjustConfig.ENVIRONMENT_SANDBOX`。在您发布应用之前,请确保将环境改设为 `AdjustConfig.ENVIRONMENT_PRODUCTION`。再次研发和测试时,请将其设回为 `AdjustConfig.ENVIRONMENT_SANDBOX`。 + + 我们按照设置的环境来区分真实流量和来自测试设备的测试流量。非常重要的是,您必须始终让该值保持有意义!这一点在您进行收入跟踪时尤为重要。 + +### 会话跟踪 + +**注意**:此步骤**非常重要**,请**确保您在应用中正确设置它**。设置之后,Adjust SDK将对您的应用进行会话跟踪。 + +### API level 14及以上版本 + +1. 添加一个私有类(private class)以实现`ActivityLifecycleCallbacks`接口。如果您不能访问该接口,则表示您的应用仅支持安卓API level 14以下版本。在此种情况下,请按照此[说明](#session-tracking-api9)手动更新每项Activity。如果您在之前已经对应用的每个Activity调用了`Adjust.onResume`和`Adjust.onPause`,请将其全部删除。 + + ![][activity_lifecycle_class] + +2. 编辑`onActivityResumed(Activity activity)`方法,添加对`Adjust.onResume()`的调用。编辑`onActivityPaused(Activity activity)`方法,添加对`Adjust.onPause()`的调用。 + + ![][activity_lifecycle_methods] + +3. 在设置Adjust SDK的位置添加`onCreate()` 方法,并添加调用 `registerActivityLifecycleCallbacks`以及被创建的`ActivityLifecycleCallbacks`类实例。 + + ```java + import com.adjust.sdk.Adjust; + import com.adjust.sdk.AdjustConfig; + + public class GlobalApplication extends Application { + @Override + public void onCreate() { + super.onCreate(); + + String appToken = "{YourAppToken}"; + String environment = AdjustConfig.ENVIRONMENT_SANDBOX; + AdjustConfig config = new AdjustConfig(this, appToken, environment); + Adjust.onCreate(config); + + registerActivityLifecycleCallbacks(new AdjustLifecycleCallbacks()); + + //... + } + + private static final class AdjustLifecycleCallbacks implements ActivityLifecycleCallbacks { + @Override + public void onActivityResumed(Activity activity) { + Adjust.onResume(); + } + + @Override + public void onActivityPaused(Activity activity) { + Adjust.onPause(); + } + + //... + } + } + ``` + + ![][activity_lifecycle_register] + +### API level 9-13版本 + +如果您的应用gradle中的`minSdkVersion`是在9至13版本之间,您应当考虑至少升级至版本14以简化集成流程。请咨询官方安卓[控制面板][android-dashboard]了解目前市场上广泛使用的主要版本。 + +为了进行准确的会话跟踪,每当任一Activity重新开始或者暂停时都需要调用某个Adjust SDK方法。否则SDK可能会错过一个会话开始或者会话结束。**请遵循以下步骤对您的应用中的每个 +Activity**进行正确设置: + +1. 打开Activity的源文件。 +2. 在文件顶部添加`import`语句。 +3. 在Activity的`onResume`方法中调用 Adjust.onResume`。必要时创建该方法。 +4. 在Activity的`onPause`方法中调用`Adjust.onPause`。必要时创建该方法。 + +完成以上步骤后,您的Activity应如下: + +```java +import com.adjust.sdk.Adjust; +// ... +public class YourActivity extends Activity { + protected void onResume() { + super.onResume(); + Adjust.onResume(); + } + protected void onPause() { + super.onPause(); + Adjust.onPause(); + } + // ... +} +``` + +![][activity] + +对您的应用中的**每个**Activity重复以上步骤。如果您在之后创建新的Activity,也请按照以上步骤设置。取决于您的编码方式,您也可通过设置所有Activitiy的通用超类来实现它。 + +### Adjust日志 + +您可以增加或减少在测试中看到的日志数量,方法是用以下参数之一来调用`AdjustConfig`实例上的`setLogLevel`: + +```java +config.setLogLevel(LogLevel.VERBOSE); // enable all logging +config.setLogLevel(LogLevel.DEBUG); // enable more logging +config.setLogLevel(LogLevel.INFO); // the default +config.setLogLevel(LogLevel.WARN); // disable info logging +config.setLogLevel(LogLevel.ERROR); // disable warnings as well +config.setLogLevel(LogLevel.ASSERT); // disable errors as well +config.setLogLevel(LogLevel.SUPRESS); // disable all log output +``` +如果您希望禁用所有日志输出,除了将日志级别设置为抑制以外,您还应该对`AdjustConfig`对象使用构建函数,它将获取boolean参数来显示是否应该支持抑制日志级别: + +```java +String appToken = "{YourAppToken}"; +String environment = AdjustConfig.ENVIRONMENT_SANDBOX; + +AdjustConfig config = new AdjustConfig(this, appToken, environment, true); +config.setLogLevel(LogLevel.SUPRESS); + +Adjust.onCreate(config); +``` + +### IMEI插件 + +对于特定市场,IMEI 及 MEID 可被用于安卓的归因。如希望启用该功能,请按照我们[文档][imei_doc]中的指引,于 Adjust 控制面板中完成必要的设置,然后添加本插件。 + +关于设备 ID 的读取,本 IMEI 插件依然遵循 Adjust 安卓 SDK 的 [逻辑][gps_adid],并在此基础上**额外地**允许 Adjust 安卓 SDK 读取设备的 IMEI 和 MEID 值。 + +如果您使用的是 Maven,请在您的 `build.gradle` 文件中添加: + +``` +compile 'com.adjust.sdk:adjust-android-imei:4.16.0' +``` + +如果您的 `AndroidManifest.xml` 文件中尚未包含以下权限,请添加: + +```xml + +``` + +请注意,对于安卓6.0后的版本,有可能需要 [请求应用权限](https://developer.android.com/training/permissions/requesting),除非安卓操作系统已被更改。 + +最后,请在启动 SDK 前,调用 `AdjustImei.readImei()` 以读取 IMEI 和 MEID 值: + +```java +// ... + +AdjustImei.readImei(); +Adjust.onCreate(config); + +// ... +``` + +如要 SDK 停止读取 IMEI 和 MEID 值,可调用 `AdjustIMEI.doNotReadImei()` 方法。 + +然而,**请注意** IMEI 和 MEID 是持久识别符(persistent identifier),这将是您的责任确保从您终端用户处收集和处理该项个人信息是合法的。 + +### 构建您的应用 + +构建并运行您的安卓应用。在`LogCat`查看工具中,您可以设置筛选`tag:Adjust`来隐藏所有其他日志。应用启动后,您可看到以下Adjust日志:`Install tracked`(安装已跟踪)。 + +![][log_message] + +## 附加功能 + +一旦您已经成功将Adjust SDK集成到您的项目中,您便可以使用以下功能。 + +### 事件跟踪 + +您可以使用Adjust来跟踪应用中的任何事件。假设您想要跟踪具体按钮的每次点击,您必须在[控制面板][dashboard]中创建一个新的事件识别码(Event Token)。例如事件识别码是`abc123`,在按钮的`onClick`方法中,您可以添加以下代码行来跟踪点击: + +```java +AdjustEvent event = new AdjustEvent("abc123"); +Adjust.trackEvent(event); +``` + +### 收入跟踪 + +如果您的用户可以通过点击广告或应用内购为您带来收入,您可以按照事件来跟踪这些收入。假设一次点击值一欧分,那么您可以这样来跟踪收入事件: + +```java +AdjustEvent event = new AdjustEvent("abc123"); +event.setRevenue(0.01, "EUR"); +Adjust.trackEvent(event); +``` + +当然,这也可以和回调参数相结合。 + +您设置货币类型后,Adjust将自动把收入转换为您选择的货币类型。阅读这里了解有关[货币转换][currency-conversion]的更多信息。 + +您可以在[事件跟踪指南][event-tracking]中了解更多有关收入和事件跟踪的内容。 + +### 收入重复数据删除 + +您也可以输入可选的交易ID,以避免跟踪重复收入。最近的十个交易ID将被记录下来,重复交易ID的收入事件将被跳过。这对于应用内购跟踪尤其有用。参见以下例子。 + +如果您想要跟踪应用内购,请确保只有交易完成以及产品被购买后调用`trackEvent`。这样您可以避免跟踪实际未产生的收入。 + +```java +AdjustEvent event = new AdjustEvent("abc123"); + +event.setRevenue(0.01, "EUR"); +event.setOrderId("{OrderId}"); + +Adjust.trackEvent(event); +``` + +### 回调参数 + +您可以在[控制面板][dashboard]中为您的事件登记回调URL。跟踪到事件时,我们会向该URL发送GET请求。您可以在跟踪事件之前调用事件实例的`addCallbackParameter`,向该事件添加回调参数。然后我们会将这些参数添加至您的回调URL。 + +假设您已经登记URL为`http://www.adjust.com/callback` ,然后如下行跟踪事件: + +```java +AdjustEvent event = new AdjustEvent("abc123"); + +event.addCallbackParameter("key", "value"); +event.addCallbackParameter("foo", "bar"); + +Adjust.trackEvent(event); +``` + +在这种情况下,我们会跟踪该事件并发送请求至: + +``` +http://www.adjust.com/callback?key=value&foo=bar +``` + +请注意,我们不保存您的任何定制参数,而只是将它们添加到您的回调中。如果您没有为事件输入回调地址,这些参数甚至不会被读取。 + +您可以在我们的[回调指南][callbacks-guide]中了解到有关使用URL回调的更多信息,包括可用值的完整列表。 + +### 合作伙伴参数 + +您还可以针对您已在Adjust控制面板中激活的渠道合作伙伴添加被发送至合作伙伴的参数。 + +方式和上述提及的回调参数类似,可以通过调用您的`AdjustEvent`实例上的`addPartnerParameter`方法来添加。 + +```java +AdjustEvent event = new AdjustEvent("abc123"); + +event.addPartnerParameter("key", "value"); +event.addPartnerParameter("foo", "bar"); + +Adjust.trackEvent(event); +``` +您可在我们的[特殊合作伙伴指南][special-partners]中了解到有关特殊合作伙伴和集成的更多信息。 + +### 回调ID +您还可为想要跟踪的每个事件添加自定义字符串ID。此ID将在之后的事件成功和/或事件失败回调中被报告,以便您了解哪些事件跟踪成功或者失败。您可通过调用`AdjustEvent`实例上的`setCallbackId`方法来设置此ID: + + ```java +AdjustEvent event = new AdjustEvent("abc123"); + event.setCallbackId("Your-Custom-Id"); + Adjust.trackEvent(event); +``` + +### 会话参数 + +一些参数被保存发送到Adjust SDK的每一个**事件**和**会话**中。一旦您已经添加任一这些参数,您无需再每次添加它们,因为这些参数已经被保存至本地。如果您添加同样参数两次,也不会有任何影响。 + +这些会话参数在Adjust SDK上线之前可以被调用,以确保它们即使在安装时也可被发送。如果您需要在安装同时发送参数,但只有在SDK上线后才能获取所需的值,您可以通过[延迟](#delay-start)Adjust SDK第一次上线以允许该行为。 + +### 会话回调参数 + +注册在[事件](#callback-parameters)中的相同回调参数也可以被保存发送至Adjust SDK的每一个事件和会话中。 + +会话回调参数拥有与事件回调参数类似的接口。该参数是通过调用`Adjust.addSessionCallbackParameter(String key, String value)`被添加,而不是通过添加Key和值至事件: + +```java +Adjust.addSessionCallbackParameter("foo", "bar"); +``` + +会话回调参数将与被添加至事件的回调参数合并。被添加至事件的回调参数拥有高于会话回调参数的优先级。这意味着,当被添加至事件的回调参数拥有与会话回调参数同样Key时,以被添加至事件的回调参数值为准。 + +您可以通过传递Key至`Adjust.removeSessionCallbackParameter(String key)`的方式来删除特定会话回调参数。 + +```java +Adjust.removeSessionCallbackParameter("foo"); +``` + +如果您希望删除会话回调参数中所有的Key及相应值,您可以通过`Adjust.resetSessionCallbackParameters()`方式重置: + +```java +Adjust.resetSessionCallbackParameters(); +``` + +### 会话合作伙伴参数 + +与[会话回调参数](#session-callback-parameters)的方式一样,会话合作伙伴参数也将被发送至Adjust SDK的每一个事件和会话中。 + +它们将被传送至渠道合作伙伴,以集成您在Adjust[控制面板][dashboard]上已经激活的模块。 + +会话合作伙伴参数具有与事件合作伙伴参数类似的接口。该参数是通过调用`Adjust.addSessionPartnerParameter(String key, String value)`被添加,而不是通过添加Key和值至事件: + +```java +Adjust.addSessionPartnerParameter("foo", "bar"); +``` + +会话合作伙伴参数将与被添加至事件的合作伙伴参数合并。被添加至事件的合作伙伴参数具有高于会话合作伙伴参数的优先级。这意味着,当被添加至事件的合作伙伴参数拥有与会话合作伙伴参数同样Key时,以被添加至事件的合作伙伴参数值为准。 + +您可以通过传递Key至`Adjust.removeSessionPartnerParameter(String key)`方式来删除特定的会话合作伙伴参数: + +```java +Adjust.removeSessionPartnerParameter("foo"); +``` + +如果您希望删除会话合作伙伴参数中所有的Key及其相应值,您可以通过`Adjust.resetSessionPartnerParameters()`方式重置: + +```java +Adjust.resetSessionPartnerParameters(); +``` + +### 延迟启动 + +延迟Adjust的SDK启动可以给您的应用一些时间获取被发送至安装的会话参数,如唯一识别码(unique identifiers)等。 + +通过在`AdjustConfig` 实例中的`setDelayStart`(设置延迟启动)方式以秒为单位设置初始延迟时间: + +```java +adjustConfig.setDelayStart(5.5); +``` + +在此种情况下,Adjust SDK不会在5.5秒内发送初始安装会话以及创建任何事件。在该时间过期后或您同时调用`Adjust.sendFirstPackages()`,每个会话参数将被添加至延迟安装的会话和事件中,Adjust SDK将恢复正常。 + +**Adjust SDK最长的延迟启动时间为10秒。** + +### 归因回传 + +您可以注册一个监听器(listener),以获取跟踪链接归因变化的通知。由于考虑到归因的不同来源,归因信息无法被同步提供。最简单的方式是创建一个单一的匿名监听器: + +请您务必考虑我们的[适用归因数据政策][attribution-data]。 + +使用`AdjustConfig` 实例,在启动SDK之前添加匿名监听器: + +```java +AdjustConfig config = new AdjustConfig(this, appToken, environment); + +config.setOnAttributionChangedListener(new OnAttributionChangedListener() { + @Override + public void onAttributionChanged(AdjustAttribution attribution) { + } +}); + +Adjust.onCreate(config); +``` + +或者,您可以在`Application`类中执行`OnAttributionChangedListener`接口,并设置其为监听器: + +```java +AdjustConfig config = new AdjustConfig(this, appToken, environment); +config.setOnAttributionChangedListener(this); +Adjust.onCreate(config); +``` + +监听器函数将在SDK接收到最终归因数据后被调用。在监听器函数中,您可以访问`attribution`(归因)参数。这里是其属性的快捷摘要: + +- `String trackerToken` 目前归因的跟踪码token +- `String trackerName` 目前归因的跟踪码名称 +- `String network` 目前归因的渠道分组级别 +- `String campaign` 目前归因的推广分组级别 +- `String adgroup` 目前归因的广告组分组级别 +- `String creative` 目前归因的创意分组级别 +- `String clickLabel` 目前归因的点击标签 +- `String adid` Adjust设备ID + +当值不可用时,则默认为`null`。 + +### 会话和事件回传 + +您可以注册一个监听器,以在事件或者会话被跟踪时获取通知。共有四个监听器:一个是用来跟踪成功事件,一个跟踪失败事件,一个跟踪成功会话,一个跟踪失败会话。您可以在创建`AdjustConfig`对象后添加任意数量的监听器: + +```java +AdjustConfig config = new AdjustConfig(this, appToken, environment); + +// Set event success tracking delegate. +config.setOnEventTrackingSucceededListener(new OnEventTrackingSucceededListener() { + @Override + public void onFinishedEventTrackingSucceeded(AdjustEventSuccess eventSuccessResponseData) { + // ... + } +}); + +// Set event failure tracking delegate. +config.setOnEventTrackingFailedListener(new OnEventTrackingFailedListener() { + @Override + public void onFinishedEventTrackingFailed(AdjustEventFailure eventFailureResponseData) { + // ... + } +}); + +// Set session success tracking delegate. +config.setOnSessionTrackingSucceededListener(new OnSessionTrackingSucceededListener() { + @Override + public void onFinishedSessionTrackingSucceeded(AdjustSessionSuccess sessionSuccessResponseData) { + // ... + } +}); + +// Set session failure tracking delegate. +config.setOnSessionTrackingFailedListener(new OnSessionTrackingFailedListener() { + @Override + public void onFinishedSessionTrackingFailed(AdjustSessionFailure sessionFailureResponseData) { + // ... + } +}); + +Adjust.onCreate(config); +``` +监听器函数将于SDK发送包(package)到服务器后调用。在监听器函数中,您可以访问专为监听器所设的响应数据对象。成功会话的响应数据对象字段摘要如下: + +- `String message` 服务器信息或者SDK纪录的错误信息 +- `String timestamp` 服务器的时间戳 +- `String adid` Adjust提供的设备唯一识别码 +- `JSONObject jsonResponse` JSON对象及服务器响应 + +两个事件响应数据对象均包含: + +- 如果跟踪的包是一个事件,`String eventToken`代表事件识别码。 +- `String callbackId` 为事件对象设置的自定义回调ID。 + +事件和会话跟踪不成功的对象也均包含: + +- `boolean willRetry`表示稍后将再尝试发送数据包。 + +### 禁用跟踪 + +您可以通过调用`setEnabled`,启用参数为`false`,来禁用Adjust SDK的跟踪功能。**该设置在会话间保存**。 + +```java +Adjust.setEnabled(false); +``` + +您可以通过调用`isEnabled`函数来查看Adjust SDK目前是否被启用。您始终可以通过调用`setEnabled`,启用参数为`true`,来激活Adjust SDK。 + +### 离线模式 + +您可以把Adjust SDK设置离线模式,以暂停发送数据到我们的服务器,但仍然继续跟踪及保存数据并在之后发送。当设为离线模式时,所有数据将存放于一个文件中,所以请注意不要于离线模式触发太多事件。 + +您可以调用`setOfflineMode`,启用参数为`true`,以激活离线模式。 + +```java +Adjust.setOfflineMode(true); +``` + +相反地,您可以调用`setOfflineMode`,启用参数为`false`,以终止离线模式。当Adjust SDK回到在线模式时,所有被保存的数据将被发送到我们的服务器,并保留正确的时间信息。 + +跟禁用跟踪设置不同的是,此设置在会话之间将*不被保存*。这意味着,即使应用在离线模式时被终止,每当SDK启动时都必定处于在线模式。 + +### 事件缓冲 + +如果您的应用大量使用事件跟踪,您可能想要延迟部分HTTP请求,以便按分钟成批发送这些请求。您可以调用`AdjustConfig`实例启用事件缓冲: + +```java +AdjustConfig config = new AdjustConfig(this, appToken, environment); + +config.setEventBufferingEnabled(true); + +Adjust.onCreate(config); +``` + +### GDPR 的被遗忘权 + +根据欧盟的《一般数据保护条例》(GDPR) 第 17 条规定,用户行使被遗忘权时,您可以通知 Adjust。调用以下方法,Adjust SDK 将会收到指示向 Adjust 后端传达用户选择被遗忘的信息: + +```java +Adjust.gdprForgetMe(context); +``` + +收到此信息后,Adjust 将清除该用户数据,并且 Adjust SDK 将停止跟踪该用户。以后不会再向 Adjust 发送来自此设备的请求。 + +### SDK签名 + +账户管理员必须启用SDK签名。如果您希望使用该功能,请联系Adjust技术支持(support@adjust.com)。 + +如果您已经在账户中启用了SDK签名,并可访问Adjust控制面板的应用密钥,请使用以下方法来集成SDK签名到您的应用。 + +在您的`AdjustConfig`实例中调用`setAppSecret`来设置应用密钥。 + +```java +AdjustConfig config = new AdjustConfig(this, appToken, environment); + +config.setAppSecret(secretId, info1, info2, info3, info4); + +Adjust.onCreate(config); +``` + +### 后台跟踪 + +Adjust SDK的默认行为是当应用处于后台时暂停发送HTTP请求。您可以调用`AdjustConfig`实例更改该设置: + +```java +AdjustConfig config = new AdjustConfig(this, appToken, environment); + +config.setSendInBackground(true); + +Adjust.onCreate(config); +``` + +### 设备ID + +Adjust SDK支持您获取一些设备ID。 + +### Amazon广告ID + +如果您需要获取Amazon广告ID,请在`Adjust`实例上调用以下方法: + +```java +String amazonAdId = Adjust.getAmazonAdId(context); +``` + +### Adjust设备ID + +Adjust后台将为每一台安装了您应用的设备生成一个唯一的**Adjust设备ID** (**adid**)。您可在`Adjust`实例上调用以下方法来获取该ID: + +```java +String adid = Adjust.getAdid(); +``` + +**注意**: 此调用只能在Adjust SDK 4.11.0和以上版本中进行。 + +**注意**: 只有在Adjust后台跟踪到应用安装后,您才能获取**adid**的相关信息。自此之后,Adjust SDK已经拥有关于设备**adid**的信息,您可以使用此方法来访问它。因此,在SDK被初始化以及您的应用安装被成功跟踪之前,您将**无法访问adid**。 + +### 用户归因 + +归因回传通过[归因回传章节](#attribution-callback)所描述的方法被触发,以向您提供关于用户归因值的任何更改信息。如果您想要在任何其他时间访问用户当前归因值的信息,您可以通过对`Adjust`实例调用如下属性来实现: + +```java +AdjustAttribution attribution = Adjust.getAttribution(); +``` + +**注意**: 此调用只能在Adjust SDK 4.11.0和以上版本中进行。 + +**注意**: 只有在Adjust后台跟踪到应用安装以及归因回传被触发后,您才能获取有关当前归因的信息。自此之后,Adjust SDK已经拥有用户归因信息,您可以使用此方法来访问它。因此,在SDK被初始化以及归因回传被触发之前,您将**无法访问用户归因值**。 + +### 推送标签(Push token) + +推送标签适用于Adjust受众分群工具(Audience Builder)和客户回传,是卸载跟踪功能的必需信息。 + +每当您获取或更新识别码时,请添加以下调用至Adjust,以发送推送标签给我们: + +```java +Adjust.setPushToken(pushNotificationsToken, context); +``` + +以上添加了`context`的更新后签名让SDK可以涵盖更多的场景,以确保推送标签被发送。因此,我们建议您使用以上签名方式。 + +我们仍支持之前的签名方式: + +```java +Adjust.setPushToken(pushNotificationsToken); +``` + +### 预安装跟踪码 + +如果您希望使用Adjust SDK来识别已在设备中预安装您的应用的用户,请执行以下步骤。 + +1. 在[控制面板][dashboard]中创建一个新的跟踪码。 +2. 打开应用委托,并在`AdjustConfig`实例中添加设置默认跟踪码: + + ```java + AdjustConfig config = new AdjustConfig(this, appToken, environment); + config.setDefaultTracker("{TrackerToken}"); + Adjust.onCreate(config); + ``` + + 用您在步骤1中创建的跟踪码替换`{TrackerToken}`(跟踪码)。请注意,控制面板中显示的是跟踪URL(包括 `http://app.adjust.com/`)。在源代码中,您应该仅指定六个字符的识别码,而不是整个URL。 + +3. 创建并运行您的应用。您应该可以在应用日志输出中看到如下行: + + ``` + Default tracker: 'abc123' + ``` + +### 深度链接 + +如果您正在使用可从网址(URL)深度链接至您应用的Adjust跟踪URL,您将有机会获取深度链接URL及其内容的相关信息。点击URL的情况发生在用户已经安装了您的应用(标准深度链接场景),或用户尚未在其设备上安装您的应用(延迟深度链接场景)。在标准深度链接场景中,安卓平台原生支持您获取关于深度链接内容的信息。但是,安卓平台不提供对延迟深度链接场景的支持。在此情况下,Adjust SDK可以帮助您获取有关深度链接内容的信息。 + +### 标准深度链接场景 + +如果用户已经安装了您的应用,您希望在用户点击带有`deep_link`(深度链接)参数的Adjust跟踪链接后打开应用,您必须在应用中启用深度链接。请定义*唯一方案名称(unique scheme name)*,并将其分配至您希望在用户点击链接后应用打开时启动的Activity中。这可以通过设置在深度链接被点击应用被打开后您希望启动的Activity类的某个属性来实现。您可在`AndroidManifest.xml`中设置它。请在manifest文件中添加`intent-filter`至您指定的Activity定义,并分配指定的方案名至`android:scheme`属性值: + +```xml + + + + + + + + + + + + + + +``` + +以上设置完成后,如果您希望在跟踪链接被点击后打开应用,请在Adjust跟踪链接的`deep_link`参数中使用指定的方案名称。未添加任何深度链接信息的跟踪链接将如下所示: + +``` +https://app.adjust.com/abc123?deep_link=adjustExample%3A%2F%2F +``` + +请记住,在URL中的`deep_link`参数值**必须采用URL编码形式**。 + +如上所述完成应用设置,当您点击跟踪链接后,您的应用将连带`MainActivity`intent(意图)打开。在`MainActivity`类中,您将自动获取关于`deep_link`参数的内容信息。虽然该内容在URL中已编码,但是它在发送给您后**不会被编码**。 + +取决于`AndroidManifest.xml`文件中Activity的`android:launchMode`设置,`deep_link`参数内容的相关信息将被传递至Activity文件的合适位置。请查看[官方安卓文档][android-launch-modes]了解关于`android:launchMode`属性值的更多信息。 + +通过`Intent`对象发送至您指定的Activity的深度链接内容信息将可能被传递至两个位置——Activity的`onCreate`或者`onNewIntent`方式。一旦应用被打开,方式被触发后,您将获得在点击URL中被传递至`deep_link`参数中的实际深度链接。您可以使用这些信息为应用增加一些附加逻辑。 + +您可以按以下两种方式提取深度链接内容: + +```java +@Override +protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_main); + + Intent intent = getIntent(); + Uri data = intent.getData(); + + // data.toString() -> This is your deep_link parameter value. +} +``` + +```java +@Override +protected void onNewIntent(Intent intent) { + super.onNewIntent(intent); + + Uri data = intent.getData(); + + // data.toString() -> This is your deep_link parameter value. +} +``` + +### 延迟深度链接场景 + +延迟深度链接场景发生在当用户点击了带有`deep_link`参数的Adjust跟踪链接,但用户在点击时还未在其设备中安装应用。点击链接后,用户将被重定向至Google Play商店下载和安装您的应用。用户首次打开该应用后,`deep_link`参数将被发送至应用。 + +为了在延迟深度链接场景下获取关于`deep_link`参数内容的相关信息,您需要在`AdjustConfig`对象中设置一个监听器。一旦Adjust SDK从后台获取到关于深度链接内容的信息,该监听器将被触发。 + +```java +AdjustConfig config = new AdjustConfig(this, appToken, environment); + +// Evaluate the deeplink to be launched. +config.setOnDeeplinkResponseListener(new OnDeeplinkResponseListener() { + @Override + public boolean launchReceivedDeeplink(Uri deeplink) { + // ... + if (shouldAdjustSdkLaunchTheDeeplink(deeplink)) { + return true; + } else { + return false; + } + } +}); + +Adjust.onCreate(config); +``` + +一旦Adjust SDK从后台接收到关于深度链接内容的信息,将在监听器内向您传递相关内容信息,并等待您的`boolean`返回值。该返回值决定是否由Adjust SDK启动您从深度链接已分配方案名称的Activity(如标准深度链接场景一样)。 + +如果您的返回值为`true`,我们将启动该Activity, 这和[标准深度链接场景章节](#deeplinking-standard)所描述的情况一样。如果您不希望SDK启动Activity,您可以从监听器返回`false`值,并根据深度链接内容自行决定下一步动作。 + +### 通过深度链接的再归因 + +Adjust能够让您使用深度链接来运行再参与推广活动。您可查看我们的[官方文档][reattribution-with-deeplinks],了解更多相关信息。 + +如果您正在使用该功能,为了准确地再归因您的用户,您需要在应用中作一个额外回传至Adjust SDK。 + +一旦您已经在应用中收到深度链接内容信息,请添加回传至 `Adjust.appWillOpenUrl(Uri, Context)` 方式。添加该回传后,Adjust SDK将尝试查找在深度链接中是否有任何新的归因信息,一旦找到,该信息将被发送至Adjust后台。如果您的用户因为点击带有深度链接内容的Adjust 跟踪链接,而应该被再归因,您将会看到应用中的[归因回传](#attribution-callback)被该用户的新归因信息触发。 + +请如下示添加至`Adjust.appWillOpenUrl(Uri, Context)`的回传: + +```java +@Override +protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_main); + + Intent intent = getIntent(); + Uri data = intent.getData(); + + Adjust.appWillOpenUrl(data, getApplicationContext()); +} +``` + +```java +@Override +protected void onNewIntent(Intent intent) { + super.onNewIntent(intent); + + Uri data = intent.getData(); + + Adjust.appWillOpenUrl(data, getApplicationContext()); +} +``` + +**注意**: `Adjust.appWillOpenUrl(Uri)` 方法从 Android SDK v4.14.0 起已被标记为 **deprecated**,请使用 `Adjust.appWillOpenUrl(Uri, Context)` 方法。 + +## 故障排查 + +### 显示"Session failed (Ignoring too frequent session. ...)" 出错信息 + +该错误信息一般于测试安装时出现的。单单卸载然后再安装应用并不足以触发新的安装。由于我们服务器已经有该设备的纪录,服务器只会判断为SDK失去了本地的会话数据而忽视该错误信息。 + +虽然该行为可能在测试阶段比较麻烦,但确是必须的,目的是为了让测试(sandbox)流程尽量等同于真实(production)流程。 + +您可以清除该设备在我们服务器中的会话数据。请查看日志显示的错误信息: + +``` +Session failed (Ignoring too frequent session. Last session: YYYY-MM-DDTHH:mm:ss, this session: YYYY-MM-DDTHH:mm:ss, interval: XXs, min interval: 20m) (app_token: {yourAppToken}, adid: {adidValue}) +``` + +输入`{yourAppToken}`和`{adidValue}`/`{gps_adidValue}`/`{androidIDValue}` 值后,打开下列其中一个链接: + +``` +http://app.adjust.com/forget_device?app_token={yourAppToken}&adid={adidValue} +``` + +``` +http://app.adjust.com/forget_device?app_token={yourAppToken}&gps_adid={gps_adidValue} +``` + +``` +http://app.adjust.com/forget_device?app_token={yourAppToken}&android_id={androidIDValue} +``` + +当成功清除该设备的记录后,链接将返回`Forgot device`信息。如果设备在启用以上链接前已经被清除了,或者填写的设备值有任何错误,返回的信息将会是`Device not found`。 + +### 我是否可以在应用激活时触发事件? + +和您想象的可能不一样,在`Application`全局类上的`onCreate`方法不仅在应用激活时被调用,而且每当应用记录到系统或应用事件时也被调用。 + +此时,我们的SDK已经准备初始化了,但是还没有正式启动。只有当activity开始时,即当用户真正激活应用时,SDK才会正式启动。 + +因此,此时的触发事件将不会达到您期望的结果。即使当用户并没有激活应用,这样调用将会启动Adjust SDK以及发送事件——具体时间取决于应用的外部因素。 + +在应用激活时触发事件将会导致被跟踪的安装及会话数量的不准确。 + +如果您希望在安装后触发事件,请使用[归因变化监听器](#attribution_changed_listener)。 + +如果您希望在应用激活后触发事件,请使用被启动的Activity的`onCreate`方法。 + +[dashboard]: http://adjust.com +[adjust.com]: http://adjust.com +[en-readme]: ../../README.md +[zh-readme]: ../chinese/android_sdk_readme_zh.md +[ja-readme]: ../japanese/android_sdk_readme_ja.md +[ko-readme]: ../korean/android_sdk_readme_ko.md + +[maven]: http://maven.org +[example]: https://github.com/adjust/android_sdk/tree/master/Adjust/example +[example-tv]: https://github.com/adjust/android_sdk/tree/master/Adjust/example-tv +[releases]: https://github.com/adjust/adjust_android_sdk/releases +[referrer]: doc/english/referrer.md +[event-tracking]: https://docs.adjust.com/zh/event-tracking +[callbacks-guide]: https://docs.adjust.com/zh/callbacks +[application_name]: http://developer.android.com/guide/topics/manifest/application-element.html#nm +[special-partners]: https://docs.adjust.com/zh/special-partners +[attribution-data]: https://github.com/adjust/sdks/blob/master/doc/attribution-data.md +[android-dashboard]: http://developer.android.com/about/dashboards/index.html +[currency-conversion]: https://docs.adjust.com/zh/event-tracking/#tracking-purchases-in-different-currencies +[android_application]: http://developer.android.com/reference/android/app/Application.html +[android-launch-modes]: https://developer.android.com/guide/topics/manifest/activity-element.html +[activity_resume_pause]: doc/activity_resume_pause.md +[reattribution-with-deeplinks]: https://docs.adjust.com/zh/deeplinking/#manually-appending-attribution-data-to-a-deep-link +[android-purchase-verification]: https://github.com/adjust/android_purchase_sdk + +[activity]: https://raw.github.com/adjust/sdks/master/Resources/android/v4/14_activity.png +[proguard]: https://raw.github.com/adjust/sdks/master/Resources/android/v4/08_proguard_new.png +[receiver]: https://raw.github.com/adjust/sdks/master/Resources/android/v4/09_receiver.png +[gradle_gps]: https://raw.github.com/adjust/sdks/master/Resources/android/v4/05_gradle_gps.png +[log_message]: https://raw.github.com/adjust/sdks/master/Resources/android/v4/15_log_message.png +[manifest_gps]: https://raw.github.com/adjust/sdks/master/Resources/android/v4/06_manifest_gps.png +[gradle_adjust]: https://raw.github.com/adjust/sdks/master/Resources/android/v4/04_gradle_adjust.png +[import_module]: https://raw.github.com/adjust/sdks/master/Resources/android/v4/01_import_module.png +[select_module]: https://raw.github.com/adjust/sdks/master/Resources/android/v4/02_select_module.png +[imported_module]: https://raw.github.com/adjust/sdks/master/Resources/android/v4/03_imported_module.png +[application_class]: https://raw.github.com/adjust/sdks/master/Resources/android/v4/11_application_class.png +[application_config]: https://raw.github.com/adjust/sdks/master/Resources/android/v4/13_application_config.png +[manifest_permissions]: https://raw.github.com/adjust/sdks/master/Resources/android/v4/07_manifest_permissions.png +[manifest_application]: https://raw.github.com/adjust/sdks/master/Resources/android/v4/12_manifest_application.png +[activity_lifecycle_class]: https://raw.github.com/adjust/sdks/master/Resources/android/v4/16_activity_lifecycle_class.png +[activity_lifecycle_methods]: https://raw.github.com/adjust/sdks/master/Resources/android/v4/17_activity_lifecycle_methods.png +[activity_lifecycle_register]: https://raw.github.com/adjust/sdks/master/Resources/android/v4/18_activity_lifecycle_register.png + +[imei_doc]: https://docs.adjust.com/zh/imei-and-meid-attribution-for-android +[gps_adid]: https://github.com/adjust/android_sdk/blob/master/doc/english/gps_adid.md + +## 许可协议 + +The Adjust SDK is licensed under the MIT License. + +Copyright (c) 2012-2018 Adjust GmbH, http://www.adjust.com + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/doc/english/criteo_plugin.md b/doc/english/criteo_plugin.md index 0d8ae512e..6036758c6 100644 --- a/doc/english/criteo_plugin.md +++ b/doc/english/criteo_plugin.md @@ -1,9 +1,10 @@ ## Criteo plugin -Add the dependency of the adjust sdk with the Criteo plugin: +Add the dependency of the Criteo plugin adjust alongside the adjust sdk: ``` -compile 'com.adjust.sdk:adjust-android-criteo:4.15.0' +compile 'com.adjust.sdk:adjust-android:4.16.0' +compile 'com.adjust.sdk:adjust-android-criteo:4.16.0' ``` Or integrate adjust with Criteo events by following these steps: diff --git a/doc/english/imei_plugin.md b/doc/english/imei_plugin.md new file mode 100644 index 000000000..843ff9ae7 --- /dev/null +++ b/doc/english/imei_plugin.md @@ -0,0 +1,975 @@ +## Summary + +This is the Android SDK of Adjust™. You can read more about Adjust™ at [adjust.com]. + +**Important:** This guide is meant for apps that are **NOT being published to the Google Play Store**. If your app will be published to Google Play Store, please follow [this guide](../../README.md) instead. + +## Table of contents + +* [Example apps](#example-apps) +* [Basic integration](#basic-integration) + * [Add the SDK to your project](#sdk-add) + * [Add permissions](#sdk-permissions) + * [Proguard settings](#sdk-proguard) + * [Integrate the SDK into your app](#sdk-integrate) + * [Basic setup](#basic-setup) + * [Session tracking](#session-tracking) + * [API level 14 and higher](#session-tracking-api14) + * [API level between 9 and 13](#session-tracking-api9) + * [Adjust logging](#adjust-logging) + * [IMEI plugin](#imei-plugin) + * [Build your app](#build-the-app) +* [Additional features](#additional-features) + * [Event tracking](#event-tracking) + * [Track revenue](#revenue-tracking) + * [Revenue deduplication](#revenue-deduplication) + * [Callback parameters](#callback-parameters) + * [Partner parameters](#partner-parameters) + * [Callback identifier](#callback-id) + * [Session parameters](#session-parameters) + * [Session callback parameters](#session-callback-parameters) + * [Session partner parameters](#session-partner-parameters) + * [Delay start](#delay-start) + * [Attribution callback](#attribution-callback) + * [Session and event callbacks](#session-event-callbacks) + * [Disable tracking](#disable-tracking) + * [Offline mode](#offline-mode) + * [Event buffering](#event-buffering) + * [GDPR right to be forgotten](#gdpr-forget-me) + * [SDK signature](#sdk-signature) + * [Background tracking](#background-tracking) + * [Device IDs](#device-ids) + * [Amazon advertising identifier](#di-amz-adid) + * [Adjust device identifier](#di-adid) + * [User attribution](#user-attribution) + * [Push token](#push-token) + * [Pre-installed trackers](#pre-installed-trackers) + * [Deep linking](#deeplinking) + * [Standard deep linking scenario](#deeplinking-standard) + * [Deferred deep linking scenario](#deeplinking-deferred) + * [Reattribution via deep links](#deeplinking-reattribution) +* [Troubleshooting](#troubleshooting) + * [I'm seeing the "Session failed (Ignoring too frequent session. ...)" error](#ts-session-failed) + * [Can I trigger an event at application launch?](#ts-event-at-launch) +* [License](#license) + +## Example apps + +There are example apps for Android inside the [`example` directory][example] and Android TV inside the [`example-tv` directory][example-tv]. You can open the Android project to see these examples on how the Adjust SDK can be integrated. + +## Basic integration + +These are the minimal steps required to integrate the Adjust SDK into your Android project. We are going to assume that you use Android Studio for your Android development and target an Android API level 9 (Gingerbread) or later. + +### Add the SDK to your project + +If you are using Maven, add the following to your `build.gradle` file: + +``` +compile 'com.adjust.sdk:adjust-android:4.16.0' +``` + +**Note**: If you are using `Gradle 3.0.0 or above`, make sure to use the `implementation` keyword instead of `compile` as follows: + +``` +implementation 'com.adjust.sdk:adjust-android:4.16.0' +``` + +--- + +You can also add the Adjust SDK to your project as a JAR library. The latest SDK version's JAR library can be found on our [releases page][releases]. + +### Add permissions + +Please add the following permissions, which the Adjust SDK needs, if they are not already present in your `AndroidManifest.xml` file: + +```xml + + + +``` + +### Proguard settings + +If you are using Proguard, add these lines to your Proguard file: + +``` +-keep public class com.adjust.sdk.** { *; } +``` + +### Integrate the SDK into your app + +To start with, we'll set up basic session tracking. + +### Basic setup + +We recommend using a global android [Application][android_application] class to initialize the SDK. If you don't have one in your app already, follow these steps: + +1. Create a class that extends `Application`. + ![][application_class] + +2. Open the `AndroidManifest.xml` file of your app and locate the `` element. +3. Add the attribute `android:name` and set it to the name of your new application class pefixed by a dot. + + In our example app we use an `Application` class named `GlobalApplication`, so the manifest file is configured as: + ```xml + + ... + + ``` + + ![][manifest_application] + +4. In your `Application` class find or create the `onCreate` method and add the following code to initialize the Adjust SDK: + + ```java + import com.adjust.sdk.Adjust; + import com.adjust.sdk.AdjustConfig; + + public class GlobalApplication extends Application { + @Override + public void onCreate() { + super.onCreate(); + + String appToken = "{YourAppToken}"; + String environment = AdjustConfig.ENVIRONMENT_SANDBOX; + AdjustConfig config = new AdjustConfig(this, appToken, environment); + Adjust.onCreate(config); + } + } + ``` + + ![][application_config] + + Replace `{YourAppToken}` with your app token. You can find this in your [dashboard]. + + Depending on whether you are building your app for testing or for production, you must set `environment` with one of these values: + + ```java + String environment = AdjustConfig.ENVIRONMENT_SANDBOX; + String environment = AdjustConfig.ENVIRONMENT_PRODUCTION; + ``` + + **Important:** This value should be set to `AdjustConfig.ENVIRONMENT_SANDBOX` if and only if you or someone else is testing your app. Make sure to set the environment to `AdjustConfig.ENVIRONMENT_PRODUCTION` before you publish the app. Set it back to `AdjustConfig.ENVIRONMENT_SANDBOX` when you start developing and testing it again. + + We use this environment to distinguish between real traffic and test traffic from test devices. It is imperative that you keep this value meaningful at all times, especially if you are tracking revenue. + +### Session tracking + +**Note**: This step is **really important** and please **make sure that you implement it properly in your app**. By implementing it, you will enable proper session tracking by the Adjust SDK in your app. + +### API level 14 and higher + +1. Add a private class that implements the `ActivityLifecycleCallbacks` interface. If you don't have access to this interface, your app is targeting an Android API level inferior to 14. You will have to update manually each Activity by following these [instructions](#session-tracking-api9). If you had `Adjust.onResume` and `Adjust.onPause` calls on each Activity of your app before, you should remove them. + + ![][activity_lifecycle_class] + +2. Edit the `onActivityResumed(Activity activity)` method and add a call to `Adjust.onResume()`. Edit the +`onActivityPaused(Activity activity)` method and add a call to `Adjust.onPause()`. + + ![][activity_lifecycle_methods] + +3. Add on the `onCreate()` method where the Adjust SDK is configured and add call `registerActivityLifecycleCallbacks` with an instance of the created `ActivityLifecycleCallbacks` class. + + ```java + import com.adjust.sdk.Adjust; + import com.adjust.sdk.AdjustConfig; + + public class GlobalApplication extends Application { + @Override + public void onCreate() { + super.onCreate(); + + String appToken = "{YourAppToken}"; + String environment = AdjustConfig.ENVIRONMENT_SANDBOX; + AdjustConfig config = new AdjustConfig(this, appToken, environment); + Adjust.onCreate(config); + + registerActivityLifecycleCallbacks(new AdjustLifecycleCallbacks()); + + //... + } + + private static final class AdjustLifecycleCallbacks implements ActivityLifecycleCallbacks { + @Override + public void onActivityResumed(Activity activity) { + Adjust.onResume(); + } + + @Override + public void onActivityPaused(Activity activity) { + Adjust.onPause(); + } + + //... + } + } + ``` + + ![][activity_lifecycle_register] + +### API level between 9 and 13 + +If your app `minSdkVersion` in gradle is between `9` and `13`, consider updating it to at least `14` to simplify the integration process in the long term. Consult the official Android [dashboard][android-dashboard] to know the latest market share of the major versions. + +To provide proper session tracking it is required to call certain Adjust SDK methods every time any Activity resumes or pauses. Otherwise the SDK might miss a session start or session end. In order to do so you should **follow these steps for each Activity of your app**: + +1. Open the source file of your Activity. +2. Add the `import` statement at the top of the file. +3. In your Activity's `onResume` method call `Adjust.onResume()`. Create the method if needed. +4. In your Activity's `onPause` method call `Adjust.onPause()`. Create the method if needed. + +After these steps your activity should look like this: + +```java +import com.adjust.sdk.Adjust; +// ... +public class YourActivity extends Activity { + protected void onResume() { + super.onResume(); + Adjust.onResume(); + } + protected void onPause() { + super.onPause(); + Adjust.onPause(); + } + // ... +} +``` + +![][activity] + +Repeat these steps for **every** Activity of your app. Don't forget these steps when you create new Activities in the future. Depending on your coding style you might want to implement this in a common superclass of all your Activities. + +### Adjust Logging + +You can increase or decrease the amount of logs that you see during testing by calling `setLogLevel` on your `AdjustConfig` instance with one of the following parameters: + +```java +config.setLogLevel(LogLevel.VERBOSE); // enable all logging +config.setLogLevel(LogLevel.DEBUG); // enable more logging +config.setLogLevel(LogLevel.INFO); // the default +config.setLogLevel(LogLevel.WARN); // disable info logging +config.setLogLevel(LogLevel.ERROR); // disable warnings as well +config.setLogLevel(LogLevel.ASSERT); // disable errors as well +config.setLogLevel(LogLevel.SUPRESS); // disable all log output +``` + +In case you want all your log output to be disabled, beside setting the log level to suppress, you should also use constructor for `AdjustConfig` object which gets boolean parameter indicating whether suppress log level should be supported or not: + +```java +String appToken = "{YourAppToken}"; +String environment = AdjustConfig.ENVIRONMENT_SANDBOX; + +AdjustConfig config = new AdjustConfig(this, appToken, environment, true); +config.setLogLevel(LogLevel.SUPRESS); + +Adjust.onCreate(config); +``` + +### IMEI plugin + +For specific markets, IMEI and MEID can be used for attribution on Android. In order to use this feature, please complete the [required steps][imei-doc] within your Adjust Dashboard and then use this plugin. + +This IMEI plugin respects the [behavior of the Adjust Android SDK][gps-adid] in terms of device ID reading **while additionally** allowing the Adjust SDK to read the IMEI and MEID values of a device. + +If you are using Maven, add the following to your `build.gradle` file: + +``` +compile 'com.adjust.sdk:adjust-android-imei:4.16.0' +``` + +Add the following permission, if it is not already present in your `AndroidManifest.xml` file: + +```xml + +``` + +Remember that after `Android 6.0` it might be necessary to [request app permission](https://developer.android.com/training/permissions/requesting) if the Android OS has not already been altered to avoid it. + +Finally, in order to read IMEI and MEID values, you need to call `AdjustImei.readImei()` before starting the SDK: + +```java +// ... + +AdjustImei.readImei(); +Adjust.onCreate(config); + +// ... +``` + +You can call a similar method `AdjustImei.doNotReadImei()` to stop the SDK from reading IMEI and MEID values. + +However, **please keep in mind** that IMEI and MEID are persistent identifiers and that it is your responsibility to ensure that the collection and processing of this personal data from your app's end-users is lawful. + +### Build your app + +Build and run your Android app. In your `LogCat` viewer you can set the filter `tag:Adjust` to hide all other logs. After your app has launched you should see the following Adjust log: `Install tracked` + +![][log_message] + +## Additional Features + +Once you have integrated the Adjust SDK into your project, you can take advantage of the following features. + +### Event tracking + +You can use adjust to track any event in your app. Suppose you want to track every tap on a button. You would have to create a new event token in your [dashboard]. Let's say that event token is `abc123`. In your button's `onClick` method you could then add the following lines to track the click: + +```java +AdjustEvent event = new AdjustEvent("abc123"); +Adjust.trackEvent(event); +``` + +### Revenue tracking + +If your users can generate revenue by tapping on advertisements or making in-app purchases you can track those revenues with events. Lets say a tap is worth one Euro cent. You could then track the revenue event like this: + +```java +AdjustEvent event = new AdjustEvent("abc123"); +event.setRevenue(0.01, "EUR"); +Adjust.trackEvent(event); +``` + +This can be combined with callback parameters of course. + +When you set a currency token, Adjust will automatically convert the incoming revenues into a reporting revenue of your choice. Read more about [currency conversion here][currency-conversion]. + +You can read more about revenue and event tracking in the [event tracking guide][event-tracking]. + +### Revenue deduplication + +You can also add an optional order ID to avoid tracking duplicate revenues. The last ten order IDs are remembered, and revenue events with duplicate order IDs are skipped. This is especially useful for in-app purchase tracking. You can see an example below. + +If you want to track in-app purchases, please make sure to call `trackEvent` only if the purchase is finished and item is purchased. That way you can avoid tracking revenue that is not actually being generated. + +```java +AdjustEvent event = new AdjustEvent("abc123"); + +event.setRevenue(0.01, "EUR"); +event.setOrderId("{OrderId}"); + +Adjust.trackEvent(event); +``` + +### Callback parameters + +You can register a callback URL for your events in your [dashboard]. We will send a GET request to that URL whenever the event is tracked. You can add callback parameters to that event by calling `addCallbackParameter` to the event instance before tracking it. We will then append these parameters to your callback URL. + +For example, suppose you have registered the URL `http://www.adjust.com/callback` then track an event like this: + +```java +AdjustEvent event = new AdjustEvent("abc123"); + +event.addCallbackParameter("key", "value"); +event.addCallbackParameter("foo", "bar"); + +Adjust.trackEvent(event); +``` + +In that case we would track the event and send a request to: + +``` +http://www.adjust.com/callback?key=value&foo=bar +``` + +Please note that we don't store any of your custom parameters, but only append them to your callbacks. If you haven't registered a callback for an event, these parameters won't even be read. + +You can read more about using URL callbacks, including a full list of available values, in our [callbacks guide][callbacks-guide]. + +### Partner parameters + +You can also add parameters to be transmitted to network partners, which have been activated in your Adjust dashboard. + +This works similarly to the callback parameters mentioned above, but can be added by calling the `addPartnerParameter` method on your `AdjustEvent` instance. + +```java +AdjustEvent event = new AdjustEvent("abc123"); + +event.addPartnerParameter("key", "value"); +event.addPartnerParameter("foo", "bar"); + +Adjust.trackEvent(event); +``` + +You can read more about special partners and these integrations in our [guide to special partners][special-partners]. + +### Callback identifier + +You can also add custom string identifier to each event you want to track. This identifier will later be reported in event success and/or event failure callbacks to enable you to keep track on which event was successfully tracked or not. You can set this identifier by calling the `setCallbackId` method on your `AdjustEvent` instance: + +```java +AdjustEvent event = new AdjustEvent("abc123"); + +event.setCallbackId("Your-Custom-Id"); + +Adjust.trackEvent(event); +``` + +### Set up session parameters + +Some parameters are saved to be sent in every **event** and **session** of the Adjust SDK. Once you have added any of these parameters, you don't need to add them every time, since they will be saved locally. If you add the same parameter twice, there will be no effect. + +These session parameters can be called before the Adjust SDK is launched to make sure they are sent even on install. If you need to send them with an install, but can only obtain the needed values after launch, it's possible to [delay](#delay-start) the first launch of the Adjust SDK to allow this behaviour. + +### Session callback parameters + +The same callback parameters that are registered for [events](#callback-parameters) can be also saved to be sent in every event or session of the Adjust SDK. + +The session callback parameters have a similar interface to the event callback parameters. Instead of adding the key and it's value to an event, it's added through a call to `Adjust.addSessionCallbackParameter(String key, String value)`: + +```java +Adjust.addSessionCallbackParameter("foo", "bar"); +``` + +The session callback parameters will be merged with the callback parameters added to an event. The callback parameters added to an event have precedence over the session callback parameters. Meaning that, when adding a callback parameter to an event with the same key to one added from the session, the value that prevails is the callback parameter added to the event. + +It's possible to remove a specific session callback parameter by passing the desiring key to the method `Adjust.removeSessionCallbackParameter(String key)`. + +```java +Adjust.removeSessionCallbackParameter("foo"); +``` + +If you wish to remove all keys and their corresponding values from the session callback parameters, you can reset it with the method `Adjust.resetSessionCallbackParameters()`. + +```java +Adjust.resetSessionCallbackParameters(); +``` + +### Session partner parameters + +In the same way that there are [session callback parameters](#session-callback-parameters) sent in every event or session of the Adjust SDK, there is also session partner parameters. + +These will be transmitted to network partners, for the integrations that have been activated in your Adjust [dashboard]. + +The session partner parameters have a similar interface to the event partner parameters. Instead of adding the key and it's value to an event, it's added through a call to `Adjust.addSessionPartnerParameter(String key, String value)`: + +```java +Adjust.addSessionPartnerParameter("foo", "bar"); +``` + +The session partner parameters will be merged with the partner parameters added to an event. The partner parameters added to an event have precedence over the session partner parameters. Meaning that, when adding a partner parameter to an event with the same key to one added from the session, the value that prevails is the partner parameter added to the event. + +It's possible to remove a specific session partner parameter by passing the desiring key to the method `Adjust.removeSessionPartnerParameter(String key)`. + +```java +Adjust.removeSessionPartnerParameter("foo"); +``` + +If you wish to remove all keys and their corresponding values from the session partner parameters, you can reset it with the method `Adjust.resetSessionPartnerParameters()`. + +```java +Adjust.resetSessionPartnerParameters(); +``` + +### Delay start + +Delaying the start of the Adjust SDK allows your app some time to obtain session parameters, such as unique identifiers, to be sent on install. + +Set the initial delay time in seconds with the method `setDelayStart` in the `AdjustConfig` instance: + +```java +adjustConfig.setDelayStart(5.5); +``` + +In this case, this will make the Adjust SDK not send the initial install session and any event created for 5.5 seconds. After this time is expired or if you call `Adjust.sendFirstPackages()` in the meanwhile, every session parameter will be added to the delayed install session and events and the Adjust SDK will resume as usual. + +**The maximum delay start time of the adjust SDK is 10 seconds**. + +### Attribution callback + +You can register a listener to be notified of tracker attribution changes. Due to the different sources considered for attribution, this information can not be provided synchronously. The simplest way is to create a single anonymous listener: + +Please make sure to consider our [applicable attribution data policies][attribution-data]. + +With the `AdjustConfig` instance, before starting the SDK, add the anonymous listener: + +```java +AdjustConfig config = new AdjustConfig(this, appToken, environment); + +config.setOnAttributionChangedListener(new OnAttributionChangedListener() { + @Override + public void onAttributionChanged(AdjustAttribution attribution) { + } +}); + +Adjust.onCreate(config); +``` + +Alternatively, you could implement the `OnAttributionChangedListener` interface in your `Application` class and set it as listener: + +```java +AdjustConfig config = new AdjustConfig(this, appToken, environment); +config.setOnAttributionChangedListener(this); +Adjust.onCreate(config); +``` + +The listener function will be called after the SDK receives the final attribution data. Within the listener function you have access to the `attribution` parameter. Here is a quick summary of its properties: + +- `String trackerToken` the tracker token of the current attribution. +- `String trackerName` the tracker name of the current attribution. +- `String network` the network grouping level of the current attribution. +- `String campaign` the campaign grouping level of the current attribution. +- `String adgroup` the ad group grouping level of the current attribution. +- `String creative` the creative grouping level of the current attribution. +- `String clickLabel` the click label of the current attribution. +- `String adid` the Adjust device identifier. + +If any value is unavailable, it will default to `null`. + +### Session and event callbacks + +You can register a listener to be notified when events or sessions are tracked. There are four listeners: one for tracking successful events, one for tracking failed events, one for tracking successful sessions and one for tracking failed sessions. You can add any number of listeners after creating the `AdjustConfig` object: + +```java +AdjustConfig config = new AdjustConfig(this, appToken, environment); + +// Set event success tracking delegate. +config.setOnEventTrackingSucceededListener(new OnEventTrackingSucceededListener() { + @Override + public void onFinishedEventTrackingSucceeded(AdjustEventSuccess eventSuccessResponseData) { + // ... + } +}); + +// Set event failure tracking delegate. +config.setOnEventTrackingFailedListener(new OnEventTrackingFailedListener() { + @Override + public void onFinishedEventTrackingFailed(AdjustEventFailure eventFailureResponseData) { + // ... + } +}); + +// Set session success tracking delegate. +config.setOnSessionTrackingSucceededListener(new OnSessionTrackingSucceededListener() { + @Override + public void onFinishedSessionTrackingSucceeded(AdjustSessionSuccess sessionSuccessResponseData) { + // ... + } +}); + +// Set session failure tracking delegate. +config.setOnSessionTrackingFailedListener(new OnSessionTrackingFailedListener() { + @Override + public void onFinishedSessionTrackingFailed(AdjustSessionFailure sessionFailureResponseData) { + // ... + } +}); + +Adjust.onCreate(config); +``` + +The listener function will be called after the SDK tries to send a package to the server. Within the listener function you have access to a response data object specifically for the listener. Here is a quick summary of the success session response data object fields: + +- `String message` the message from the server or the error logged by the SDK. +- `String timestamp` timestamp from the server. +- `String adid` a unique device identifier provided by Adjust. +- `JSONObject jsonResponse` the JSON object with the reponse from the server. + +Both event response data objects contain: + +- `String eventToken` the event token, if the package tracked was an event. +- `String callbackId` the custom defined callback ID set on event object. + +If any value is unavailable, it will default to `null`. + +And both event and session failed objects also contain: + +- `boolean willRetry` indicates that will be an attempt to resend the package at a later time. + +### Disable tracking + +You can disable the Adjust SDK from tracking any activities of the current device by calling `setEnabled` with parameter `false`. **This setting is remembered between sessions**. + +```java +Adjust.setEnabled(false); +``` + +You can check if the Adjust SDK is currently enabled by calling the function `isEnabled`. It is always possible to activatе the Adjust SDK by invoking `setEnabled` with the enabled parameter as `true`. + +### Offline mode + +You can put the Adjust SDK in offline mode to suspend transmission to our servers, while retaining tracked data to be sent later. While in offline mode, all information is saved in a file, so be careful not to trigger too many events while in offline mode. + +You can activate offline mode by calling `setOfflineMode` with the parameter `true`. + +```java +Adjust.setOfflineMode(true); +``` + +Conversely, you can deactivate offline mode by calling `setOfflineMode` with `false`. When the Adjust SDK is put back in online mode, all saved information is sent to our servers with the correct time information. + +Unlike disabling tracking, this setting is **not remembered** between sessions. This means that the SDK is in online mode whenever it is started, even if the app was terminated in offline mode. + +### Event buffering + +If your app makes heavy use of event tracking, you might want to delay some HTTP requests in order to send them in one batch every minute. You can enable event buffering with your `AdjustConfig` instance: + +```java +AdjustConfig config = new AdjustConfig(this, appToken, environment); + +config.setEventBufferingEnabled(true); + +Adjust.onCreate(config); +``` + +### GDPR right to be forgotten + +In accordance with article 17 of the EU's General Data Protection Regulation (GDPR), you can notify Adjust when a user has exercised their right to be forgotten. Calling the following method will instruct the Adjust SDK to communicate the user's choice to be forgotten to the Adjust backend: + +```java +Adjust.gdprForgetMe(context); +``` + +Upon receiving this information, Adjust will erase the user's data and the Adjust SDK will stop tracking the user. No requests from this device will be sent to Adjust in the future. + +### SDK signature + +An account manager must activate the Adjust SDK signature. Contact Adjust support (support@adjust.com) if you are interested in using this feature. + +If the SDK signature has already been enabled on your account and you have access to App Secrets in your Adjust Dashboard, please use the method below to integrate the SDK signature into your app. + +An App Secret is set by calling `setAppSecret` on your `AdjustConfig` instance: + +```java +AdjustConfig config = new AdjustConfig(this, appToken, environment); + +config.setAppSecret(secretId, info1, info2, info3, info4); + +Adjust.onCreate(config); +``` + +### Background tracking + +The default behaviour of the Adjust SDK is to pause sending HTTP requests while the app is in the background. You can change this in your `AdjustConfig` instance: + +```java +AdjustConfig config = new AdjustConfig(this, appToken, environment); + +config.setSendInBackground(true); + +Adjust.onCreate(config); +``` + +### Device IDs + +The Adjust SDK offers you possibility to obtain some of the device identifiers. + +### Amazon advertising identifier + +If you need to obtain the Amazon Advertising ID, you can make a call to following method on `Adjust` instance: + +```java +String amazonAdId = Adjust.getAmazonAdId(context); +``` + +### Adjust device identifier + +For each device with your app installed on it, Adjust backend generates unique **Adjust device identifier** (**adid**). In order to obtain this identifier, you can make a call to following method on `Adjust` instance: + +```java +String adid = Adjust.getAdid(); +``` + +**Note**: You can only make this call in the Adjust SDK v4.11.0 and above. + +**Note**: Information about **adid** is available after app installation has been tracked by the Adjust backend. From that moment on, Adjust SDK has information about your device **adid** and you can access it with this method. So, **it is not possible** to access **adid** value before the SDK has been initialised and installation of your app was tracked successfully. + +### User attribution + +Like described in [attribution callback section](#attribution-callback), this callback get triggered providing you info about new attribution when ever it changes. In case you want to access info about your user's current attribution when ever you need it, you can make a call to following method of the `Adjust` instance: + +```java +AdjustAttribution attribution = Adjust.getAttribution(); +``` + +**Note**: You can only make this call in the Adjust SDK v4.11.0 and above. + +**Note**: Information about current attribution is available after app installation has been tracked by the Adjust backend and attribution callback has been initially triggered. From that moment on, Adjust SDK has information about your user's attribution and you can access it with this method. So, **it is not possible** to access user's attribution value before the SDK has been initialized and attribution callback has been initially triggered. + +### Push token + +Push tokens are used for Audience Builder and client callbacks, and they are required for uninstall and reinstall tracking. + +To send us the push notification token, add the following call to Adjust once you have obtained your token or when ever it's value is changed: + +```java +Adjust.setPushToken(pushNotificationsToken, context); +``` + +This updated signature with `context` added allows the SDK to cover more scenarios to make sure that the push token is sent, and it is advised that you use the signature method above. + +We still support the previous signature of the same method: + +```java +Adjust.setPushToken(pushNotificationsToken); +``` + +### Pre-installed trackers + +If you want to use the Adjust SDK to recognize users whose devices came with your app pre-installed, follow these steps. + +1. Create a new tracker in your [dashboard]. +2. Open your app delegate and add set the default tracker of your `AdjustConfig`: + + ```java + AdjustConfig config = new AdjustConfig(this, appToken, environment); + config.setDefaultTracker("{TrackerToken}"); + Adjust.onCreate(config); + ``` + + Replace `{TrackerToken}` with the tracker token you created in step 1. Please note that the Dashboard displays a tracker URL (including `http://app.adjust.com/`). In your source code, you should specify only the six-character token and not the + entire URL. + +3. Build and run your app. You should see a line like the following in your LogCat: + + ``` + Default tracker: 'abc123' + ``` + +### Deep linking + +If you are using an Adjust tracker URL with the option to deep link into your app, there is the possibility to get information about the deep link URL and its content. Hitting the URL can happen when the user has your app already installed (standard deep linking scenario) or if they don't have the app on their device (deferred deep linking scenario). In the standard deep linking scenario, the Android platform natively offers the possibility for you to get the information about the deep link content. The deferred deep linking scenario is something which the Android platform doesn't support out of the box, and, in this case, the Adjust SDK will offer you the mechanism you need to get the information about the deep link content. + +### Standard deep linking scenario + +If a user has your app installed and you want it to launch after hitting an Adjust tracker URL with the `deep_link` parameter in it, you need to enable deep linking in your app. This is done by choosing a desired **unique scheme name** and assigning it to the Activity you want to launch once your app opens following a user clicking on the tracker URL. This is set in the `AndroidManifest.xml`. You need to add the `intent-filter` section to your desired Activity definition in the manifest file and assign an `android:scheme` property value with the desired scheme name: + +```xml + + + + + + + + + + + + + + +``` + +With this now set, you need to use the assigned scheme name in the Adjust tracker URL's `deep_link` parameter if you want your app to launch once the tracker URL is clicked. A tracker URL without any information added to the deep link can be built to look something like this: + +``` +https://app.adjust.com/abc123?deep_link=adjustExample%3A%2F%2F +``` + +Please, have in mind that the `deep_link` parameter value in the URL **must be URL encoded**. + +After clicking this tracker URL, and with the app set as described above, your app will launch along with the `MainActivity` intent. Inside the `MainActivity` class, you will automatically be provided with the information about the `deep_link` parameter content. Once this content is delivered to you, it **will not be encoded**, although it was encoded in the URL. + +Depending on the `android:launchMode` setting of your Activity in the `AndroidManifest.xml` file, information about the `deep_link` parameter content will be delivered to the appropriate place in the Activity file. For more information about the possible values of the `android:launchMode` property, check [the official Android documentation][android-launch-modes]. + +There are two places within your desired Activity where information about the deep link content will be delivered via the `Intent` object--either in the Activity's `onCreate` or `onNewIntent` methods. Once your app has launched and one of these methods has been triggered, you will be able to get the actual deep link passed in the `deep_link` parameter in the click URL. You can then use this information to conduct some additional logic in your app. + +You can extract the deep link content from these two methods like this: + +```java +@Override +protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_main); + + Intent intent = getIntent(); + Uri data = intent.getData(); + + // data.toString() -> This is your deep_link parameter value. +} +``` + +```java +@Override +protected void onNewIntent(Intent intent) { + super.onNewIntent(intent); + + Uri data = intent.getData(); + + // data.toString() -> This is your deep_link parameter value. +} +``` + +### Deferred deep linking scenario + +The deferred deep linking scenario occurs when a user clicks on an Adjust tracker URL with a `deep_link` parameter in it, but does not have the app installed on the device at click time. After that, the user will be redirected to the Play Store to download and install your app. After opening it for the first time, the `deep_link` parameter content will be delivered to your app. + +In order to get information about the `deep_link` parameter content in a deferred deep linking scenario, you should set a listener method on the `AdjustConfig` object. This will be triggered once the Adjust SDK gets the information about the deep link content from the Adjust backend. + +```java +AdjustConfig config = new AdjustConfig(this, appToken, environment); + +// Evaluate the deeplink to be launched. +config.setOnDeeplinkResponseListener(new OnDeeplinkResponseListener() { + @Override + public boolean launchReceivedDeeplink(Uri deeplink) { + // ... + if (shouldAdjustSdkLaunchTheDeeplink(deeplink)) { + return true; + } else { + return false; + } + } +}); + +Adjust.onCreate(config); +``` + +Once the Adjust SDK receives the information about the deep link content from the Adjust backend, it will deliver you the information about its content in this listener and expect the `boolean` return value from you. This return value represents your decision on whether the Adjust SDK should launch the Activity to which you have assigned the scheme name from the deep link (like in the standard deep linking scenario) or not. + +If you return `true`, we will launch it and the exact same scenario which is described in the [Standard deep linking scenario chapter](#deeplinking-standard) will happen. If you do not want the SDK to launch the Activity, you can return `false` from this listener, and, based on the deep link content, decide on your own what to do next in your app. + +### Reattribution via deep links + +Adjust enables you to run re-engagement campaigns through deep links. For more information on how to do that, please check our [official docs][reattribution-with-deeplinks]. + +If you are using this feature, in order for your user to be properly reattributed, you need to make one additional call to the Adjust SDK in your app. + +Once you have received deep link content information in your app, add a call to the `Adjust.appWillOpenUrl(Uri, Context)` method. By making this call, the Adjust SDK will try to find if there is any new attribution information inside of the deep link. If there is any, it will be sent to the Adjust backend. If your user should be reattributed due to a click on the adjust tracker URL with deep link content, you will see the [attribution callback](#attribution-callback) in your app being triggered with new attribution info for this user. + +The call to `Adjust.appWillOpenUrl(Uri, Context)` should be done like this: + +```java +@Override +protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_main); + + Intent intent = getIntent(); + Uri data = intent.getData(); + + Adjust.appWillOpenUrl(data, getApplicationContext()); +} +``` + +```java +@Override +protected void onNewIntent(Intent intent) { + super.onNewIntent(intent); + + Uri data = intent.getData(); + + Adjust.appWillOpenUrl(data, getApplicationContext()); +} +``` + +**Note**: `Adjust.appWillOpenUrl(Uri)` method is marked as **deprecated** as of Android SDK v4.14.0. Please, use `Adjust.appWillOpenUrl(Uri, Context)` method instead. + +## Troubleshooting + +### I'm seeing the "Session failed (Ignoring too frequent session. ...)" error. + +This error typically occurs when testing installs. Uninstalling and reinstalling the app is not enough to trigger a new install. The servers will determine that the SDK has lost its locally aggregated session data and ignore the erroneous message, given the information available on the servers about the device. + +This behaviour can be cumbersome during tests, but is necessary in order to have the sandbox behaviour match production as much as possible. + +You can reset the session data of the device in our servers. Check the error message in the logs: + +``` +Session failed (Ignoring too frequent session. Last session: YYYY-MM-DDTHH:mm:ss, this session: YYYY-MM-DDTHH:mm:ss, interval: XXs, min interval: 20m) (app_token: {yourAppToken}, adid: {adidValue}) +``` + +With the `{yourAppToken}` and `{adidValue}`/`{gps_adidValue}`/`{androidIDValue}` values filled in below, open one of the +following links: + + +``` +http://app.adjust.com/forget_device?app_token={yourAppToken}&adid={adidValue} +``` + +``` +http://app.adjust.com/forget_device?app_token={yourAppToken}&gps_adid={gps_adidValue} +``` + +``` +http://app.adjust.com/forget_device?app_token={yourAppToken}&android_id={androidIDValue} +``` + +When the device is forgotten, the link just returns `Forgot device`. If the device was already forgotten or the values were incorrect, the link returns `Device not found`. + +### Can I trigger an event at application launch? + +Not how you might intuitively think. The `onCreate` method on the global `Application` class is called not only at application launch, but also when a system or application event is captured by the app. + +Our SDK is prepared for initialization at this time, but not actually started. This will only happen when an activity is started, i.e., when a user actually launches the app. + +That's why triggering an event at this time will not do what you would expect. Such calls will start the Adjust SDK and send the events, even when the app was not launched by the user - at a time that depends on external factors of the app. + +Triggering events at application launch will thus result in inaccuracies in the number of installs and sessions tracked. + +If you want to trigger an event after the install, use the [attribution callback](#attribution-callback). + +If you want to trigger an event when the app is launched, use the `onCreate` method of the Activity which is started. + +[dashboard]: http://adjust.com +[adjust.com]: http://adjust.com + +[maven]: http://maven.org +[example]: https://github.com/adjust/android_sdk/tree/master/Adjust/example +[example-tv]: https://github.com/adjust/android_sdk/tree/master/Adjust/example-tv +[releases]: https://github.com/adjust/adjust_android_sdk/releases +[referrer]: doc/english/referrer.md +[imei-doc]: https://docs.adjust.com/en/imei-and-meid-attribution-for-android +[gps-adid]: https://github.com/adjust/android_sdk/blob/master/doc/english/gps_adid.md +[event-tracking]: https://docs.adjust.com/en/event-tracking +[callbacks-guide]: https://docs.adjust.com/en/callbacks +[application_name]: http://developer.android.com/guide/topics/manifest/application-element.html#nm +[special-partners]: https://docs.adjust.com/en/special-partners +[attribution-data]: https://github.com/adjust/sdks/blob/master/doc/attribution-data.md +[android-dashboard]: http://developer.android.com/about/dashboards/index.html +[currency-conversion]: https://docs.adjust.com/en/event-tracking/#tracking-purchases-in-different-currencies +[android_application]: http://developer.android.com/reference/android/app/Application.html +[android-launch-modes]: https://developer.android.com/guide/topics/manifest/activity-element.html +[activity_resume_pause]: doc/activity_resume_pause.md +[reattribution-with-deeplinks]: https://docs.adjust.com/en/deeplinking/#manually-appending-attribution-data-to-a-deep-link +[android-purchase-verification]: https://github.com/adjust/android_purchase_sdk + +[activity]: https://raw.github.com/adjust/sdks/master/Resources/android/v4/14_activity.png +[proguard]: https://raw.github.com/adjust/sdks/master/Resources/android/v4/08_proguard_new.png +[receiver]: https://raw.github.com/adjust/sdks/master/Resources/android/v4/09_receiver.png +[gradle_gps]: https://raw.github.com/adjust/sdks/master/Resources/android/v4/05_gradle_gps.png +[log_message]: https://raw.github.com/adjust/sdks/master/Resources/android/v4/15_log_message.png +[manifest_gps]: https://raw.github.com/adjust/sdks/master/Resources/android/v4/06_manifest_gps.png +[gradle_adjust]: https://raw.github.com/adjust/sdks/master/Resources/android/v4/04_gradle_adjust.png +[import_module]: https://raw.github.com/adjust/sdks/master/Resources/android/v4/01_import_module.png +[select_module]: https://raw.github.com/adjust/sdks/master/Resources/android/v4/02_select_module.png +[imported_module]: https://raw.github.com/adjust/sdks/master/Resources/android/v4/03_imported_module.png +[application_class]: https://raw.github.com/adjust/sdks/master/Resources/android/v4/11_application_class.png +[application_config]: https://raw.github.com/adjust/sdks/master/Resources/android/v4/13_application_config.png +[manifest_permissions]: https://raw.github.com/adjust/sdks/master/Resources/android/v4/07_manifest_permissions.png +[manifest_application]: https://raw.github.com/adjust/sdks/master/Resources/android/v4/12_manifest_application.png +[activity_lifecycle_class]: https://raw.github.com/adjust/sdks/master/Resources/android/v4/16_activity_lifecycle_class.png +[activity_lifecycle_methods]: https://raw.github.com/adjust/sdks/master/Resources/android/v4/17_activity_lifecycle_methods.png +[activity_lifecycle_register]: https://raw.github.com/adjust/sdks/master/Resources/android/v4/18_activity_lifecycle_register.png + +## License + +The Adjust SDK is licensed under the MIT License. + +Copyright (c) 2012-2018 Adjust GmbH, http://www.adjust.com + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/doc/english/migrate.md b/doc/english/migrate.md index ec5c948bd..791c116f8 100644 --- a/doc/english/migrate.md +++ b/doc/english/migrate.md @@ -1,4 +1,4 @@ -## Migrate your adjust SDK for Android to 4.15.1 from 3.6.2 +## Migrate your adjust SDK for Android to 4.16.0 from 3.6.2 ### The Application class diff --git a/doc/english/sociomantic_plugin.md b/doc/english/sociomantic_plugin.md index e5eb120ae..a3299d0e7 100644 --- a/doc/english/sociomantic_plugin.md +++ b/doc/english/sociomantic_plugin.md @@ -1,9 +1,10 @@ ## Sociomantic plugin -Add the dependency of the adjust sdk with the Sociomantic plugin: +Add the dependency of the Sociomantic plugin adjust alongside the adjust sdk: ``` -compile 'com.adjust.sdk:adjust-android-sociomantic:4.15.0' +compile 'com.adjust.sdk:adjust-android:4.16.0' +compile 'com.adjust.sdk:adjust-android-sociomantic:4.16.0' ``` Or integrate adjust with Sociomantic events by following these steps: diff --git a/doc/english/trademob_plugin.md b/doc/english/trademob_plugin.md index b2773c5a2..2aae9ec3f 100644 --- a/doc/english/trademob_plugin.md +++ b/doc/english/trademob_plugin.md @@ -1,9 +1,10 @@ ## Trademob plugin -Add the dependency of the adjust sdk with the Trademob plugin: +Add the dependency of the Trademob plugin adjust alongside the adjust sdk: ``` -compile 'com.adjust.sdk:adjust-android-trademob:4.15.0' +compile 'com.adjust.sdk:adjust-android:4.16.0' +compile 'com.adjust.sdk:adjust-android-trademob:4.16.0' ``` Or integrate adjust with Trademob events by following these steps: diff --git a/doc/english/web_views.md b/doc/english/web_views.md index cc5e8435b..fd47928f8 100644 --- a/doc/english/web_views.md +++ b/doc/english/web_views.md @@ -66,14 +66,14 @@ These are the minimal steps required to integrate the Adjust SDK into your Andro If you are using Maven, add the following to your `build.gradle` file: ``` -compile 'com.adjust.sdk:adjust-android:4.15.1' +compile 'com.adjust.sdk:adjust-android:4.16.0' compile 'com.android.installreferrer:installreferrer:1.0' ``` **Note**: If you are using `Gradle 3.0.0 or above`, make sure to use the `implementation` keyword instead of `compile` as follows: ``` -implementation 'com.adjust.sdk:adjust-android:4.15.1' +implementation 'com.adjust.sdk:adjust-android:4.16.0' implementation 'com.android.installreferrer:installreferrer:1.0' ``` @@ -88,13 +88,13 @@ You can also add the Adjust SDK to your project as a JAR library. The latest SDK If you are using Maven, add the following to your `build.gradle` file: ``` -compile 'com.adjust.sdk:adjust-android-webbridge:4.15.0' +compile 'com.adjust.sdk:adjust-android-webbridge:4.16.0' ``` **Note**: If you are using `Gradle 3.0.0 or above`, make sure to use the `implementation` keyword instead of `compile` as follows: ``` -implementation 'com.adjust.sdk:adjust-android-webbridge:4.15.0' +implementation 'com.adjust.sdk:adjust-android-webbridge:4.16.0' ``` --- diff --git a/doc/japanese/README.md b/doc/japanese/README.md new file mode 100644 index 000000000..b6e4717b5 --- /dev/null +++ b/doc/japanese/README.md @@ -0,0 +1,977 @@ +こちらは、adjust™のAndroid用SDKです。adjust™についての詳細は[adjust.com]をご覧ください。 + +Web Viewをアプリ内でご使用の場合、Javascriptコードからadjustのトラッキングをご利用いただくには、 +[Android Web View SDKガイド](https://github.com/adjust/android_sdk/blob/master/doc/japanese/web_views_ja.md)をご確認ください。 + +
+
+ +Read this in other languages: [English][en-readme], [中文][zh-readme], [日本語][ja-readme], [한국어][ko-readme]. + +### サンプルアプリ + +サンプルアプリがexampleディレクトリ([`example-app-java` directory][example-java] )に、Android TVのサンプルが [`example-tv` directory][example-tv]にご用意しています。 Androidプロジェクトを開き、SDK実装の際は、このサンプルをご参照ください。 + +### 基本的な連携方法 + +Androidプロジェクトにadjust SDKを連携させるための手順を説明します。 +Android の開発に Android Studio が使用されていること、Android API レベル9(Gingerbread)以降が使用されていることを仮定します。 + +#### プロジェクトへのSDKの追加 + +Mavenをご利用の場合、アプリの`build.gradle`ファイルを開き、代わりに書きの行を加えてください。 + +``` +implementation 'com.adjust.sdk:adjust-android:4.16.0' +implementation 'com.android.installreferrer:installreferrer:1.0' +``` + +#### Google Playサービスの追加 + +2014年8月1日以降、Google Playストア内のアプリはデバイスの特定のために[Google広告ID][google_ad_id]を使うことが必須とされています。 +adjust SDKでGoogle広告IDを使うためには、[Google Playサービス][google_play_services]を連携させる必要があります。 +Google Playサービスの連携がお済みでない場合は、以下の手順に進んでください。 + +- `build.gradle`ファイルを開き、`dependencies`ブロックを探してください。そこに、以下の行を追加してください。 + + ``` + implementation 'com.google.android.gms:play-services-analytics:16.0.4' + ``` + +- **Google Playサービスのバージョン7以降を使っている場合は、このステップは飛ばしてください。** +パッケージ・エクスプローラからAndroidプロジェクトの`AndroidManifest.xml`を開いてください。 +以下の`meta-data`タグを``エレメントの中に追加してください。 + + ```xml + + ``` + +#### パーミッションの追加 + +パッケージ・エクスプローラからAndroidプロジェクトの`AndroidManifest.xml`を開いてください。 +`INTERNET`の`uses-permission`タグがそこになければ、これを追加してください。 + +```xml + + +``` + +**Google Playストア向けでない**アプリの場合は、両方のパーミッションを追加してください。 + +```xml + +``` + +#### Proguard設定 + +Proguardをお使いの場合は、下記の記述をProguardファイルに追加してください。 + +``` +-keep public class com.adjust.sdk.** { *; } +-keep class com.google.android.gms.common.ConnectionResult { + int SUCCESS; +} +-keep class com.google.android.gms.ads.identifier.AdvertisingIdClient { + com.google.android.gms.ads.identifier.AdvertisingIdClient$Info getAdvertisingIdInfo(android.content.Context); +} +-keep class com.google.android.gms.ads.identifier.AdvertisingIdClient$Info { + java.lang.String getId(); + boolean isLimitAdTrackingEnabled(); +} +-keep public class com.android.installreferrer.** { *; } +``` + +**Google Playストア向けでない**アプリの場合は、`com.google.android.gms`の記述を省略できます。 + + +#### Adjust broadcastレシーバ + +`INSTALL_REFERRER`インテントの受信に**Broadcastレシーバを使わない**場合、`AndroidManifest.xml`の`application`タグの中に以下の`receiver`タグを追加してください。 + +```xml + + + + + +``` + +adjustはコンバージョンをより正確にトラッキングできるよう、インストールリファラを受信するためにこのBroadcastレシーバを使用します。 + +`INSTALL_REFERRER`インテントに別のBroadcastレシーバを既にお使いの場合、 +[こちらの手順][multibroadcast]に従ってadjustのBroadcastレシーバを追加してください。 + +#### アプリへのSDKの連携 + +はじめに、基本的なセッションのトラッキングの設定を行います。 + +#### 基本設定 + +SDKの初期化にグローバルAndroid[Application][android_application]クラスのご使用をおすすめします。 +まだこのクラスを実装していなければ、次の手順で実装してください。 + +- `Application`を拡張するクラスを作成してください。 +- アプリの`AndroidManifest.xml`ファイルを開き、``エレメントを置いてください。 +- `android:name`アトリビュートを追加し、先頭にドットをつけて新しいアプリケーションクラスの名前に設定してください。 + + サンプルアプリでは`GlobalApplication`と名付けた`Application`クラスを使用していますので、マニフェストファイルは以下のように設定されます。 + + ```xml + + + ``` + +- `Application`クラスに`onCreate`メソッドがあればそこに、なければこれを作成し、adjust SDK初期化の以下のコードを追加してください。 + + ```java + import com.adjust.sdk.Adjust; + import com.adjust.sdk.AdjustConfig; + + public class GlobalApplication extends Application { + @Override + public void onCreate() { + super.onCreate(); + + String appToken = "{YourAppToken}"; + String environment = AdjustConfig.ENVIRONMENT_SANDBOX; + AdjustConfig config = new AdjustConfig(this, appToken, environment); + Adjust.onCreate(config); + } + } + ``` + +`{YourAppToken}`にアプリトークンを記入してください。トークンは[dashboard]でご確認いただけます。 + +`environment`に以下のどちらかを設定してください。これはテスト用アプリか本番用アプリかによって異なります。 + + +```java +String environment = AdjustConfig.ENVIRONMENT_SANDBOX; +String environment = AdjustConfig.ENVIRONMENT_PRODUCTION; +``` + +**重要** この値はアプリのテスト中のみ`AdjustConfig.ENVIRONMENT_SANDBOX`に設定してください。 +アプリを提出する前に`AdjustConfig.ENVIRONMENT_PRODUCTION`になっていることを必ず確認してください。 +再度開発やテストをする際は`AdjustConfig.ENVIRONMENT_SANDBOX`に戻してください。 + +この変数は実際のトラフィックとテスト端末からのテストのトラフィックを区別するために利用されます。 +正しく計測するために、この値の設定には常に注意してください。収益のトラッキングの際には特に重要です。 + +#### セッショントラッキング + +**重要** この作業は**非常に重要**ですので、必ず**アプリ内で正しく実装されている**ことをご確認ください。 +この実装により、adjust SDKにより的確なセッションのトラッキングが有効になります。 + +##### レベル14以降のAPI + +- `ActivityLifecycleCallbacks`インターフェイスを実装したプライベートクラスを追加してください。 +このインターフェイスへのアクセスができなければ、そのアプリのAndroid APIレベルは14未満です。 +アクティビティをそれぞれ手動でアップデートする必要がありますので、こちらの[ガイド](#session-tracking-api9)をご参照ください。 +以前にそれぞれのアクティビティで`Adjust.onResume`と`Adjust.onPause`コールを使っていた場合は、これらを削除してください。 + +- `onActivityResumed(Activity activity)`メソッドを編集し、`Adjust.onResume()`のコールを追加してください。 +`onActivityPaused(Activity activity)`メソッドを編集し、`Adjust.onPause()`のコールを追加してください。 + +- adjust SDKが設定されている部分に`onCreate()`メソッドを追加し、`registerActivityLifecycleCallbacks`のコールと +作成した`ActivityLifecycleCallbacks`クラスのインスタンスを追加してください。 + + ```java + import com.adjust.sdk.Adjust; + import com.adjust.sdk.AdjustConfig; + + public class GlobalApplication extends Application { + @Override + public void onCreate() { + super.onCreate(); + + String appToken = "{YourAppToken}"; + String environment = AdjustConfig.ENVIRONMENT_SANDBOX; + AdjustConfig config = new AdjustConfig(this, appToken, environment); + Adjust.onCreate(config); + + registerActivityLifecycleCallbacks(new AdjustLifecycleCallbacks()); + + //... + } + + private static final class AdjustLifecycleCallbacks implements ActivityLifecycleCallbacks { + @Override + public void onActivityResumed(Activity activity) { + Adjust.onResume(); + } + + @Override + public void onActivityPaused(Activity activity) { + Adjust.onPause(); + } + + //... + } + } + ``` + +##### レベル9から13のAPI + +Gradleの`minSdkVersion`が`9`から`13`の間の場合、`14`以上にアップデートしていただくと今後の連携の手順が簡単になります。 +ぜひご検討ください。Androidの[公式ページ][android-dashboard]にて最新のマーケットシェアをご確認ください。 + +セッショントラッキングを正しく行うためには、アクティビティの開始または停止ごとにadjust SDKの該当メソッドをコールする必要があります。 +これを怠ると、SDKはセッションの開始や終了を関知できなくなる場合があります。正しいセッショントラッキングのために、 +**すべてのアクティビティに対して以下の作業を行ってください**。 + +- アクティビティにソースファイルを開いてください。 +- ファイル最上部に`import`の記述を加えてください。 +- アクティビティの`onResume`メソッド中に`Adjust.onResume()`へのコールを追加してください。 + `onResume`メソッドがなければ作成してください。 +- アクティビティの`onPause`メソッド中に`Adjust.onPause()`へのコールを追加してください。 + `onPause`メソッドがなければ作成してください。 + +これらの手順が済むと、アクティビティは次のようになるはずです。 + +```java +import com.adjust.sdk.Adjust; +// ... +public class YourActivity extends Activity { + protected void onResume() { + super.onResume(); + Adjust.onResume(); + } + protected void onPause() { + super.onPause(); + Adjust.onPause(); + } + // ... +} +``` + +**すべての**アクティビティに対してこれらの作業を行ってください。今後新しいアクティビティを作成した時にも忘れずに行ってください。 +すべてのアクティビティに対する共通のスーパークラスにこれを実装するという方法もあります。 + +#### Adjustログ + +`AdjustConfig`インスタンスの`setLogLevel`に設定するパラメータを変更することによって記録するログのレベルを調節できます。 +パラメータは以下の種類があります。 + +```java +config.setLogLevel(LogLevel.VERBOSE); // enable all logging +config.setLogLevel(LogLevel.DEBUG); // enable more logging +config.setLogLevel(LogLevel.INFO); // the default +config.setLogLevel(LogLevel.WARN); // disable info logging +config.setLogLevel(LogLevel.ERROR); // disable warnings as well +config.setLogLevel(LogLevel.ASSERT); // disable errors as well +config.setLogLevel(LogLevel.SUPRESS); // disable all log output +``` + +#### アプリのビルド + +アプリをビルドして実行しましょう。`LogCat`ビューアにて`tag:Adjust`フィルターを設定し、他のログすべてを非表示にすることがでいます。 +アプリが実行されたあと、`Install tracked`のログが出力されるはずです。 + +### 追加機能 + +プロジェクトにadjust SDKを連携させると、以下の機能をご利用できるようになります。 + +#### イベントトラッキング + +adjustを使ってアプリ内のイベントをトラッキングすることができます。ここではあるボタンのタップを毎回トラックしたい場合について説明します。 +[dashboard]にてイベントトークンを作成し、そのイベントトークンは仮に`abc123`というイベントトークンと関連しているとします。 +タップをトラックするため、ボタンの`onClick`メソッドに以下のような記述を追加します。 + +```java + AdjustEvent event = new AdjustEvent("abc123"); + Adjust.trackEvent(event); +``` + +##### 収益のトラッキング + +広告をタップした時やアプリ内課金をした時などにユーザーが報酬を得る仕組みであれば、そういったイベントもトラッキングできます。 +1回のタップで1ユーロセントの報酬と仮定すると、報酬イベントは以下のようになります。 + +```java +AdjustEvent event = new AdjustEvent("abc123"); +event.setRevenue(0.01, "EUR"); +Adjust.trackEvent(event); +``` + +もちろんこれはコールバックパラメータと紐付けることができます。 + +通貨トークンを設定する場合、adjustは自動的に収益を任意の報酬に変換します。 +詳しくは[通貨の変換][currency-conversion]をご覧ください。 + +収益とイベントトラッキングについては[イベントトラッキングガイド][event-tracking]もご参照ください。 + +イベントインスタンスは、イベントがトラッキングされる前にそのイベントを設定するためにも使えます。 + +##### アプリ内課金の検証 + +adjustのサーバーサイドのレシート検証ツール、Purchase Verificationを使ってアプリ内で行われたアプリ内課金の妥当性を調べる際は、 +Android purchase SDKをご利用ください。詳しくは[こちら][android-purchase-verification]をご覧ください。 + +##### コールバックパラメータ + +[dashboard]でイベントにコールバックURLを登録することができます。イベントがトラッキングされるたびに +そのURLにGETリクエストが送信されます。トラッキングする前にイベントで`addCallbackParameter`をコールすることによって、 +イベントにコールバックパラメータを追加できます。そうして追加されたパラメータはコールバックURLに送られます。 + +例えば、コールバックURLに`http://www.adjust.com/callback`を登録した場合、イベントトラッキングは以下のようになります。 + +```java +AdjustEvent event = new AdjustEvent("abc123"); +event.addCallbackParameter("key", "value"); +event.addCallbackParameter("foo", "bar"); +Adjust.trackEvent(event); +``` +この場合、adjustはこのイベントをトラッキングし以下にリクエストが送られます。 + +``` +http://www.adjust.com/callback?key=value&foo=bar +``` + +パラメータの値として使われることのできるプレースホルダーは、`{gps_adid}`のような様々な形に対応しています。 +得られるコールバック内で、このプレースホルダーは該当デバイスのGoogle PlayサービスIDに置き換えられます。 +独自に設定されたパラメータには何も格納しませんが、コールバックに追加されます。 +イベントにコールバックを登録していない場合は、これらのパラメータは使われません。 + +URLコールバックについて詳しくは[コールバックガイド][callbacks-guide]をご覧ください。 +利用可能な値のリストもこちらで参照してください。 + +##### パートナーパラメータ + +adjustのダッシュボード上で連携が有効化されているネットワークパートナーに送信するパラメータを設定することができます。 + +これは上記のコールバックパラメータと同様に機能しますが、 +`AdjustEvent`インスタンスの`addPartnerParameter`メソッドをコールすることにより追加されます。 + +```java +AdjustEvent event = new AdjustEvent("abc123"); +event.addPartnerParameter("key", "value"); +event.addPartnerParameter("foo", "bar"); +Adjust.trackEvent(event); +``` + +スペシャルパートナーとその統合について詳しくは[連携パートナーガイド][special-partners]をご覧ください。 + +### コールバック ID +トラッキングしたいイベントにカスタムIDを追加できます。このIDはイベントをトラッキングし、成功か失敗かの通知を受け取けとれるようコールバックを登録することができます。このIDは`AdjustEvent`インスタンスの`setCallbackId`メソッドと呼ぶように設定できます: + +```java +AdjustEvent event = new AdjustEvent("abc123"); +event.setCallbackId("Your-Custom-Id"); +Adjust.trackEvent(event); +``` + +#### セッションパラメータ + +いくつかのパラメータは、adjust SDKのイベントごと、セッションごとに送信するために保存されます。 +このいずれかのパラメータを追加すると、これらはローカル保存されるため、毎回追加する必要はありません。 +同じパラメータを再度追加しても何も起こりません。 + +これらのセッションパラメータはadjust SDKが立ち上がる前にコールすることができるので、インストール時に送信を確認することもできます。 +インストール時に送信したい場合は、adjust SDKの初回立ち上げを[遅らせる](#delay-start)ことができます。 +ただし、必要なパラメータの値を得られるのは立ち上げ後となります。 + +##### セッションコールバックパラメータ + +[イベント](#callback-parameters)で設定された同じコールバックパラメータを、 +adjust SDKのイベントごとまたはセッションごとに送信するために保存することもできます。 + +セッションコールバックパラメータのインターフェイスとイベントコールバックパラメータは似ています。 +イベントにキーと値を追加する代わりに、`Adjust`の`Adjust.addSessionCallbackParameter(String key, String value)`へのコールで追加されます。 + +```java +Adjust.addSessionCallbackParameter("foo", "bar"); + +``` + +セッションコールバックパラメータは、イベントに追加されたコールバックパラメータとマージされます。 +イベントに追加されたコールバックパラメータは、セッションコールバックパラメータより優先されます。 +イベントに追加されたコールバックパラメータがセッションから追加されたパラメータと同じキーを持っている場合、 +イベントに追加されたコールバックパラメータの値が優先されます。 + +`Adjust.removeSessionCallbackParameter(String key)`メソッドに指定のキーを渡すことで、 +特定のセッションコールバックパラメータを削除することができます。 + +```java +Adjust.removeSessionCallbackParameter("foo"); +``` + +セッションコールバックパラメータからすべてのキーと値を削除したい場合は、 +`Adjust.resetSessionCallbackParameters()`メソッドを使ってリセットすることができます。 + +```java + Adjust.resetSessionCallbackParameters(); +``` + +##### セッションパートナーパラメータ + +adjust SDKのイベントごとやセッションごとに送信される[セッションコールバックパラメータ](#session-callback-parameters)があるように、 +セッションパートナーパラメータも用意されています。 + +これらはネットワークパートナーに送信され、adjust[ダッシュボード]で有効化されている連携のために利用されます。 + +セッションパートナーパラメータのインターフェイスとイベントパートナーパラメータは似ています。 +イベントにキーと値を追加する代わりに、`Adjust.addSessionPartnerParameter(String key, String value)`へのコールで追加されます。 + +```java + Adjust.addSessionPartnerParameter("foo", "bar"); +``` + +セッションパートナーパラメータはイベントに追加されたパートナーパラメータとマージされます。イベントに追加されたパートナーパラメータは、 +セッションパートナーパラメータより優先されます。イベントに追加されたパートナーパラメータが +セッションから追加されたパラメータと同じキーを持っている場合、イベントに追加されたパートナーパラメータの値が優先されます。 + +`Adjust.removeSessionPartnerParameter(String key)`メソッドに指定のキーを渡すことで、 +特定のセッションパートナーパラメータを削除することができます。 + +```java +Adjust.removeSessionPartnerParameter("foo"); +``` + +セッションパートナーパラメータからすべてのキーと値を削除したい場合は、 +`Adjust.resetSessionPartnerParameters()`メソッドを使ってリセットすることができます。 + +```java +Adjust.resetSessionPartnerParameters(); +``` + +##### ディレイスタート + +adjust SDKのスタートを遅らせると、ユニークIDなどのセッションパラメータを取得しインストール時に送信できるようにすることができます。 + +`AdjustConfig`インスタンスの`setDelayStart`メソッドで、遅らせる時間を秒単位で設定できます。 + +```java +adjustConfig.setDelayStart(5.5); +``` + +この場合、adjust SDKは最初のインストールセッションと生成されるイベントを初めの5.5秒間は送信しません。 +この時間が過ぎるまで、もしくは`Adjust.sendFirstPackages()`がコールされるまで、 +セッションパラメータはすべてディレイインストールセッションとイベントに追加され、adjust SDKは通常通り再開します。 + +adjust SDKのディレイスタートは最大で10秒です。 + +#### アトリビューションコールバック + +トラッカーのアトリビューション変化の通知を受けるために、リスナを登録することができます。 +アトリビューションには複数のソースがあり得るため、この情報は同時に送ることができません。匿名リスナを作成する最も簡単な方法を以下で紹介します。 + +[アトリビューションデータに関するポリシー][attribution-data]を必ずご確認ください。 + +`AdjustConfig`インスタンスで、SDKをスタートする前に以下の匿名リスナを追加してください。 + +```java +AdjustConfig config = new AdjustConfig(this, appToken, environment); + +config.setOnAttributionChangedListener(new OnAttributionChangedListener() { + @Override + public void onAttributionChanged(AdjustAttribution attribution) { + } +}); + +Adjust.onCreate(config); +``` + +代わりに、`Application`クラスに`OnAttributionChangedListener`インターフェイスを実装してリスナとして設定することもできます。 + +```java +AdjustConfig config = new AdjustConfig(this, appToken, environment); +config.setOnAttributionChangedListener(this); +Adjust.onCreate(config); +``` + +リスナはSDKが最後のアトリビューションデータを取得した時に呼ばれます。 +リスナの機能で`attribution`パラメータを確認することができます。このパラメータのプロパティの概要は以下の通りです。 + +- `String trackerToken` 最新アトリビューションのトラッカートークン +- `String trackerName` 最新アトリビューションのトラッカー名 +- `String network` 最新アトリビューションの流入元名 +- `String campaign` 最新アトリビューションのキャンペーン名 +- `String adgroup` 最新アトリビューションのアドグループ名 +- `String creative` 最新アトリビューションのクリエイティブ名 +- `String clickLabel` 最新アトリビューションのクリックラベル +- `String adid` adjustユニークID + +#### イベントとセッションのコールバック + +イベントとセッションの双方もしくはどちらかをトラッキングし、成功か失敗かの通知を受け取れるようリスナを登録することができます。 +`AdjustConfig`オブジェクトを生成すると、リスナをいくつでも追加することができます。 + +```java +AdjustConfig config = new AdjustConfig(this, appToken, environment); + +// Set event success tracking delegate. +config.setOnEventTrackingSucceededListener(new OnEventTrackingSucceededListener() { + @Override + public void onFinishedEventTrackingSucceeded(AdjustEventSuccess eventSuccessResponseData) { + // ... + } +}); + +// Set event failure tracking delegate. +config.setOnEventTrackingFailedListener(new OnEventTrackingFailedListener() { + @Override + public void onFinishedEventTrackingFailed(AdjustEventFailure eventFailureResponseData) { + // ... + } +}); + +// Set session success tracking delegate. +config.setOnSessionTrackingSucceededListener(new OnSessionTrackingSucceededListener() { + @Override + public void onFinishedSessionTrackingSucceeded(AdjustSessionSuccess sessionSuccessResponseData) { + // ... + } +}); + +// Set session failure tracking delegate. +config.setOnSessionTrackingFailedListener(new OnSessionTrackingFailedListener() { + @Override + public void onFinishedSessionTrackingFailed(AdjustSessionFailure sessionFailureResponseData) { + // ... + } +}); + +Adjust.onCreate(config); +``` + +リスナ関数はSDKがサーバーにパッケージ送信を試みた後で呼ばれます。 +リスナ関数内でリスナ用のレスポンスデータオブジェクトを確認することができます。 +レスポンスデータのプロパティの概要は以下の通りです。 + +- `String message` サーバーからのメッセージまたはSDKのエラーログ +- `String timestamp` サーバーからのタイムスタンプ +- `String adid` adjustから提供されるユニークデバイスID +- `JSONObject jsonResponse` サーバーからのレスポンスのJSONオブジェクト + +イベントのレスポンスデータは以下を含みます。 + +- `String eventToken` トラッキングされたパッケージがイベントだった場合、そのイベントトークン +- `String callbackId` イベントオブジェクトにカスタム設定されたコールバックID + +失敗したイベントとセッションは以下を含みます。 + +- `boolean willRetry` しばらく後に再送を試みる予定であるかどうかを示します。 + +#### トラッキングの無効化 + +`setEnabled`にパラメータ`false`を渡すことで、adjustSDKが行うデバイスのアクティビティのトラッキングをすべて無効にすることができます。 +**この設定はセッション間で記憶されます** + + ```java + Adjust.setEnabled(false); + ``` + +adjust SDKが現在有効かどうか、`isEnabled`関数を呼び出せば確認できます。 +また、`setEnabled`関数に`true`を渡せば、adjust SDKを有効にすることができます。 + +#### オフラインモード + +adjustのサーバーへの送信を一時停止し、保持されているトラッキングデータを後から送信するために +adjust SDKをオフラインモードにすることができます。 +オフラインモード中はすべての情報がファイルに保存されるので、イベントをたくさん発生させすぎないようにご注意ください。 + +`true`パラメータで`setOfflineMode`を呼び出すとオフラインモードを有効にできます。 + +```java +Adjust.setOfflineMode(true); +``` + +反対に、`false`パラメータで`setOfflineMode`を呼び出せばオフラインモードを解除できます。 +adjust SDKがオンラインモードに戻った時、保存されていた情報は正しいタイムスタンプでadjustのサーバーに送られます。 + +トラッキングの無効化とは異なり、この設定はセッション間で**記憶されません**。 +オフラインモード時にアプリを終了しても、次に起動した時にはオンラインモードとしてアプリが起動します。 + +#### イベントバッファリング + +イベントトラッキングを酷使している場合、HTTPリクエストを遅らせて1分毎にまとめて送信したほうがいい場合があります。 +その場合は、`AdjustConfig`インスタンスでイベントバッファリングを有効にしてください。 + +```java +AdjustConfig config = new AdjustConfig(this, appToken, environment); +config.setEventBufferingEnabled(true); +Adjust.onCreate(config); +``` + +### GDPR消去する権利(忘れられる権利) + +次のメソッドを呼び出すと、EUの一般データ保護規制(GDPR)第17条に従い、ユーザーが消去する権利(忘れられる権利)を行使した際にAdjust SDKがAdjustバックエンドに情報を通知します。 + +```java +Adjust.gdprForgetMe(context); +``` + +この情報を受け取ると、Adjustはユーザーのデータを消去し、Adjust SDKはユーザーの追跡を停止します。この削除された端末からのリクエストは今後、Adjustに送信されません。 + +#### バックグラウンドでのトラッキング + +adjust SDKはデフォルドではアプリがバックグラウンドにある時はHTTPリクエストを停止します。 +この設定は`AdjustConfig`インスタンスで変更できます。 + +```java +AdjustConfig config = new AdjustConfig(this, appToken, environment); +config.setSendInBackground(true); +Adjust.onCreate(config); +``` + +#### デバイスID + +Google Analyticsなどの一部のサービスでは、レポートの重複を防ぐためにデバイスIDとクライアントIDを連携させることが求められます。 + +Google広告IDを取得する必要がある場合、広告IDはバックグラウンドでのスレッドでしか読み込みできないという制約があります。 +`getGoogleAdId`関数と`OnDeviceIdsRead`インスタンスをコールすると、この条件以外でも取得できるようになります。 + +```java +Adjust.getGoogleAdId(this, new OnDeviceIdsRead() { + @Override + public void onGoogleAdIdRead(String googleAdId) { + // ... + } +}); +``` + +`OnDeviceIdsRead`インスタンスの`onGoogleAdIdReadメソッド内で、Google広告IDを`googleAdId`変数として利用できます。 + +#### Pushトークン + +プッシュ通知のトークンを送信するには、トークンを取得次第またはその値が変更され次第、adjustへの以下のコールを追加してください。 + +```java +Adjust.setPushToken(pushNotificationsToken, context); +``` + +#### プレインストールのトラッカー + +すでにアプリをインストールしたことのあるユーザーをadjust SDKを使って識別したい場合は、次の手順で設定を行ってください。 + +- [dashboard]上で新しいトラッカーを作成してください。 +- App Delegateを開き、`ADJConfig`のデフォルトトラッカーを設定してください。 + + ```java + AdjustConfig config = new AdjustConfig(this, appToken, environment); + config.setDefaultTracker("{TrackerToken}"); + Adjust.onCreate(config); + ``` + + `{TrackerToken}`にステップ2で作成したトラッカートークンを入れてください。 +ダッシュボードには`http://app.adjust.com/`を含むトラッカーURLが表示されます。 +ソースコード内にはこのURLすべてではなく、6文字のトークンを抜き出して指定してください。 + +- アプリをビルドしてください。LogCatで下記のような行が表示されるはずです。 + + ``` + Default tracker: 'abc123' + ``` + +#### ディープリンキング + +URLからアプリへのディープリンクを使ったadjustトラッカーURLをご利用の場合、ディープリンクURLとその内容の情報を得られる可能性があります。 +ユーザーがすでにアプリをインストールしている状態でそのURLに訪れた場合(スタンダード・ディープリンキング)と、 +アプリをインストールしていないユーザーがURLを開いた場合(ディファード・ディープリンキング)が有り得ます。 +スタンダード・ディープリンキングの場合、Androidのプラットフォームにはディープリンクの内容を取得できる仕組みがあります。 +ディファード・ディープリンキングに対してはAndroidプラットフォームはサポートしていませんので、 +adjust SDKがディープリンクの内容を取得するメカニズムを提供します。 + +##### スタンダード・ディープリンキング + +アプリをすでにインストールしているユーザーが`deep_link`パラメータのついたadjustのトラッカーURLを叩いた後でアプリを立ち上げたい場合、 +アプリのディープリンキングを有効化する必要があります。**ユニークスキーム名**を選択し、リンクがクリックされてアプリが開いた時に起動したいアクティビティを +指定することで有効化できます。これは`AndroidManifest.xml`内で設定できます。マニフェストファルの該当のアクティビティ定義に +`intent-filter`セクションを追加し、該当のスキーム名に`android:scheme`プロパティを指定してください。 + +```xml + + + + + + + + + + + + + + +``` + +この設定をすると、トラッカーURLがクリックされた時にアプリを開くには、adjustトラッカーURLの`deep_link`パラメータにあるスキーム名を指定する必要があります。 +ディープリンクに情報を追加していないトラッカーURLは次のようになります。 + +``` +https://app.adjust.com/abc123?deep_link=adjustExample%3A%2F%2F +``` + +`deep_link`パラメータの値は**URLエンコード**される必要があります。 + +トラッカーURLをクリック後、アプリが上記の設定をされていれば、アプリは`MainActivity`インテントの通りに起動します。 +`MainActivity`クラス内で`deep_link`パラメータの内容が自動的に提供されます。 +届けられたこの情報は**エンコードされていません**が、URL内ではエンコードされています。 + +`AndroidManifest.xml`ファイルのアクティビティの`android:launchMode`設定によっては、`deep_link`パラメータの内容情報は +アクティビティファイルの適切な箇所に届けられます。`android:launchMode`のとり得る値について詳しくは[Android公式資料][android-launch-modes]をご確認ください。 + +指定のアクティビティに`Intent`オブジェクトを介してディープリンクの内容情報を送ることができる場所は2か所あります。 +アクティビティの`onCreate`メソッドか`onNewIntent`メソッドのいずれかです。アプリが起動してこれらのどちらかのメソッドが呼ばれると、 +クリックURL中の`deep_link`パラメータ内の実際に渡されたディープリンクを取得することができます。 +この情報はロジックを追加する際に使うことができます。 + +これらのメソッドからディープリンク情報を抽出する方法は以下の通りです。 + +```java +@Override +protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_main); + + Intent intent = getIntent(); + Uri data = intent.getData(); + // data.toString() -> This is your deep_link parameter value. +} +``` + +```java +@Override +protected void onNewIntent(Intent intent) { + super.onNewIntent(intent); + + Uri data = intent.getData(); + // data.toString() -> This is your deep_link parameter value. +} +``` + +##### ディファード・ディープリンキング + +ユーザーが`deep_link`パラメータのついたトラッカーURLをクリックした時にそのユーザーがアプリをデバイスにインストールしていなかった場合、 +ディファード・ディープリンキングを使用します。この場合、クリックした後ユーザーはプレイストアにリダイレクトされ、アプリをダウンロードできます。 +アプリの初回起動後、`deep_link`パラメータの内容がアプリに送信されます。 + +ディファード・ディープリンキングを使って`deep_link`パラメータの内容情報を取得するには、`AdjustConfig`オブジェクトにリスナメソッドを +設定してください。このメソッドはadjust SDKがサーバーからディープリンク内容を取得した時に呼ばれます。 + +```java +AdjustConfig config = new AdjustConfig(this, appToken, environment); + +// Evaluate the deeplink to be launched. +config.setOnDeeplinkResponseListener(new OnDeeplinkResponseListener() { + @Override + public boolean launchReceivedDeeplink(Uri deeplink) { + // ... + if (shouldAdjustSdkLaunchTheDeeplink(deeplink)) { + return true; + } else { + return false; + } + } +}); + +Adjust.onCreate(config); +``` + +adjust SDKがサーバーからディープリンク情報を受信すると、リスナ内のディープリンク内容の情報を送信しますので、`boolean`値を返してください。 +この値はadjust SDKがディープリンクから指定したスキーム名へアクティビティを起動させたいかどうかで決定してください。 +スキーム名の指定はスタンダード・ディープリンキングと同様です。 + +`true`を返すと、[スタンダード・ディープリンキング](#deeplinking-standard)の章で説明したものと同様に起動します。 +SDKにアクティビティをスタートさせたくない場合、リスナから`false`を返してください。 +ディープリンクの内容に基づいてアプリの次の挙動を決定してください。 + +##### ディープリンクを介したリアトリビューション + +adjustはディープリンクを使ったリエンゲージメントキャンペーンをサポートしています。 +詳しくは[公式資料][reattribution-with-deeplinks]をご覧ください。 + +この機能をご利用の場合、ユーザーが正しくリアトリビューションされるために、adjust SDKへのコールを追加してください。 + +アプリでディープリンクの内容データを受信したら、`Adjust.appWillOpenUrl(Uri, Context)`メソッドへのコールを追加してください。 +このコールによって、adjust SDKはディープリンクの中に新たなアトリビューションが存在するかを調べ、あった場合はadjustサーバーにこれを送信します。 +ディープリンクのついたadjustトラッカーURLのクリックによってユーザーがリアトリビュートされる場合、 +[アトリビューションコールバック](#attribution-callback)がこのユーザーの新しいアトリビューションデータで呼ばれます。 + +`Adjust.appWillOpenUrl(Uri, Context)`のコールは下記のようになります。 + +```java +@Override +protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_main); + + Intent intent = getIntent(); + Uri data = intent.getData(); + Adjust.appWillOpenUrl(data, getApplicationContext()); +} +``` + +```java +@Override +protected void onNewIntent(Intent intent) { + super.onNewIntent(intent); + + Uri data = intent.getData(); + Adjust.appWillOpenUrl(data, getApplicationContext()); +} +``` +**注**: Android SDK v4.14.0より`Adjust.appWillOpenUrl(Uri)` メソッドは**deprecated**(推奨されていません) と表示されます。代わりに`Adjust.appWillOpenUrl(Uri, Context)`メソッドを使用してください。 + +### トラブルシューティング + +#### "Session failed (Ignoring too frequent session. ...)"というエラーが出る + +このエラーはインストールのテストの際に起こりえます。アンインストール後に再度インストールするだけでは新規インストールとして動作しません。 +SDKがローカルで統計したセッションデータを失ったとサーバーは判断してエラーメッセージを無視し、 +その端末に関する有効なデータのみが与えられます。 + +この仕様はテスト中には厄介かもしれませんが、サンドボックスと本番用の挙動をできる限り近づけるために必要です。 + +adjustのサーバーにある端末のセッションデータをリセットすることができます。ログにあるエラーメッセージをチェックしてください。 + +``` +Session failed (Ignoring too frequent session. Last session: YYYY-MM-DDTHH:mm:ss, this session: YYYY-MM-DDTHH:mm:ss, interval: XXs, min interval: 20m) (app_token: {yourAppToken}, adid: {adidValue}) +``` + +`{yourAppToken}`と`{adidValue}`/`{gps_adidValue}`/`{androidIDValue}`の各値を入力し、以下のリンクを開いてください。 + + +``` +http://app.adjust.com/forget_device?app_token={yourAppToken}&adid={adidValue} +``` + +``` +http://app.adjust.com/forget_device?app_token={yourAppToken}&gps_adid={gps_adidValue} +``` + +``` +http://app.adjust.com/forget_device?app_token={yourAppToken}&android_id={androidIDValue} +``` + +端末に関する記録が消去されると、このリンクは`Forgot device`と返します。 +もしその端末の記録がすでに消去されていたり、値が不正だった場合は`Device not found`が返ります。 + +#### Broadcastレシーバがインストールリファラを受信していない + +[ガイド](#broadcast_receiver)に従って設定を済ませていれば、 +BroadcastレシーバはadjustのSDKとサーバーにインストールを送信するよう設定されているはずです。 + +手動でテスト用インストールリファラを作動させることで確認できます。`com.your.appid`にアプリIDを入力し、Android Studioの +[adb](http://developer.android.com/tools/help/adb.html)ツールで以下のコマンドを実行してください。 + +``` +adb shell am broadcast -a com.android.vending.INSTALL_REFERRER -n com.your.appid/com.adjust.sdk.AdjustReferrerReceiver --es "referrer" "adjust_reftag%3Dabc1234%26tracking_id%3D123456789%26utm_source%3Dnetwork%26utm_medium%3Dbanner%26utm_campaign%3Dcampaign" +``` + +`INSTALL_REFERRER`インテントに対してすでに別のBroadcastリファラを使っている状態でこの[ガイド][referrer]の設定をした場合、 +`com.adjust.sdk.AdjustReferrerReceiver`にBroadcastレシーバを入力してください。 + +`-n com.your.appid/com.adjust.sdk.AdjustReferrerReceiver`パラメータを削除することもできます。 +削除すると、デバイスに入っているすべてのアプリが`INSTALL_REFERRER`インテントを受信します。 + +ログレベルを`verbose`に設定していれば、リファラが読み込まれると以下のログが表示されるはずです。 + +``` +V/Adjust: Reading query string (adjust_reftag=abc1234&tracking_id=123456789&utm_source=network&utm_medium=banner&utm_campaign=campaign) from reftag +``` + +SDKのパッケージハンドラーに追加されるクリックパッケージは以下のような形です。 + +``` +V/Adjust: Path: /sdk_click + ClientSdk: android4.6.0 + Parameters: + app_token abc123abc123 + click_time yyyy-MM-dd'T'HH:mm:ss.SSS'Z'Z + created_at yyyy-MM-dd'T'HH:mm:ss.SSS'Z'Z + environment sandbox + gps_adid 12345678-0abc-de12-3456-7890abcdef12 + needs_attribution_data 1 + referrer adjust_reftag=abc1234&tracking_id=123456789&utm_source=network&utm_medium=banner&utm_campaign=campaign + reftag abc1234 + source reftag + tracking_enabled 1 +``` + +アプリの起動前にこのテストを行う場合、パッケージの送信は表示されません。パッケージはアプリの起動後に送信されます。 + +"**重要:** この機能をテストをするために`adb`ツールを利用することは推奨しておりません。全てのリファラコンテンツを`adb`でテストするためには(`&`で分けられた複数のパラメータがある場合)、ブロードキャストリシーバーで受信するためにコンテンツをエンコードすることが必要です。もしエンコードをしないと、`adb`はレファラを最初の`&`サインで切り、誤ったコンテンツをブロードキャストレシーバーに伝えます。アプリがどのようにエンコードされていないリファラを受信しているかを確認したい場合は、Adjustのサンプルアプリを利用して、`MainActivity.java`ファイルの`onFireIntentClick`メソッドのインテント内に送信されたコンテンツを変更してください: + +```java +public void onFireIntentClick(View v) { + Intent intent = new Intent("com.android.vending.INSTALL_REFERRER"); + intent.setPackage("com.adjust.examples"); + intent.putExtra("referrer", "utm_source=test&utm_medium=test&utm_term=test&utm_content=test&utm_campaign=test"); + sendBroadcast(intent); +} +``` +自分の選んだコンテントで`putExtra`2番目のパラメーターを自由に変更してください。 + +#### アプリ起動時にイベントを始動したい + +直感的には分かりにくいですが、グローバル`Application`クラスの`onCreate`メソッドはアプリ起動時だけでなく、 +アプリによってシステムやイベントが作動する時にも呼ばれます。 + +adjust SDKはこの場合の初期化についてサポートしています。この機能はアプリが実際に起動した時でなく、 +アクティビティがスタートした時、たとえばユーザーがアプリを起動させた時に起こります。 + +これらのコールはアプリがユーザーの操作以外の要因で起動した場合にも、adjust SDKを起動しイベントを送信しします。これはアプリの外部要因にもよります。 + +このように、アプリ起動時のイベントの作動はインストールとセッションの数を正確にトラッキングできません。 + +インストール後にイベントを作動させたい場合は、[アトリビューション変更時用のリスナ](#attribution_changed_listener)をご利用ください。 + +アプリ起動時にイベントを作動させたい場合は、スタートするアクティビティの`onCreate`メソッドをご使用ください。 + +[dashboard]: http://adjust.com +[adjust.com]: http://adjust.com +[en-readme]: ../../README.md +[zh-readme]: ../chinese/README.md +[ja-readme]: ../japanese/README.md +[ko-readme]: ../korean/README.md + +[maven]:http://maven.org +[example-java]: ../../Adjust/example-app-java +[example-tv]: ../../Adjust/example-app-tv +[releases]:https://github.com/adjust/adjust_android_sdk/releases +[referrer]:doc/english/referrer.md +[google_ad_id]:https://support.google.com/googleplay/android-developer/answer/6048248?hl=en +[event-tracking]:https://docs.adjust.com/en/event-tracking +[callbacks-guide]:https://docs.adjust.com/en/callbacks +[application_name]:http://developer.android.com/guide/topics/manifest/application-element.html#nm +[special-partners]:https://docs.adjust.com/en/special-partners +[attribution-data]:https://github.com/adjust/sdks/blob/master/doc/attribution-data.md +[android-dashboard]:http://developer.android.com/about/dashboards/index.html +[currency-conversion]:https://docs.adjust.com/en/event-tracking/#tracking-purchases-in-different-currencies +[android_application]:http://developer.android.com/reference/android/app/Application.html +[android-launch-modes]:https://developer.android.com/guide/topics/manifest/activity-element.html +[google_play_services]:http://developer.android.com/google/play-services/setup.html +[activity_resume_pause]:doc/activity_resume_pause.md +[reattribution-with-deeplinks]:https://docs.adjust.com/en/deeplinking/#manually-appending-attribution-data-to-a-deep-link +[android-purchase-verification]:https://github.com/adjust/android_purchase_sdk + + +### ライセンス + +adjust SDKはMITライセンスを適用しています。 + +Copyright (c) 2012-2018 Adjust GmbH, +http://www.adjust.com + +以下に定める条件に従い、本ソフトウェアおよび関連文書のファイル(以下「ソフトウェア」)の複製を取得するすべての人に対し、 +ソフトウェアを無制限に扱うことを無償で許可します。これには、ソフトウェアの複製を使用、複写、変更、結合、掲載、頒布、サブライセンス、 +および/または販売する権利、およびソフトウェアを提供する相手に同じことを許可する権利も無制限に含まれます。 + +上記の著作権表示および本許諾表示を、ソフトウェアのすべての複製または重要な部分に記載するものとします。 + +ソフトウェアは「現状のまま」で、明示であるか暗黙であるかを問わず、何らの保証もなく提供されます。 +ここでいう保証とは、商品性、特定の目的への適合性、および権利非侵害についての保証も含みますが、それに限定されるものではありません。 +作者または著作権者は、契約行為、不法行為、またはそれ以外であろうと、ソフトウェアに起因または関連し、 +あるいはソフトウェアの使用またはその他の扱いによって生じる一切の請求、損害、その他の義務について何らの責任も負わないものとします。 diff --git a/doc/japanese/fb_pixel_ja.md b/doc/japanese/fb_pixel_ja.md new file mode 100644 index 000000000..ae2f6071d --- /dev/null +++ b/doc/japanese/fb_pixel_ja.md @@ -0,0 +1,128 @@ +## Facebook Pixelの統合 + + +[Facebook Pixel](https://www.facebook.com/business/help/952192354843755) はFacebookが提供するウェブサイト専用の分析ツールです。以前は、アプリ内のweb viewでPixelイベントをトラッキングするのにFacebook SDKを利用できませんでした。[FB SDK](https://developers.facebook.com/docs/analytics) v4.34のリリース以降はトラッキングが可能になり、[Hybrid Mobile App Events](https://developers.facebook.com/docs/app-events/hybrid-app-events) を使用して、Facebook PixelイベントをFacebook アプリイベントに変換します。 + +また、FB SDKを統合しなくても、Adjust SDKを使用してアプリ内のweb viewでFacebook Pixelを利用できるようになりました。 + +## Facebookの統合 + +### アプリサンプル + +[`example-fbpixel` ディレクトリ][example-fbpixel]にあるアプリサンプルを見ると、Adjustのweb view SDKを使用してどのようにFacebook Pixelイベントをトラッキングできるかがわかります。 + +### FacebookアプリID + +FB SDKを統合する必要はありませんが、Adjust SDKがFacebook Pixelを統合するために、一部FB SDKと同じ統合手順に従う必要があります。 + +まず[FB SDK Android SDKガイド](https://developers.facebook.com/docs/android/getting-started/#app_id) に記載の通り、対象のFacebookアプリIDをアプリに追加する必要があります。 +統合手順は上記リンクガイドに記載がありますが、以下にも転載致します。 + +- `strings.xml` ファイルを開けます. パスの例: `/app/src/main/res/values/strings.xml`. +- 名前`facebook_app_id`と対象のFacebook App IDに新しい文字列を追加します。 +- `AndroidManifest.xml`を開きます。 +- `uses-permission` エレメントを以下のマニフェストに追加します。 + + + ```xml + + ``` + +- `meta-data`エレメントを`application`エレメントに追加します。 + +```xml + + ... + + ... + + ``` + +### Facebook Pixelの設定 + +Facebook Pixelの統合方法については、Facebookのガイドに従ってください。Javascriptコードは以下のように記述する必要があります。 + +```js + + +... + +``` + +この後、[Hybrid Mobile App Eventsガイド](https://developers.facebook.com/docs/app-events/hybrid-app-events) の`Update Your Pixel`セクションに記載の通り、Facebook Pixelのコードを以下のように変更するだけです。 + + +```js +fbq('init', ); +fbq('set', 'mobileBridge', , ); +``` + + +**注意**:最初に`'init'`メソッドを呼び出し、直後に`'set'`メソッドを呼び出すことが**非常に重要**です。HTMLのウェブページに貼り付けるFacebookが提供する(上記に示すような)スクリプトスニペットには、`'init'`メソッドの呼び出しの直後にページビューイベントの`'track'`メソッドが含まれています。このページビューイベントを正しくトラッキングするには、両者の間に必ず`'set'`メソッドを呼び出してください。 + +## Adjustの統合 + +### Facebook SDK Javascriptインターフェイスの登録 + + +[Android web view SDK](web_views_ja.md) アプリの統合ガイドを参照ください。登録のセクションで、Adjustブリッジのデフォルトのインスタンスを取得します(以下参照)。 + +```java +AdjustBridge.registerAndGetInstance(getApplication(), webview); +``` + +save the return instance, as `adjustBridgeInstance`, for example, and then add the following line: + +```java +adjustBridgeInstance.registerFacebookSDKJSInterface(); +``` + +### Event名の設定 + +Adjust web bridge SDKは、Facebook PixelイベントをAdjustイベントに変換します。 + +このため、Facebook Pixel設定の`fbq('track', 'PageView');`をコピーペーストで追加し、Adjust SDKを開始してFacebook Pixelイベントをトラッキングする ***前*** に、Facebook Pixelsを特定のAdjustイベントにマッピングするか、デフォルトのAdjustイベントトークンを設定する必要があります。 + +Facebook PixelイベントをAdjustイベントにマッピングするには、Adjust SDKを初期化する前に`adjustConfig`インスタンスの`addFbPixelMapping(fbEventNameKey, adjEventTokenValue)`を呼び出します。マッピングの例は以下の通りです。 + + +```js +adjustConfig.addFbPixelMapping('fb_mobile_search', adjustEventTokenForSearch); +adjustConfig.addFbPixelMapping('fb_mobile_purchase', adjustEventTokenForPurchase); +``` + +注意:これは、以下のFacebook Pixelイベントをトラッキングする際の`fbq('track', 'Search', ...);`および`fbq('track', 'Purchase', ...);`にそれぞれ対応します。残念ながら、Javascriptでトラッキングされるイベント名とFB SDKで使用されるイベント名との間のすべてのマッピングスキームにはアクセスできません。 + +参考として、以下はAdjustがこれまで確認したイベント名の情報になります。 + +| Pixelイベント名 | 対応するFacebookアプリのイベント名 +| ---------------- | ------------------------------------- +| ViewContent | fb_mobile_content_view +| Search | fb_mobile_search +| AddToCart | fb_mobile_add_to_cart +| AddToWishlist | fb_mobile_add_to_wishlist +| InitiateCheckout | fb_mobile_initiated_checkout +| AddPaymentInfo | fb_mobile_add_payment_info +| Purchase | fb_mobile_purchase +| CompleteRegistration | fb_mobile_complete_registration + + +これは完全なリストではない可能性があります。また、Facebookが現在のリストに追加や更新を加える可能性もあります。テスト中は、Adjustログで以下のような警告を確認してください。 + +``` +There is not a default event token configured or a mapping found for event named: 'fb_mobile_search'. It won't be tracked as an adjust event +``` + +``` +イベント名'fb_mobile_search'について、設定されたデフォルトイベントトークンが存在しないか、マッピングが見つかりません。Adjustイベントとしてトラッキングできません。 +``` + +また、マッピングを設定しない場合でもデフォルトのAdjustイベントの使用は可能です。Adjust SDKを初期化する前に、`adjustConfig.setFbPixelDefaultEventToken(defaultEventToken);`を呼び出してください。 + + +[example-fbpixel]: ../../Adjust/example-fbpixel diff --git a/doc/korean/README.md b/doc/korean/README.md new file mode 100644 index 000000000..4bf02b28d --- /dev/null +++ b/doc/korean/README.md @@ -0,0 +1,1034 @@ +## 요약 + +이 항목에서는 Adjust의 Android SDK에 대해 설명합니다. Adjust에 대한 자세한 내용은 [adjust.com]을 참조하십시오. + +Web views를 쓰는 앱이며 Javascript 코드에서 Adjust 추적을 사용하고자 할 경우 안드로이드 [web views SDK 설명서](doc/english/web_views.md)를 참조해 주십시오. + +Read this in other languages: [English][en-readme], [中文][zh-readme], [日本語][ja-readme], [한국어][ko-readme]. + +## 목차 + +* [앱 예제](#example-app) +* [기본 연동](#basic-integration) + * [프로젝트에 SDK 추가](#sdk-add) + * [Google Play 서비스 추가](#sdk-gps) + * [권한 추가](#sdk-permissions) + * [Proguard 설정](#sdk-proguard) + * [설치 referrer](#install-referrer) + * [Google Play referrer API](#gpr-api) + * [Google Play Store 인텐트](#gps-intent) + * [앱에 SDK 연동](#sdk-integrate) + * [기본 설정](#basic-setup) + * [세션 추적](#session-tracking) + * [API 레벨 14 이상](#session-tracking-api14) + * [API 레벨 9-13](#session-tracking-api9) + * [Adjust 로그 기록(logging)](#adjust-logging) + * [앱 빌드](#build-the-app) +* [부가 기능](#additional-features) + * [이벤트 추적](#event-tracking) + * [매출 추적](#revenue-tracking) + * [매출 중복 제거](#revenue-deduplication) + * [인앱 구매 검증](#iap-verification) + * [콜백 파라미터](#callback-parameters) + * [파트너 파라미터](#partner-parameters) + * [콜백 ID](#callback-id) + * [세션 파라미터](#session-parameters) + * [세션 콜백 파라미터](#session-callback-parameters) + * [세션 파트너 파라미터](#session-partner-parameters) + * [예약 시작(delay start)](#delay-start) + * [어트리뷰션 콜백](#attribution-callback) + * [세션 및 이벤트 콜백](#session-event-callbacks) + * [추적 사용 중지](#disable-tracking) + * [오프라인 모드](#offline-mode) + * [이벤트 버퍼링(buffering)](#event-buffering) + * [GDPR(일반 개인정보 보호법) 상의 잊힐 권리](#gdpr-forget-me) + * [SDK 서명](#sdk-signature) + * [백그라운드 추적](#background-tracking) + * [기기 ID](#device-ids) + * [Google Play 서비스 광고 식별자](#di-gps-adid) + * [Amazon 광고 식별자](#di-amz-adid) + * [Adjust 기기 식별자](#di-adid) + * [사용자 어트리뷰션](#user-attribution) + * [푸시 토큰(push token)](#push-token) + * [사전 설치 트래커(pre-installed trackers)](#pre-installed-trackers) + * [딥링크](#deeplinking) + * [기본 딥링크](#deeplinking-standard) + * [지연된(deferred) 딥링크](#deeplinking-deferred) + * [딥링크를 통한 리어트리뷰션](#deeplinking-reattribution) +* [문제해결](#troubleshooting) + * ["Session failed (Ignoring too frequent session. ...)" 오류가 나타납니다.](#ts-session-failed) + * [브로드캐스트 리시버가 설치 참조 페이지를 제대로 캡처하고 있나요?](#ts-broadcast-receiver) + * [응용 프로그램 런칭 시 이벤트를 촉발할 수 있나요?](#ts-event-at-launch) +* [라이선스](#license) + +## 앱 예제 + +[`example-app-java` directory][example-java] 안에 예시 앱이 있습니다. 그리고 [`example-tv` directory][example-tv]안에 예시 Android TV가 있습니다. Android 프로젝트를 열어 Adjust SDK 연동 방법의 예를 확인할 수 있습니다. + +## 기본 연동 + +다음은 Adjust SDK를 안드로이드 프로젝트와 연동하기 위해 최소한으로 수행해야 하는 절차입니다. 여기서는 Android Studio를 안드로이드 개발에 사용하고 API 레벨 9(Gingerbread) 이상을 대상으로 한다고 가정합니다. + +### 프로젝트에 SDK 추가 + +Maven을 사용하는 경우 `build.gradle` 파일에 다음 라인을 추가합니다. + +``` +implementation 'com.adjust.sdk:adjust-android:4.16.0' +implementation 'com.android.installreferrer:installreferrer:1.0' +``` + +### Google Play 서비스 추가 + +2014년 8월 1일 자로 Google Play Store의 앱은 [Google 광고 ID][google_ad_id]를 사용하여 장치를 고유하게 식별해야 합니다. Adjust SDK에서 Google 광고 ID를 사용할 수 있게 하려면 [Google Play 서비스][google_play_services]를 연동해야 합니다. 이 작업을 아직 수행하지 않은 경우 다음 단계를 수행하십시오. + +- 앱의 `build.gradle` 파일을 열고 `dependencies` 블록을 찾은 후 다음 라인을 추가합니다. + + ``` + implementation 'com.google.android.gms:play-services-analytics:16.0.4' + ``` + +**주의**: Adjust SDK는 Google Play 서비스 라이브러리 내 `play-services-analytics` 부분의 어떤 특정 버전에도 연결되어 있지 않으므로 언제나 가장 최신 또는 필요한 버전을 사용하면 됩니다. + +- **Google Play 서비스 버전 7 이상을 사용 중인 경우 이 단계를 건너뜁니다.** Package Explorer에서 Android 프로젝트의 `AndroidManifest.xml`을 엽니다. `` 요소에 다음 `meta-data` 태그를 추가합니다. + + + ```xml + + ``` + +### 권한 추가 + +Adjust SDK에 필요한 다음 권한이 `AndroidManifest.xml`에 없다면 추가하세요. + +```xml + + +``` + +Google Play Store가 대상이 **아닌** 경우 다음 권한을 추가합니다. + +```xml + +``` + +### Proguard 설정 + +Proguard를 사용 중인 경우 다음 행을 Proguard 파일에 추가합니다. + +``` +-keep public class com.adjust.sdk.** { *; } +-keep class com.google.android.gms.common.ConnectionResult { + int SUCCESS; +} +-keep class com.google.android.gms.ads.identifier.AdvertisingIdClient { + com.google.android.gms.ads.identifier.AdvertisingIdClient$Info getAdvertisingIdInfo(android.content.Context); +} +-keep class com.google.android.gms.ads.identifier.AdvertisingIdClient$Info { + java.lang.String getId(); + boolean isLimitAdTrackingEnabled(); +} +-keep public class com.android.installreferrer.** { *; } +``` + +**Google Play Store가 대상이 아닌** 경우 `com.google.android.gms` 규칙을 제거할 수 있습니다. + +### 설치 referrer + +Adjust는 앱 설치를 소스에 제대로 어트리뷰트하기 위해 **설치 referrer** 관련 정보를 필요로 합니다. 이 정보는 **Google Play Referrer API**를 사용하거나 브로드캐스트 리시버로 **Google Play Store 인텐트**를 잡아 얻을 수 있습니다. + +**중요**: Google Play Referrer API는 보다 안전하고 믿을만한 설치 referrer 정보 획득 방식을 제공하는 동시에 클릭 인젝션으로부터 어트리뷰션 제공자를 보호할 목적으로 Google이 새롭게 도입한 방식입니다. 따라서 앱에서 지원할 것을 **강력히 권장합니다**. Google Play Store 인텐트는 이보다 좀 덜 안전한 설치 referrer 정보 획득 방식입니다. 당분간은 새로운 Google Play referrer API와 공존하지만 향후에는 더 이상 사용하지 않을 예정입니다.. + +#### Google Play Referrer API + +앱에서 Google Play Referrer API를 지원하려면, [프로젝트에 SDK 추가](#sdk-add)에 설명한 대로 확실하게 실행한 다음 `build.gradle` 파일에 다음 라인을 추가했는지 확인합니다. + +``` +implementation 'com.android.installreferrer:installreferrer:1.0' +``` + +그리고 [Proguard 설정](#sdk-proguard)에서 언급한 내용, 특히 이 기능에 필요한 부분이 확실히 추가되었는지도 살펴보세요. + +``` +-keep public class com.android.installreferrer.** { *; } +``` + +이 기능은 **Adjust SDK v4.12.0 버전 이상** 사용 시 지원됩니다. + +#### Google Play Store 인텐트 + +브로드캐스트 리시버로 Google Play Store `INSTALL_REFERRER` 인텐트를 캡쳐해야 합니다. `INSTALL_REFERRER` 수신을 위해 **고유 브로드캐스트 리시버를 사용하고 있지 않다면**, `AndroidManifest.xml` 내 `application` 태그에 다음과 같이 `receiver` 태그를 추가하세요. + +```xml + + + + + +``` + +Adjust는 이 브로드캐스트 리시버를 사용하여 설치 referrer를 검색 후 백엔드에 전달합니다. + +`INSTALL_REFERRER` 인텐트 수신을 위해 다른 브로드캐스트 리시버를 사용 중이라면 [이 지침][referrer]에 따라 브로드캐스트 리시버를 추가하세요. + +### 앱에 SDK 연동 + +먼저 기본 세션 트래킹을 설정합니다. + +#### 기본 설정 + +전역 android [응용 프로그램][android_application] 클래스를 사용하여 SDK를 초기화하는 것이 좋습니다. 앱에 이 클래스가 아직 없는 경우 다음 단계를 수행하십시오. + +- `Application`을 확장하는 클래스를 만듭니다. +- 앱의 `AndroidManifest.xml` 파일을 열고 `` 요소를 찾습니다. +- `android:name` 특성을 추가하고 새 응용 프로그램 클래스 이름으로 설정한 후 이름 앞에 점을 추가합니다. + + 앱 예제에서는 이름이 `GlobalApplication`인 `Application` 클래스를 사용하므로, 매니페스트 파일은 다음과 같이 구성됩니다. + + ```xml + + + ``` + +- `Application` 클래스에서 `onCreate` 메서드를 추가하거나 만들고 다음 코드를 추가하여 Adjust SDK를 초기화합니다. + + ```java + import com.adjust.sdk.Adjust; + import com.adjust.sdk.AdjustConfig; + + public class GlobalApplication extends Application { + @Override + public void onCreate() { + super.onCreate(); + + String appToken = "{YourAppToken}"; + String environment = AdjustConfig.ENVIRONMENT_SANDBOX; + AdjustConfig config = new AdjustConfig(this, appToken, environment); + Adjust.onCreate(config); + } + } + ``` + + `{YourAppToken}`을 앱 토큰으로 대체합니다. 앱 토큰은 [대시보드][adjust.com]에서 찾을 + 수 있습니다. + + 앱을 테스트에 사용할지 아니면 프로덕션에 사용할지에 따라 `environment`를 다음 값 중 하나로 설정해야 합니다. + + ```java + String environment = AdjustConfig.ENVIRONMENT_SANDBOX; + String environment = AdjustConfig.ENVIRONMENT_PRODUCTION; + ``` + +**중요:** 이 값은 앱을 테스트하는 경우에만 `AdjustConfig.ENVIRONMENT_SANDBOX`로 설정해야 합니다. 앱을 게시하기 전에 environment를 `AdjustConfig.ENVIRONMENT_PRODUCTION`으로 설정해야 합니다. 개발 및 테스트를 다시 시작할 경우에는 `AdjustConfig.ENVIRONMENT_SANDBOX`로 다시 설정하십시오. + +이 environment는 실제 트래픽과 테스트 장치의 테스트 트래픽을 구별하기 위해 사용합니다. 이 값을 항상 유의미하게 유지해야 합니다! + +#### 세션 추적 + +**주의:** 이 단계는 **매우 중요**하므로 **앱에 제대로 구현했는지 반드시 확인하세요**. 구현하게 되면 Adjust SDK가 제공하는 세션 추적을 앱에서 올바르게 활성화할 수 있습니다. + +#### API 레벨 14 이상 + +- `ActivityLifecycleCallbacks` 인터페이스를 구현하는 비공개 클래스를 추가합니다. 이 인터페이스에 액세스할 권한이 없다면, 앱의 대상 Android api 레벨이 14보다 낮기 때문입니다. 이 [지침](#session-tracking-api9)에 따라 각 작업을 수동으로 업데이트해야 합니다. 이전에 앱의 각 작업에 대한 `Adjust.onResume` 및 `Adjust.onPause` 호출이 있었을 경우 각 호출을 제거해야 합니다. + +- `onActivityResumed(Activity activity)` 메서드를 편집하고 `Adjust.onResume()`에 호출을 추가합니다. +`onActivityPaused(Activity activity)` 메서드를 편집하고 `Adjust.onPause()`에 호출을 추가합니다. + +- adjust SDK가 구성된 `onCreate()` 메서드를 추가하고 `registerActivityLifecycleCallbacks` 호출을 이전에 만든 `ActivityLifecycleCallbacks` 클래스의 인스턴스와 함께 추가합니다. + + ```java + import com.adjust.sdk.Adjust; + import com.adjust.sdk.AdjustConfig; + + public class GlobalApplication extends Application { + @Override + public void onCreate() { + super.onCreate(); + + String appToken = "{YourAppToken}"; + String environment = AdjustConfig.ENVIRONMENT_SANDBOX; + AdjustConfig config = new AdjustConfig(this, appToken, environment); + Adjust.onCreate(config); + + registerActivityLifecycleCallbacks(new AdjustLifecycleCallbacks()); + + //... + } + + private static final class AdjustLifecycleCallbacks implements ActivityLifecycleCallbacks { + @Override + public void onActivityResumed(Activity activity) { + Adjust.onResume(); + } + + @Override + public void onActivityPaused(Activity activity) { + Adjust.onPause(); + } + + //... + } + } + ``` + +#### API 레벨 9-13 + +앱 `minSdkVersion`이 `9`와 `13` 사이일 경우, 장기 연동 절차를 간소화하기 위해 `14` 이상으로의 업그레이드를 고려해 주십시오. 주요 버전의 최신 시장 점유율을 확인하려면 안드로이드 [대시보드][adjust.com]를 참조하십시오. + +올바른 세션 추적을 위해서는 작업 재개 혹은 중지가 있을 때마다 Adjust SDK 메서드 몇 가지를 호출해야 합니다. 그렇게 하지 않으면 SDK가 세션 시작이나 종결을 놓칠 수 있습니다. 이 작업을 위해서는 **앱 내 각 작업 시 다음 단계를 수행해야 합니다**. + +- 작업 소스 파일을 엽니다. +- 파일 맨 위에 `import` 문을 추가합니다. +- 작업 `onResume` 메소드에서 `Adjust.onResume()` 메소드를 호출합니다. 필요 시에는 이 메소드를 만듭니다. +- 작업 `onPause` 메소드에서 `Adjust.onPause()` 메소드를 호출합니다. 필요 시에는 이 메소드를 만듭니다. + +단계 수행 후 작업이 다음과 같이 보여야 합니다. + +```java + import com.adjust.sdk.Adjust; +// ... +public class YourActivity extends Activity { + protected void onResume() { + super.onResume(); + Adjust.onResume(); + } + protected void onPause() { + super.onPause(); + Adjust.onPause(); + } + // ... +} +``` + +**모든** 앱 액티비티에서 이같은 단계를 반복해야 하므로 신규 액티비티 생성 시에 잊지 마세요. 코딩 유형에 따라 액티비티 전체에서 이를 공통 슈퍼클래스로 설정해야 할 수도 있습니다. + +### Adjust 로그 기록 + +다음 파라미터 중 하나를 사용하여 `AdjustConfig` 인스턴스에서 `setLogLevel`을 호출하면 테스트에 표시되는 로그의 양을 늘리거나 줄일 수 있습니다. + +```java +config.setLogLevel(LogLevel.VERBOSE); // 모든 로그 활성화 +config.setLogLevel(LogLevel.DEBUG); // 더 많은 로그 활성화 +config.setLogLevel(LogLevel.INFO); // 기본값 +config.setLogLevel(LogLevel.WARN); // info 로그 비활성화 +config.setLogLevel(LogLevel.ERROR); // 경고 역시 비활성화 +config.setLogLevel(LogLevel.ASSERT); // 오류 역시 비활성화 +config.setLogLevel(LogLevel.SUPRESS); // 모든 로그 비활성화 +``` + +로그 출력 전부를 비활성화하고 싶다면, 로그 레벨을 supress로 설정하는 동시에 `AdjustConfig` 개체에서 생성자를 사용해야 합니다. 이 개체는 supress 로그를 지원할 지 아닐지를 가리키는 boolean 파라미터를 받습니다. + +```java +String appToken = "{YourAppToken}"; +String environment = AdjustConfig.ENVIRONMENT_SANDBOX; + +AdjustConfig config = new AdjustConfig(this, appToken, environment, true); +config.setLogLevel(LogLevel.SUPRESS); + +Adjust.onCreate(config); +``` + +### 앱 빌드 + +안드로이드 앱을 작성하고 실행합니다. `LogCat` 뷰어에서 `tag:Adjust` 필터를 설정하여 다른 모든 로그를 숨길 수 있습니다. 앱이 시작된 후에 다음 `Install tracked` Adjust 로그가 표시됩니다. + +## 추가 기능 + +Adjust SDK를 프로젝트와 연동한 후에는 다음 기능을 사용할 수 있습니다. + +### 이벤트 추적 + +Adjust를 사용하여 앱의 모든 이벤트를 추적할 수 있습니다. 버튼의 모든 탭을 추적하려면 [대시보드][adjust.com]에서 새 이벤트 토큰을 만들어야 합니다. 예를 들어 이벤트 토큰이 `abc123`일 경우, 버튼의 `onClick` 메서드에 다음 라인을 추가하여 클릭을 추적할 수 있습니다. + +```java +AdjustEvent event = new AdjustEvent("abc123"); +Adjust.trackEvent(event); +``` + +### 매출 추적 + +사용자가 광고를 누르거나 인앱 구매를 할 때 매출이 발생하는 경우, 이벤트를 사용하여 해당 매출을 추적할 수 있습니다. 예를 들어 광고를 한 번 누를 때 0.01 유로의 매출이 발생한다면 매출 이벤트를 다음과 같이 추적할 수 있습니다. + +```java +AdjustEvent event = new AdjustEvent("abc123"); +event.setRevenue(0.01, "EUR"); +Adjust.trackEvent(event); +``` + +물론 콜백 파라미터와도 연결할 수 있습니다. + +통화 토큰을 설정할 경우, Adjust가 자동으로 들어오는 매출을 미리 지정한 보고용 통화로 전환해 줍니다. 통화 전환에 관한 자세한 내용은 [여기][currency-conversion]에서 확인하세요. + +매출 및 이벤트 추적에 관한 자세한 내용은 [이벤트 추적 설명서][event-tracking]에서 확인하세요. + +### 매출 중복 제거 + +거래 ID를 선택 사항으로 추가하여 매출 중복 추적을 피할 수 있습니다. 가장 최근에 사용한 거래 ID(Order ID) 10개를 기억하며, 똑같은 거래 ID(Order ID)로 이루어진 매출 이벤트는 중복 집계하지 않습니다. 인앱 구매 추적 시 특히 유용합니다. 사용 예는 아래에 나와 있습니다. + +인앱 구매를 추적할 경우, 거래가 완료되고 아이템을 구매했을 때만 `trackEvent`를 호출해야 한다는 사실을 기억하십시오. 그렇게 해야 실제로 발생하지 않은 매출을 추적하는 일을 피할 수 있습니다. + +```java +AdjustEvent event = new AdjustEvent("abc123"); +event.setRevenue(0.01, "EUR"); +event.setOrderId("{OrderId}"); +Adjust.trackEvent(event); +``` + +### 인앱 구매 검증 + +Adjust의 서버 측 수신 확인 도구인 구매 검증(Purchase Verification)을 사용하여 앱에서 이루어지는 구매의 유효성을 확인하려면 안드로이드 구매 SDK를 확인하십시오. 자세한 내용은 [여기][android-purchase-verification]에서 확인할 수 있습니다. + +### 콜백 파라미터 + +[대시보드][adjust.com]에서 이벤트 콜백 URL을 등록할 수 있습니다. 이벤트를 추적할 때마다 GET 요청이 해당 URL로 전송됩니다. 이벤트를 추적하기 전에 이벤트 인스턴스에서 `addCallbackParameter`를 호출하여 콜백 파라미터를 해당 이벤트에 추가할 수 있습니다. 그러면 해당 파라미터가 콜백 URL에 추가됩니다. + +예를 들어 URL `http://www.adjust.com/callback`을 등록했다면 이벤트를 다음과 같이 추적할 수 있습니다. + +```java +AdjustEvent event = new AdjustEvent("abc123"); +event.addCallbackParameter("key", "value"); +event.addCallbackParameter("foo", "bar"); +Adjust.trackEvent(event); +``` + +이 경우에는 이벤트를 추적하고 다음 주소로 요청이 전송됩니다. + +``` +http://www.adjust.com/callback?key=value&foo=bar +``` + +파라미터 값으로 사용할 수 있는 `{gps_adid}`와 같은 다양한 자리 표시자(placeholder)를 지원합니다. 그 결과로 생성한 콜백에서 이 자리 표시자는 현재 기기의 Google Play 서비스 ID로 대체됩니다. 사용자 지정 파라미터는 저장되지 않으며 콜백에만 추가됩니다. 이벤트에 대한 콜백을 등록하지 않은 경우 해당 파라미터는 읽을 수 없습니다. + +사용 가능한 값의 전체 목록을 포함한 URL 콜백 사용에 대한 자세한 내용은 [콜백 설명서][callbacks-guide]를 참조하십시오. + +### 파트너 파라미터 + +Adjust 대시보드에서 활성화된 연동에 대해 네트워크 파트너로 전송할 파라미터도 추가할 수 있습니다. + +위에서 설명한 콜백 매개변수의 경우와 비슷하지만, `AdjustEvent` 인스턴스에서 `addPartnerParameter` 메서드를 호출해야 추가할 수 있습니다. + +```java +AdjustEvent event = new AdjustEvent("abc123"); +event.addPartnerParameter("key", "value"); +event.addPartnerParameter("foo", "bar"); +Adjust.trackEvent(event); +``` + +특별 파트너와 그 연동에 대한 자세한 내용은 [특별 파트너 설명서][special-partners]를 참조하십시오. + +### 콜백 ID + +추적하고자 하는 각 이벤트에 개별 스트링 ID를 따로 붙일 수도 있습니다. 나중에 이벤트 성공/실패 콜백에서 해당 ID에 전달하여 이벤트 트래킹의 성공 또는 실패 여부를 추적할 수 있게 해 줍니다. `AdjustEvent` 인스턴스에서 `setCallbackId` 메서드를 호출하여 설정할 수 있습니다: + +```java +AdjustEvent event = new AdjustEvent("abc123"); +event.setCallbackId("Your-Custom-Id"); +Adjust.trackEvent(event); +``` + +### 세션 파라미터 설정 + +일부 파라미터는 Adjust SDK **이벤트** 및 **세션** 발생시마다 전송을 위해 저장합니다. 어느 파라미터든 한 번 저장하면 로컬에 바로 저장되므로 매번 새로 추가할 필요가 없습니다. 같은 파라미터를 두 번 저장해도 효력이 없습니다. + +이 세션 파라미터는 설치 시에도 전송할 수 있도록 Adjust SDK 런칭 전에도 호출할 수 있습니다. 설치 시에 전송하지만 필요한 값은 런칭 후에야 들어갈 수 있게 하고 싶다면 Adjust SDK 런칭 시 [예약 시작](#delay-start)을 걸 수 있습니다. + +### 세션 콜백 파라미터 + +[이벤트](#callback-parameters)에 등록한 콜백 파라미터는 Adjust SDK 전체 이벤트 및 세션 시 전송할 목적으로 저장할 수 있습니다. + +세션 콜백 파라미터는 이벤트 콜백 파라마터와 비슷한 인터페이스를 지녔지만, 이벤트에 키, 값을 추가하는 대신 `Adjust.addSessionCallbackParameter(String key, String value)` 메서드를 호출하여 추가합니다. + +```java +Adjust.addSessionCallbackParameter("foo", "bar"); +``` + +세션 콜백 파라미터는 이벤트에 추가된 콜백 파라미터와 합쳐지며, 이벤트에 추가된 콜백 파라미터가 우선권을 지닙니다. 그러나 세션에서와 같은 키로 이벤트에 콜백 파라미터를 추가한 경우 새로 추가한 콜백 파라미터가 우선권을 가집니다. + +원하는 키를 `Adjust.removeSessionCallbackParameter(String key)` 메서드로 전달하여 특정 세션 콜백 파라미터를 제거할 수 있습니다. + +```java +Adjust.removeSessionCallbackParameter("foo"); +``` + +세션 콜백 파라미터의 키와 값을 전부 없애고 싶다면 `Adjust.resetSessionCallbackParameters()` 메서드로 재설정하면 됩니다. + +```java +Adjust.resetSessionCallbackParameters(); +``` + +### 세션 파트너 파라미터 + +Adjust SDK 내 모든 이벤트 및 세션에서 전송되는 [세션 콜백 파라미터](#session-callback-parameters)가 있는 것처럼, 세션 파트너 파라미터도 있습니다. + +이들 파라미터는 Adjust [대시보드](adjust.com)에서 연동을 활성화한 네트워크 파트너에게 전송할 수 있습니다. + +세션 파트너 파라미터는 이벤트 파트너 파라미터와 인터페이스가 비슷하지만, 이벤트에 키, 값을 추가하는 대신 `Adjust.addSessionPartnerParameter(String key, String value)` 메서드를 호출하여 추가합니다. + +```java +Adjust.addSessionPartnerParameter("foo", "bar"); +``` + +세션 파트너 파라미터는 이벤트에 추가한 파트너 파라미터와 합쳐지며, 이벤트에 추가된 파트너 파라미터가 우선순위를 지닙니다. 그러나 세션에서와 같은 키로 이벤트에 파트너 파라미터를 추가한 경우, 새로 추가한 파트너 파라미터가 우선권을 가집니다. + +원하는 키를 `Adjust.removeSessionPartnerParameter(String key)` 메서드로 전달하여 특정 세션 파트너 파라미터를 제거할 수 있습니다. + +```java +Adjust.removeSessionPartnerParameter("foo"); +``` + +세션 파트너 파라미터의 키와 값을 전부 없애고 싶다면 `Adjust.resetSessionPartnerParameters()` 메서드로 재설정하면 됩니다. + +```java +Adjust.resetSessionPartnerParameters(); +``` + +### 예약 시작 + +Adjust SDK에 예약 시작을 걸면 앱이 고유 식별자 등의 세션 파라미터를 얻어 설치 시에 전송할 시간을 벌 수 있습니다. + +`AdjustConfig` 인스턴스의 `setDelayStart` 메소드에서 예약 시작 시각을 초 단위로 설정하세요. + +```java +adjustConfig.setDelayStart(5.5); +``` + +이 경우 Adjust SDK는 최초 인스톨 세션 및 생성된 이벤트를 5.5초간 기다렸다가 전송합니다. 이 시간이 지난 후, 또는 그 사이에 `Adjust.sendFirstPackages()`을 호출했을 경우 모든 세션 파라미터가 지연된 인스톨 세션 및 이벤트에 추가되며 Adjust SDK는 원래대로 돌아옵니다. + +**Adjust SDK의 최대 지연 예약 시작 시간은 10초입니다**. + +### 어트리뷰션 콜백 + +리스너(listner)를 등록하여 트래커 어트리뷰션 변경 알림을 받을 수 있습니다. 어트리뷰션에서 고려하는 소스가 각각 다르기 때문에 이 정보는 동시간에 제공할 수 없습니다. 가장 간단한 방법은 익명의 단일 리스너를 생성하는 것입니다. + +[해당 어트리뷰션 데이터 정책][attribution-data]을 반드시 고려하세요. + +SDK를 시작하기 전에 `AdjustConfig`로 익명 리스너를 추가합니다. + + +```java +AdjustConfig config = new AdjustConfig(this, appToken, environment); + +config.setOnAttributionChangedListener(new OnAttributionChangedListener() { + @Override + public void onAttributionChanged(AdjustAttribution attribution) { + } +}); + +Adjust.onCreate(config); +``` + +또는 `Application` 클래스에서 `OnAttributionChangedListener` 인터페이스를 실행하여 리스너로 설정해도 됩니다. + +```java +AdjustConfig config = new AdjustConfig(this, appToken, environment); +config.setOnAttributionChangedListener(this); +Adjust.onCreate(config); +``` + +리스너 함수는 SDK가 최종 어트리뷰션 데이터를 접수한 후 호출됩니다. 리스너 함수에서는 `attribution` 파라미터에 액세스할 수 있습니다. 해당 파라미터에 대한 개요는 다음과 같습니다. + +- `string trackerToken` 현재 설치된 트래커 토큰. +- `string trackerName` 현재 설치된 트래커 이름. +- `string network` 현재 설치된 네트워크 그룹화 기준. +- `string campaign` 현재 설치된 캠페인 그룹화 기준. +- `string adgroup` 현재 설치된 광고 그룹 그룹화 기준. +- `string creative` 현재 설치된 크리에이티브 그룹화 기준. +- `string clickLabel` 현재 설치된 클릭 레이블. +- `string adid` Adjust 기기 식별자. + +값을 사용할 수 없을 경우 `null`로 기본 설정됩니다. + +### 세션 및 이벤트 콜백 + +리스너를 등록하여 이벤트나 세션 추적 시 알림을 받을 수 있습니다. 리스너에는 4가지가 있습니다. 이벤트 추적 성공, 이벤트 추적 실패, 세션 추적 성공, 그리고 세션 추적 실패입니다. `AdjustConfig` 개체를 생성한 후 리스너를 원하는 만큼 추가할 수 있습니다. + +```java +AdjustConfig config = new AdjustConfig(this, appToken, environment); + +// Set event success tracking delegate. +config.setOnEventTrackingSucceededListener(new OnEventTrackingSucceededListener() { + @Override + public void onFinishedEventTrackingSucceeded(AdjustEventSuccess eventSuccessResponseData) { + // ... + } +}); + +// Set event failure tracking delegate. +config.setOnEventTrackingFailedListener(new OnEventTrackingFailedListener() { + @Override + public void onFinishedEventTrackingFailed(AdjustEventFailure eventFailureResponseData) { + // ... + } +}); + +// Set session success tracking delegate. +config.setOnSessionTrackingSucceededListener(new OnSessionTrackingSucceededListener() { + @Override + public void onFinishedSessionTrackingSucceeded(AdjustSessionSuccess sessionSuccessResponseData) { + // ... + } +}); + +// Set session failure tracking delegate. +config.setOnSessionTrackingFailedListener(new OnSessionTrackingFailedListener() { + @Override + public void onFinishedSessionTrackingFailed(AdjustSessionFailure sessionFailureResponseData) { + // ... + } +}); + +Adjust.onCreate(config); +``` + +리스너 함수는 SDK가 서버에 패키지 전송을 시도한 후에 호출됩니다. 리스너 함수에서 리스너에 대한 특정 응답 데이터 개체에 액세스할 수 있습니다. 세션 성공 시 응답 데이터 개체 필드 개요는 다음과 같습니다. + +- `String message` 서버에서 전송한 메시지 또는 SDK가 기록한 오류 +- `String timestamp` 서버에서 전송한 데이터의 타임스탬프 +- `String adid` Adjust가 제공하는 고유 기기 식별자 +- `JSONObject jsonResponse` 서버로부터의 응답이 있는 JSON 개체 + +이벤트 응답 데이터 개체 두 가지에는 다음 정보가 포함됩니다. + +- `String eventToken` 추적 패키지가 이벤트인 경우 이벤트 토큰 +- `String callbackId`: 이벤트 객체에서 사용자가 설정하는 콜백 ID. + +값을 사용할 수 없을 경우 `null`로 기본 설정됩니다. + +그리고 이벤트 및 세션 실패 개체에는 다음 정보도 포함됩니다. + +- `boolean willRetry` 나중에 패키지 재전송 시도가 있을 것임을 나타냅니다. + +### 추적 사용 중지 + +`setEnabled`를 `false` 파라미터로 설정한 상태로 호출하면 Adjust SDK에서 현재 장치의 모든 작업 추적을 중지할 수 있습니다. **이 설정은 세션 간에 기억됩니다**. + +```java +Adjust.setEnabled(false); +``` + +`isEnabled` 함수를 호출하여 Adjust SDK가 현재 사용 가능한지 확인할 수 있습니다. 파라미터가 `true`로 설정된 `setEnabled`를 호출하면 Adjust SDK를 언제든 활성화할 수 있습니다. + +### 오프라인 모드 + +Adjust SDK를 오프라인 모드로 전환하여 서버로 전송하는 작업을 일시 중단하고 추적 데이터를 보관하여 나중에 보낼 수 있습니다. 오프라인 모드일 때는 모든 정보가 파일에 저장되므로, 너무 많은 이벤트를 촉발(trigger)하지 않도록 주의하십시오. + +`setOfflineMode`를 `true`로 설정하여 호출하면 오프라인 모드를 활성화할 수 있습니다. + +```java +Adjust.setOfflineMode(true); +``` + +`setOfflineMode`를 `false`로 설정한 상태로 호출하면 오프라인 모드를 비활성화할 수 있습니다. Adjust SDK를 다시 온라인 모드로 전환하면 저장된 정보가 모두 올바른 시간 정보와 함께 Adjust 서버로 전송됩니다. + +추적 사용 중지와 달리 이 설정은 세션 간에 **기억되지 않습니다.** 따라서 앱을 오프라인 모드에서 종료한 경우에도 SDK는 항상 온라인 모드로 시작됩니다. + +### 이벤트 버퍼링 + +앱이 이벤트 추적을 많이 사용하는 경우, 매 분마다 배치(batch) 하나씩만 보내도록 하기 위해 일부 HTTP 요청을 지연시키고자 할 경우가 있을 수 있습니다. `AdjustConfig` 인스턴스로 이벤트 버퍼링을 적용할 수 있습니다. + +```java +AdjustConfig config = new AdjustConfig(this, appToken, environment); +config.setEventBufferingEnabled(true); +Adjust.onCreate(config); +``` + +### GDPR(일반 개인정보 보호법) 상의 잊힐 권리 + +유럽연합(EU) 일반 개인정보 보호법 제 17조에 의거하여, 사용자가 잊힐 권리를 행사하였을 경우 Adjust에 이를 통보할 수 있습니다. 다음 매서드를 호출하면 Adjust SDK는 사용자가 잊힐 권리를 사용하기로 했음을 Adjust 백엔드에 전달합니다: + +```java +Adjust.gdprForgetMe(context); +``` + +이 정보를 받는 즉시 Adjust는 사용자의 데이터를 삭제하며 Adjust SDK는 해당 사용자 추적을 중단합니다. 향후 이 기기로부터 어떤 요청도 Adjust에 전송되지 않습니다. + +### SDK 서명 + +계정 매니저가 Adjust SDK 서명을 활성화해야 합니다. 이 기능을 사용해 보고자 할 경우 Adjust 지원 팀(support@adjust.com)으로 연락해 주십시오. + +SDK 서명이 계정에서 이미 사용 가능 상태로 Adjust 대시보드에서 App Secret에 억세스할 수 있는 상태라면, 아래 매서드를 사용하여 SDK 서명을 앱에 연동하십시오. + +`AdjustConfig` 인스턴스에서 `setAppSecret`를 호출하면 App Secret이 설정됩니다. + +```java +AdjustConfig config = new AdjustConfig(this, appToken, environment); +config.setAppSecret(secretId, info1, info2, info3, info4); +Adjust.onCreate(config); +``` + +### 백그라운드 추적 + +Adjust SDK 기본값 행위는 **앱이 백그라운드에 있을 동안에는 HTTP 요청 전송을 잠시 중지**하는 것입니다. `AdjustConfig` 인스턴스에서 이 설정을 바꿀 수 있습니다. + +```java +AdjustConfig config = new AdjustConfig(this, appToken, environment); +config.setSendInBackground(true); +Adjust.onCreate(config); +``` + +### 기기 ID + +Adjust SDK로 기기 식별자 몇 가지를 획득할 수 있습니다. + +### Google Play 서비스 광고 식별자 + +Google Analytics와 같은 서비스를 사용하려면 중복 보고가 발생하지 않도록 기기 ID와 클라이언트 ID를 조정해야 합니다. + +Google 광고 ID가 필요한 경우 제한 사항으로 인해 백그라운드 스레드에서만 ID를 읽을 수 있습니다. `getGoogleAdId` 함수를 컨텍스트 및 `OnDeviceIdsRead` 인스턴스와 함께 호출하면 상황에 관계 없이 작동합니다. + +```java +Adjust.getGoogleAdId(this, new OnDeviceIdsRead() { + @Override + public void onGoogleAdIdRead(String googleAdId) { + // ... + } +}); +``` + +`OnDeviceIdsRead` 인스턴스의 `onGoogleAdIdRead` 메서드를 통해 Google 광고 ID에 `googleAdId` 변수로 액세스할 수 있습니다. + +### Amazon 광고 식별자 + +Amazon 광고 ID를 얻으려면 `Adjust` 인스턴스에서 다음 메서드를 호출하면 됩니다. + +```java +String amazonAdId = Adjust.getAmazonAdId(context); +``` + +### Adjust 기기 식별자 + +Adjust 백엔드는 앱을 인스톨한 장치에서 고유한 **Adjust 기기 식별자** (**adid**)를 생성합니다. 이 식별자를 얻으려면 `Adjust` 인스턴스에서 다음 메서드를 호출하면 됩니다. + +```java +String adid = Adjust.getAdid(); +``` + +**주의**: 이 호출은 Adjust SDK v4.11.0 이상 버전에서만 수행할 수 있습니다. + +**주의**: **adid** 관련 정보는 Adjust 백엔드가 앱 설치를 추적한 후에만 얻을 수 있습니다. 그 순간부터 Adjust SDK는 기기 **adid** 정보를 갖게 되며 이 메서드로 억세스할 수 있습니다. 따라서 SDK가 초기화되고 앱 설치 추적이 성공적으로 이루어지기 전에는 **adid** 억세스가 **불가능합니다**. + +### 사용자 어트리뷰션 + +[어트리뷰션 콜백 섹션](#attribution-callback)에서 설명한 바와 같이, 이 콜백은 변동이 있을 때마다 새로운 어트리뷰션 관련 정보를 전달할 목적으로 촉발됩니다. 사용자의 현재 어트리뷰션 값 관련 정보를 언제든 억세스하고 싶다면, `Adjust` 인스턴스의 다음 메서드를 호출하면 됩니다. + +```java +AdjustAttribution attribution = Adjust.getAttribution(); +``` + +**주의**: 이 호출은 Adjust SDK v4.11.0 이상 버전에서만 수행할 수 있습니다. + +**주의**: 사용자의 현재 어트리뷰션 관련 정보는 Adjust 백엔드가 앱 인스톨을 추적하여 최초 어트리뷰션 콜백이 촉발된 후에만 얻을 수 있습니다. 그 순간부터 Adjus SDK는 사용자 어트리뷰션 정보를 갖게 되며 이 메서드로 억세스할 수 있습니다. 따라서 SDK가 초기화되고 최초 어트리뷰션 콜백이 촉발되기 전에는 사용자 어트리뷰션 값 억세스가 **불가능합니다**. + +### 푸시 토큰 + +푸시 토큰은 Audience Builder와 클라이언트 콜백에 사용되며, 앱 제거(uninstall) 및 재설치 (reinstall) 트래킹을 위해 필수입니다. + +푸시 알림 토큰을 전송하려면 앱에서 토큰을 받거나 값 변화가 있을 때마다 아래와 같이 Adjust에 대한 호출을 추가하세요. + +```java +Adjust.setPushToken(pushNotificationsToken, context); +``` +`context`를 추가하여 업데이트된 이 서명을 사용하여 SDK가 더욱 다양한 상황에서 푸시 토큰을 전송할 수 있으므로, 가능하면 이를 사용할 것을 권장합니다. + +동일한 메서드에 대해 이전 버전의 아래 서명도 여전히 지원합니다. + +```java +Adjust.setPushToken(pushNotificationsToken); +``` + +### 사전 설치 트래커 + +Adjust SDK를 사용하여 앱이 사전 설치된 장치를 지닌 사용자를 인식하고 싶다면 다음 절차를 따르세요. + +- [대시보드][adjust.com]에 새 트래커를 생성합니다. + +- 앱 델리게이트를 열고 `AdjustConfig` 인스턴스의 기본값 트래커를 다음과 같이 설정합니다. + +```java +AdjustConfig config = new AdjustConfig(this, appToken, environment); +config.setDefaultTracker("{TrackerToken}"); +Adjust.onCreate(config); +``` + +`{TrackerToken}`을 2에서 생성한 트래커 토큰으로 대체합니다. 대시보드에서는 (`http://app.adjust.com/`을 포함하는) 트래커 URL을 표시한다는 사실을 명심하세요. 소스코드에서는 전체 URL을 표시할 수 없으며 6자로 이루어진 토큰만을 명시해야 합니다. + +- 앱 빌드를 실행하세요. LogCat에서 다음 라인을 볼 수 있을 것입니다. + +``` +Default tracker: 'abc123' +``` + +### 딥링크 + +URL에서 앱으로 딥링크를 거는 옵션이 있는 Adjust 트래커 URL을 사용하고 있다면, 딥링크 URL과 그 내용 관련 정보를 얻을 가능성이 있습니다. 해당 URL 클릭 시 사용자가 이미 앱을 설치한 상태(기본 딥링크)일 수도, 앱을 설치하지 않은 상태(지연된 딥링크)일 수도 있습니다. 기본 딥링크 상황에서 안드로이드는 딥링크 내용에 관한 정보 인출을 기본 지원합니다. 안드로이드는 지연된 딥링크를 기본 지원하지 않지만, Adjust SDK는 지연된 딥링크 정보를 인출하는 메커니즘을 제공합니다. + +#### 기본 딥링크 + +사용자가 앱을 설치하고 `deep_link` 파라미터가 들어간 Adjust 트래커 URL을 클릭 시 런칭하도록 하려 할 경우, 앱에 딥링크를 활성화해야 합니다. 이는 원하는 **고유 스킴명 (scheme name)** 을 선택하여 사용자가 링크를 클릭하고 앱이 열릴 때 런칭할 작업을 배정하여 이루어집니다. 이 과정은 `AndroidManifest.xml`에 설정되어 있습니다. `intent-filter` 섹션을 매니페스트 파일 내 원하는 작업 정의에 추가하고 `android:scheme` 어트리뷰션값을 원하는 스킴명과 함께 배정하면 됩니다. + +```xml + + + + + + + + + + + + + + +``` + +이 설정이 끝나고 트래커 URL 클릭 시 앱이 런칭되도록 하려면, 배정한 스킴명을 Adjust 트래커 URL의 `deep_link` 파라미터에 사용해야 합니다. 딥링크에 정보가 추가되지 않은 트래커 URL은 아래와 같이 보일 것입니다. + +``` +https://app.adjust.com/abc123?deep_link=adjustExample%3A%2F%2F +``` + +URL 내 `deep_link` 파라미터 값은 **URL 인코딩이 되어야 한다**는 사실을 명심하세요. + +앱이 위와 같이 설정된 상황에서 이 트래커 URL을 클릭하면 `MainActivity` 인텐트와 함께 앱이 런칭됩니다. `MainActivity` 클래스에서 `deep_link` 파라미터 내용이 자동으로 제공됩니다. URL에서 인코딩이 된 상태라 해도 내용이 전달된 후에는 **인코딩이 이루어지지 않습니다**. + +`AndroidManifest.xml` 파일 내 `android:launchMode` 작업 설정에 따라 `deep_link` 파라미터 내용 정보가 작업 파일 내 적절한 위치로 전달됩니다. `android:launchMode` 어트리뷰션 값에 대한 더 자세한 정보는 [안드로이드 문서](https://developer.android.com/guide/topics/manifest/activity-element.html)에서 확인하세요. + +딥링크 내용 정보는 `Intent` 개체를 통해 원하는 작업 내 `onCreate` 메서드 또는 `onNewIntent` 메서드로 전달됩니다. 앱을 런칭하고 두 개 메서드 중 하나가 촉발되면 실제 딥링크가 클릭한 URL 내 `deep_link` 파라미터로 전달되게 할 수 있습니다. 이렇게 하면 이 정보를 사용하여 앱에서 추가적 로직을 수행할 수 있게 됩니다. + +딥링크 내용은 이들 두 개 메서드에서 다음과 같이 추출할 수 있습니다. + +```java +@Override +protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_main); + + Intent intent = getIntent(); + Uri data = intent.getData(); + // data.toString() -> This is your deep_link parameter value. +} +``` + +```java +@Override +protected void onNewIntent(Intent intent) { + super.onNewIntent(intent); + + Uri data = intent.getData(); + // data.toString() -> This is your deep_link parameter value. +} +``` + +#### 지연된 딥링크 (Deferred deep linking) + +지연된 딥링크는 사용자가 `deep_link` 파라미터가 들어 있는 Adjust 트래커 URL을 클릭했으나, 그 시점에 장치에 앱을 설치하지 않은 경우 발생합니다. 클릭 후 사용자는 Play Store로 재이동하여 앱을 다운로드하게 됩니다. 링크를 처음 연 후 `deep_link` 파라미터 내용이 앱으로 전달됩니다. + + 딥링크에서 `deep_link` 파라미터 내용 정보를 얻으려면 `AdjustConfig` 개체에 리스너를 설치해야 합니다. Adjust SDK가 백엔드에서 딥링크 정보를 얻으면 리스너가 촉발됩니다. + +```java +AdjustConfig config = new AdjustConfig(this, appToken, environment); + +// Evaluate the deeplink to be launched. +config.setOnDeeplinkResponseListener(new OnDeeplinkResponseListener() { + @Override + public boolean launchReceivedDeeplink(Uri deeplink) { + // ... + if (shouldAdjustSdkLaunchTheDeeplink(deeplink)) { + return true; + } else { + return false; + } + } +}); + +Adjust.onCreate(config); +``` + +Adjust SDK가 백엔드에서 딥링크 내용 정보를 수신하면 그 내용이 리스너에 전달되며 `boolean` 리턴값을 요청합니다. 리턴값은 (기본 딥링크에서와 마찬가지로) Adjust SDK가 스킴명을 배정한 작업을 딥링크에서 런칭할 것인지 여부를 표시합니다. + +리턴값을 `true`로 설정하면 작업이 런칭되어 [기본 딥링크](#deeplinking-standard)에서 설명한 것과 같은 결과를 구현합니다. SDK가 작업을 런칭하기를 원하지 않는다면, 리스너에서 `false`를 리턴하여 딥링크 내용을 토대로 앱에서 다음 작업을 어떻게 실행할 지 스스로 정할 수 있습니다. + +#### 딥링크를 통한 리어트리뷰션 + +Adjust는 딥링크를 사용하여 광고 캠페인 리인게이지먼트(re-engagement)를 수행할 수 있게 해줍니다. 이에 대한 자세한 정보는 [관련 문서](https://docs.adjust.com/en/deeplinking/#manually-appending-attribution-data-to-a-deep-link)를 참조하세요. + +이 기능을 사용 중이라면, 사용자를 올바로 리어트리뷰트하기 위해 앱에서 호출을 한 가지 더 수행해야 합니다. + +앱에서 딥링크 내용을 수신했다면, `Adjust.appWillOpenUrl(Uri, Context)` 메서드 호출을 추가하세요. 이 호출이 이루어지면 Adjust SDK는 딥링크 내에 새로운 어트리뷰션 정보가 있는지 확인하고, 새 정보가 있으면 Adjust 백엔드로 송신합니다. 딥링크 정보가 담긴 Adjust 트래커 URL을 클릭한 사용자를 리어트리뷰트해야 할 경우 앱에서 해당 사용자의 새 어트리뷰션 정보로 [어트리뷰션 콜백](#attribution-callback)이 촉발되는 것을 확인할 수 있습니다. + +`Adjust.appWillOpenUrl(Uri, Context)` 호출은 다음과 같이 이루어집니다. + +```java +@Override +protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_main); + + Intent intent = getIntent(); + Uri data = intent.getData(); + Adjust.appWillOpenUrl(data, getApplicationContext()); +} +``` + +```java +@Override +protected void onNewIntent(Intent intent) { + super.onNewIntent(intent); + + Uri data = intent.getData(); + Adjust.appWillOpenUrl(data, getApplicationContext()); +} +``` +참고 : Adjust.appWillOpenUrl (Uri) 메소드는 Android SDK v4.14.0 기준으로 사용되지 않게 되었습니다. 따라서 Adjust.appWillOpenUrl (Uri, Context) 메서드를 사용하시기 바랍니다. + +## 문제 해결 + +### "Session failed (Ignoring too frequent session. ...)" 오류가 나타납니다. + +이 오류는 일반적으로 설치를 테스트할 때 발생합니다. 앱을 제거하고 다시 설치해도 새 설치를 촉발할 수 없습니다. 서버에서는 SDK가 로컬에서 집계한 세션 데이터를 유실했다고 판단하며 서버에 제공된 장치 관련 정보에 따라 오류 메시지를 무시합니다. + +이 동작은 테스트 중 불편을 초래할 수도 있지만, sandbox 동작이 프로덕션 환경과 최대한 일치하도록 하기 위해 필요합니다. + +기기의 세션 데이터를 Adjust 서버에서 재설정할 수 있습니다. 로그에서 다음 오류 메시지를 확인합니다. + +``` +Session failed (Ignoring too frequent session. Last session: YYYY-MM-DDTHH:mm:ss, this session: YYYY-MM-DDTHH:mm:ss, interval: XXs, min interval: 20m) (app_token: {yourAppToken}, adid: {adidValue}) +``` + +아래에 `{yourAppToken}` 및 `{adidValue}/{gps_adidValue}/{androidIDValue}` 값을 입력하고 다음 링크 중 하나를 엽니다. + +``` +http://app.adjust.com/forget_device?app_token={yourAppToken}&adid={adidValue} +``` + +``` +http://app.adjust.com/forget_device?app_token={yourAppToken}&gps_adid={gps_adidValue} +``` + +``` +http://app.adjust.com/forget_device?app_token={yourAppToken}&android_id={androidIDValue} +``` + +기기가 메모리에서 삭제되면 링크에서 `Forgot device`만 반환됩니다. 기기가 이미 메모리에서 삭제되었거나 값이 올바르지 않으면 `Device not found` 메시지가 반환됩니다. + +### 브로드캐스트 리시버가 설치 referrer를 제대로 캡처하고 있나요? + +[설명서](#broadcast-receiver) 지침을 따랐다면 브로드캐스트 리시버는 설치 referrer를 Adjust SDK와 Adjust 서버로 보내도록 구성됩니다. + +테스트 설치 참조 페이지를 수동으로 촉발시켜 이 구성을 테스트할 수 있습니다. `com.your.appid`를 앱 ID로 대체하고 Android Studio와 함께 제공되는 [adb](http://developer.android.com/tools/help/adb.html) 도구를 사용하여 다음 명령을 실행합니다. + +``` +adb shell am broadcast -a com.android.vending.INSTALL_REFERRER -n com.your.appid/com.adjust.sdk.AdjustReferrerReceiver --es "referrer" "adjust_reftag%3Dabc1234%26tracking_id%3D123456789%26utm_source%3Dnetwork%26utm_medium%3Dbanner%26utm_campaign%3Dcampaign" +``` + +이미 다른 브로드캐스트 리시버를 `INSTALL_REFERRER` 인텐트 수신용으로 사용 중이면서 이 [설명서][referrer]의 지침을 따른 경우, `com.adjust.sdk.AdjustReferrerReceiver`를 브로드캐스트 리시버로 대체합니다. + +`-n com.your.appid/com.adjust.sdk.AdjustReferrerReceiver` 파라미터를 제거하여 기기의 모든 앱에서 `INSTALL_REFERRER` 인텐트를 수신하도록 할 수도 있습니다. + +로그 레벨을 `verbose`로 설정하면 referrer 확인 시 로그가 보일 것입니다. + +``` +V/Adjust: Reading query string (adjust_reftag=abc1234&tracking_id=123456789&utm_source=network&utm_medium=banner&utm_campaign=campaign) from reftag +``` + +그리고 SDK 패키지 처리기에 추가된 다음 클릭 패키지를 읽어서 로그를 볼 수 있습니다. + +``` +V/Adjust: Path: /sdk_click + ClientSdk: android4.6.0 + Parameters: + app_token abc123abc123 + click_time yyyy-MM-dd'T'HH:mm:ss.SSS'Z'Z + created_at yyyy-MM-dd'T'HH:mm:ss.SSS'Z'Z + environment sandbox + gps_adid 12345678-0abc-de12-3456-7890abcdef12 + needs_attribution_data 1 + referrer adjust_reftag=abc1234&tracking_id=123456789&utm_source=network&utm_medium=banner&utm_campaign=campaign + reftag abc1234 + source reftag + tracking_enabled 1 +``` + +앱 시작 전에 이 테스트를 실시하면 전송할 패키지가 보이지 않습니다. 패키지는 앱이 시작된 후에 전송됩니다. + +**중요:** 이 기능 테스트에 `adb`툴 사용을 권장하지 않는다는 사실에 주의해 주십시오. (여러 개의 파라미터를 `&`로 구분해 놓은 경우) 참조자 내용 전체를 `adb`에서 테스트한다면, 브로드캐스트 수신자에 들어가게 하기 위해 해당 내용을 인코딩해야 합니다. 인코딩을 하지 않으면 `adb`에서 첫 번째 `&` 다음에 나오는 참조자 내용을 잘라 버리기 때문에 브로드캐스트 수신자에 올바르지 않은 내용이 전달됩니다. + +인코딩되지 않은 참조자 값이 앱에서 어떻게 수신되는지 보려면 아래 Adjust의 예제 앱을 참조하십시오. 전달되는 내용 중 `MainActivity.java` 파일에 있는 `onFireIntentClick` 메서드 내 인텐트로 촉발되는 부분을 다르게 써 본 후 그 결과를 확인할 수 있습니다. + +```java +public void onFireIntentClick(View v) { + Intent intent = new Intent("com.android.vending.INSTALL_REFERRER"); + intent.setPackage("com.adjust.examples"); + intent.putExtra("referrer", "utm_source=test&utm_medium=test&utm_term=test&utm_content=test&utm_campaign=test"); + sendBroadcast(intent); +} +``` + +`putExtra` 메서드에서 두 번째 파라미터를 필요한 대로 바꿔 쓰시면 됩니다. + +### 응용 프로그램 런칭 시 이벤트를 촉발할 수 있나요? + +직관적으로 생각하는 것과는 다를 수 있습니다. 전역 `Application` 클래스의 `onCreate` 메서드는 응용 프로그램이 시작될 때뿐만 아니라, 시스템 또는 응용 프로그램 이벤트가 앱에 의해 캡처될 때도 호출됩니다. + +Adjust SDK는 이 때 초기화가 준비되지만 실제로 시작되지는 않습니다. 작업 시작 시, 즉 사용자가 실제로 앱을 시작할 경우에만 실제로 시작됩니다. + +따라서 이 때 이벤트를 촉발해도 원하는 작업이 수행되지 않습니다. 이런 호출은 사용자가 앱을 시작하지 않은 경우에도 외부 요인에 따라 결정되는 시간에 맞춰 Adjust SDK를 시작하고 이벤트를 보냅니다. + +따라서 응용 프로그램 시작 시 이벤트를 촉발시키면 추적하는 설치 및 세션 수가 부정확해집니다. + +설치 후에 이벤트를 촉발시키려면 [어트리뷰션 콜백](#attribution-callback)을 사용하십시오. + +앱이 시작될 때 이벤트를 촉발시키려면 시작된 작업의 `onCreate` 메서드를 사용하십시오. + +[dashboard]: http://adjust.com +[adjust.com]: http://adjust.com +[en-readme]: ../../README.md +[zh-readme]: ../chinese/README.md +[ja-readme]: ../japanese/README.md +[ko-readme]: ../korean/README.md + +[maven]: http://maven.org +[example-java]: ../../Adjust/example-app-java +[example-tv]: ../../Adjust/example-app-tv +[releases]: https://github.com/adjust/adjust_android_sdk/releases +[referrer]: https://github.com/adjust/sdks/blob/master/doc/ko-sdks/referrer.md +[google_ad_id]: https://support.google.com/googleplay/android-developer/answer/6048248?hl=en +[event-tracking]: https://docs.adjust.com/ko/event-tracking +[callbacks-guide]: https://docs.adjust.com/ko/callbacks +[application_name]: http://developer.android.com/guide/topics/manifest/application-element.html#nm +[special-partners]: https://docs.adjust.com/ko/special-partners +[attribution-data]: https://github.com/adjust/sdks/blob/master/doc/attribution-data.md +[android-dashboard]: http://developer.android.com/about/dashboards/index.html +[currency-conversion]: https://docs.adjust.com/ko/event-tracking/#part-7 +[android_application]: http://developer.android.com/reference/android/app/Application.html +[android-launch-modes]: https://developer.android.com/guide/topics/manifest/activity-element.html +[google_play_services]: http://developer.android.com/google/play-services/setup.html +[activity_resume_pause]: doc/activity_resume_pause.md +[reattribution-with-deeplinks]: https://docs.adjust.com/ko/deeplinking/#part-6-1 +[android-purchase-verification]: https://github.com/adjust/android_purchase_sdk/tree/master/doc/korean + +## 라이선스 + +adjust SDK는 MIT 라이선스에 따라 사용이 허가되었습니다. + +Copyright (c) 2012-2018 adjust GmbH, +http://www.adjust.com + +이로써 본 소프트웨어와 관련 문서 파일(이하 "소프트웨어")의 복사본을 받는 사람에게는 아래 조건에 따라 소프트웨어를 제한 없이 다룰 수 있는 권한이 무료로 부여됩니다. 이 권한에는 소프트웨어를 사용, 복사, 수정, 병합, 출판, 배포 및/또는 판매하거나 2차 사용권을 부여할 권리와 소프트웨어를 제공 받은 사람이 소프트웨어를 사용, 복사, 수정, 병합, 출판, 배포 및/또는 판매하거나 2차 사용권을 부여하는 것을 허가할 수 있는 권리가 제한 없이 포함됩니다. + +위 저작권 고지문과 본 권한 고지문은 소프트웨어의 모든 복사본이나 주요 부분에 포함되어야 합니다. + +소프트웨어는 상품성, 특정 용도에 대한 적합성 및 비침해에 대한 보증 등을 비롯한 어떤 종류의 명시적이거나 암묵적인 보증 없이 "있는 그대로" 제공됩니다. 어떤 경우에도 저작자나 저작권 보유자는 소프트웨어와 소프트웨어의 사용 또는 기타 취급에서 비롯되거나 그에 기인하거나 그와 관련하여 발생하는 계약 이행 또는 불법 행위 등에 관한 배상 청구, 피해 또는 기타 채무에 대해 책임지지 않습니다. +--END-- diff --git a/doc/korean/fb_pixel_ko.md b/doc/korean/fb_pixel_ko.md new file mode 100644 index 000000000..8e8259e21 --- /dev/null +++ b/doc/korean/fb_pixel_ko.md @@ -0,0 +1,115 @@ +## Facebook 픽셀 연동 + +[Facebook 픽셀](https://www.facebook.com/business/help/952192354843755)은 Facebook의 웹 전용 애널리틱스 도구입니다. 종전에는 Facebook SDK으로 앱 WebView에서 픽셀 이벤트를 추적할 수 없었으나 [Facebook SDK](https://developers.facebook.com/docs/analytics) v4.34 버전 출시와 더불어 이제 가능해졌으며, [하이브리드 모바일 앱 이벤트](https://developers.facebook.com/docs/app-events/hybrid-app-events)를 사용하여 Facebook 픽셀 이벤트를 Facebook 앱 이벤트로 전환할 수 있습니다. + +또한 Facebook SDK에 연동하지 않고도 Adjust SDK로 Facebook 픽셀을 사용할 수 있습니다. + +## Facebook 연동 + +### 앱 예제 + +[`AdjustExample-FbPixel` 디렉토리][example-fbpixel]에서 Adjust WebView SDK를 사용하지 않고 Facebook 픽셀 이벤트를 추적하는 방법을 설명하는 앱 예제를 찾아볼 수 있습니다. + +### Facebook App ID + +Facebook SDK 연동을 하지 않아도 됩니다. 그러나 Adjust SDK가 Facebook 픽셀을 연동하도록 하기 위해서는 Facebook SDK에서와 동일한 몇 단계의 절차를 밟아야 합니다. + +[Facebook 안드로이드 SDK 지침](https://developers.facebook.com/docs/android/getting-started/#app_id)에 설명한 대로 Facebook App ID를 앱에 추가해야 합니다. 위 지침에 설명한 단계를 그대로 따르면 되며, 이용자의 편의를 위해 아래에 그대로 복사해 놓았습니다. + +- `strings.xml` 파일을 엽니다. 경로 예: `/app/src/main/res/values/strings.xml`. +- 이름이 `facebook_app_id`, 사용하는 Facebook App ID를 값으로 하는 새로운 라인을 추가합니다. +- `AndroidManifest.xml`을 엽니다. +- `uses-permission` 엘리먼트를 선언에 추가합니다. + + ```xml + + ``` + +- `meta-data` 엘리먼트를 `application` 엘리먼트에 추가합니다. + +```xml + + ... + + ... + + ``` + +### Facebook 픽셀 환경설정 + +픽셀 연동에 대한 Facebook 지침을 따르면 됩니다. 자바스크립트 코드는 다음과 같이 보일 것입니다. + +```js + + +... + +``` + +이제 [하이브리드 모바일 앱 이벤트 지침](https://developers.facebook.com/docs/app-events/hybrid-app-events) 내 `Update Your Pixel` 섹션에서 설명한 대로 Facebook 픽셀 코드를 다음과 같이 업데이트합니다. + +```js +fbq('init', ); +fbq('set', 'mobileBridge', , ); +``` + +**주의**: `'init'`를 먼저 호출하고 바로 그 다음에 `'set'` 메서드를 호출하는 게 **대단히 중요**함을 명심해 주십시오. (위에 나온 것처럼) Facebook에서 제공하여 사용 대상 HTML 웹 페이지에 붙이는 스크립트 라인에는, `'init'` 호출 바로 다음에 페이지 보기 이벤트에 사용하는 `'track'` 메서드가 들어 있습니다. 이 페이지 보기 이벤트를 올바로 추적하려면 그 사이에 반드시 `'set'` 메서드를 호출해야 합니다! + +## Adjust 연동 + +### Facebook SDK 자바스크립트 인터페이스 등록 + +[안드로이드 WebView SDK](web_views.md) 앱 연동 지침을 따르면 됩니다. 등록을 진행하고 Adjust 브릿지 기본값 인스턴스를 얻을 섹션은 아래를 참조하십시오. + +```java +AdjustBridge.registerAndGetInstance(getApplication(), webview); +``` + +리턴 인스턴스를 `adjustBridgeInstance`와 같은 이름으로 저장한 다음 다음 라인을 추가합니다. + +```java +adjustBridgeInstance.registerFacebookSDKJSInterface(); +``` + +### 이벤트 이름 환경설정 + +Adjust 웹 브릿지 SDK는 Facebook 픽셀 이벤트를 Adjust 이벤트로 전환시켜 줍니다. + +따라서 Facebook 픽셀을 특정한 Adjust 이벤트에 배치(매핑, mapping)하거나, Facebook 픽셀 환경설정에서 복사해 와서 붙이는 `fbq('track', 'PageView');` 등의 Facebook 픽셀 이벤트 추적을 Adjust SDK를 사용하여 시작하기 **전에** Adjust 이벤트 토큰의 기본값을 설정해야 합니다. + +Facebook 픽셀 이벤트와 Adjust 이벤트를 매핑하려면 Adjust SDK를 초기화하기 전에 `adjustConfig` 인스턴스에서 `addFbPixelMapping(fbEventNameKey, adjEventTokenValue)` 메서드를 호출합니다. 매핑이 이루어진 예는 아래와 같습니다. + +```js +adjustConfig.addFbPixelMapping('fb_mobile_search', adjustEventTokenForSearch); +adjustConfig.addFbPixelMapping('fb_mobile_purchase', adjustEventTokenForPurchase); +``` + +위에 보이는 매핑의 예시는 Facebook 이벤트 중 `fbq('track', 'Search', ...);` 및 `fbq('track', 'Purchase', ...);`를 각각 추적하는 경우에 해당함을 유의해 주십시오. 아쉽게도 Adjust는 자바스크립트에서 추적하는 이벤트 이름과 Facebook SDK에 사용하는 이벤트 이름 전체의 매핑 구조에는 접근할 수 없습니다. + +사용자에게 도움을 드리고자 Adjust가 지금까지 찾아 낸 이벤트 이름 정보를 다음과 같이 정리했습니다. + +| 픽셀 이벤트 이름 | 해당하는 Facebook 앱 이벤트 이름 +| ---------------- | ------------------------------------- +| ViewContent | fb_mobile_content_view +| Search | fb_mobile_search +| AddToCart | fb_mobile_add_to_cart +| AddToWishlist | fb_mobile_add_to_wishlist +| InitiateCheckout | fb_mobile_initiated_checkout +| AddPaymentInfo | fb_mobile_add_payment_info +| Purchase | fb_mobile_purchase +| CompleteRegistration | fb_mobile_complete_registration + +위 목록은 완전하지 않을 수 있으며, Facebook이 현재 목록에 새 항목을 추가하거나 목록을 업데이트할 가능성도 있습니다. 테스트하는 중에는 다음과 같은 Adjust 경고 로그를 확인하십시오. + +``` +There is not a default event token configured or a mapping found for event named: 'fb_mobile_search'. It won't be tracked as an adjust event +``` + +매핑 환경설정을 하지 않았다면 그냥 Adjust 이벤트 기본값을 사용할 수도 있습니다. Adjust SDK를 초기화하기 전에 `adjustConfig.setFbPixelDefaultEventToken(defaultEventToken);` 메서드를 호출하기만 하면 됩니다. + +[example-fbpixel]: ../../Adjust/example-fbpixel