Skip to content

Commit

Permalink
Merge pull request #1 from tiktok/v1.3.1
Browse files Browse the repository at this point in the history
Feature: SDK supports automatic IAP tracking&Standardized Event Repor…
  • Loading branch information
chaofeng01 authored May 10, 2024
2 parents ff4fe1f + c008468 commit 714388f
Show file tree
Hide file tree
Showing 60 changed files with 2,448 additions and 433 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,4 @@ The TikTok business SDK takes the automatically/manually logged events, and repo
* We may use this app event data for subsequent retargeting and dynamic product ads like we do with app event data forwarded from measurement partners.
* In the near future, we will introduce our own attribution solutions and input into our optimization models based on these app events.

** For details including integration instructions, see the [TikTok Business Mobile SDK Documentation](https://ads.tiktok.com/marketing_api/docs?rid=rscv11ob9m9&id=1683138352999426). **
** For details including integration instructions, see the [TikTok Business Mobile SDK Documentation](https://ads.tiktok.com/marketing_api/docs?rid=rscv11ob9m9&id=1683138352999426). **
7 changes: 2 additions & 5 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,8 @@ ext {
versionName = VERSION_NAME

minSdkVersion = 17
targetSdkVersion = 31
compileSdkVersion = 31

sourceCompatibilityVersion = JavaVersion.VERSION_1_8
targetCompatibilityVersion = JavaVersion.VERSION_1_8
targetSdkVersion = 33
compileSdkVersion = 33
}

task clean(type: Delete) {
Expand Down
6 changes: 1 addition & 5 deletions business-core/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,6 @@ android {
buildConfig = true
}

compileOptions {
sourceCompatibility rootProject.ext.sourceCompatibilityVersion
targetCompatibility rootProject.ext.targetCompatibilityVersion
}

lintOptions {
textReport true
textOutput 'stdout'
Expand All @@ -52,6 +47,7 @@ dependencies {
implementation 'androidx.lifecycle:lifecycle-process:2.3.1'
implementation 'androidx.lifecycle:lifecycle-common-java8:2.3.1'
implementation 'commons-codec:commons-codec:1.11'
compileOnly('com.android.billingclient:billing:6.0.0')

testImplementation 'junit:junit:4.13.2'

Expand Down
1 change: 1 addition & 0 deletions business-core/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
package="com.tiktok">

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="com.google.android.gms.permission.AD_ID" />

<application
android:networkSecurityConfig="@xml/network_security_config">
Expand Down
102 changes: 88 additions & 14 deletions business-core/src/main/java/com/tiktok/TikTokBusinessSdk.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,20 @@

package com.tiktok;

import static com.tiktok.util.TTConst.TTSDK_EXCEPTION_CRASH;

import android.app.Application;
import android.content.Context;
import android.text.TextUtils;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import com.tiktok.appevents.*;
import com.tiktok.appevents.base.EventName;
import com.tiktok.appevents.base.TTBaseEvent;
import com.tiktok.iap.TTInAppPurchaseWrapper;
import com.tiktok.util.RegexUtil;
import com.tiktok.util.TTConst;
import com.tiktok.util.TTLogger;

Expand Down Expand Up @@ -99,14 +106,18 @@ private TikTokBusinessSdk(@NonNull TTConfig ttConfig) {
logger = new TTLogger(TAG, logLevel);

/* no app id exception */
if (ttConfig.appId == null) {
throw new IllegalArgumentException("app id not set");
if (TextUtils.isEmpty(ttConfig.appId) || !RegexUtil.validateAppId(ttConfig.appId)) {
ttConfig.appId = "";
logger.warn("Invalid App Id!");
}

if (ttConfig.ttAppId == null) {
logger.warn("ttAppId not set, but its usage is encouraged");
if (ttConfig.ttAppId == null || !RegexUtil.validateTTAppId(ttConfig.ttAppId)) {
ttConfig.ttAppId = "";
ttConfig.ttAppIds = new String[]{""};
ttConfig.ttFirstAppId = new BigInteger("0");
logger.warn("Invalid TikTok App Id!");
}

logger.info("appId: %s, TTAppId: %s, autoIapTrack: %s", ttConfig.appId, ttConfig.ttAppId, ttConfig.autoIapTrack);
config = ttConfig;
networkSwitch = new AtomicBoolean(ttConfig.autoStart);
sdkDebugModeSwitch.set(ttConfig.debugModeSwitch);
Expand Down Expand Up @@ -136,7 +147,7 @@ public static synchronized void initializeSdk(TTConfig ttConfig) {
@Override
public void uncaughtException(@NonNull Thread thread, @NonNull Throwable throwable) {
if (TTCrashHandler.isTTSDKRelatedException(throwable)) {
TTCrashHandler.handleCrash(TAG, throwable);
TTCrashHandler.handleCrash(TAG, throwable, TTSDK_EXCEPTION_CRASH);
}
if (getCrashListener() != null) {
getCrashListener().onCrash(thread, throwable);
Expand All @@ -155,6 +166,9 @@ public void uncaughtException(@NonNull Thread thread, @NonNull Throwable throwab
// the appEventLogger instance will be the main interface to track events
appEventLogger = new TTAppEventLogger(ttConfig.autoEvent,ttConfig.disabledEvents,
ttConfig.flushTime, ttConfig.disableMetrics, initTimeMS);
if (ttConfig.autoIapTrack) {
TTInAppPurchaseWrapper.registerIapTrack();
}

try {
long endTimeMS = System.currentTimeMillis();
Expand Down Expand Up @@ -258,10 +272,27 @@ void onNetworkChange(int toBeSentRequests, int successfulRequest, int failedRequ
* A shortcut method for the situations where the events do not require a property body.
* see more {@link TikTokBusinessSdk#trackEvent(String, JSONObject)}
*/
@Deprecated
public static void trackEvent(String event) {
appEventLogger.track(event, null);
}

@Deprecated
public static void trackEvent(String event, String eventId) {
appEventLogger.track(event, null, eventId);
}

public static void trackTTEvent(TTBaseEvent event) {
appEventLogger.track(event.eventName, event.properties, event.eventId);
}

public static void trackTTEvent(EventName event) {
appEventLogger.track(event.toString(), null);
}

public static void trackTTEvent(EventName event, String eventId) {
appEventLogger.track(event.toString(), null, eventId);
}

/**
* <pre>
Expand All @@ -286,8 +317,13 @@ public static void trackEvent(String event) {
*
* @param event event name
*/
@Deprecated
public static void trackEvent(String event, @Nullable JSONObject props) {
appEventLogger.track(event, props);
appEventLogger.track(event, props, "");
}
@Deprecated
public static void trackEvent(String event, @Nullable JSONObject props, String eventId) {
appEventLogger.track(event, props, eventId);
}

/**
Expand Down Expand Up @@ -363,10 +399,18 @@ public static String getAppId() {
/**
* returns api_id
*/
public static BigInteger getTTAppId() {
public static String getTTAppId() {
return config.ttAppId;
}

public static String[] getTTAppIds() {
return config.ttAppIds;
}

public static BigInteger getFirstTTAppIds() {
return config.ttFirstAppId;
}

/**
* if only appId is provided, the json schema would be like
* {
Expand Down Expand Up @@ -416,7 +460,7 @@ public static BigInteger getTTAppId() {

public static boolean onlyAppIdProvided() {
if(config.appId == null){
throw new IllegalStateException("AppId should be checked before, this path should not be accessed");
logger.warn("AppId should be checked before, this path should not be accessed");
}
return config.ttAppId == null;
}
Expand Down Expand Up @@ -504,7 +548,10 @@ public static synchronized void identify(String externalId,
@Nullable String phoneNumber,
@Nullable String email) {
long initTimeMS = System.currentTimeMillis();
appEventLogger.identify(externalId, externalUserName, phoneNumber, email);
boolean isReset = appEventLogger.identify(externalId, externalUserName, phoneNumber, email);
if (!isReset) {
return;
}
try {
long endTimeMS = System.currentTimeMillis();
JSONObject meta = TTUtil.getMetaWithTS(initTimeMS)
Expand Down Expand Up @@ -566,9 +613,11 @@ public static class TTConfig {
/* application context */
private final Application application;
/* api_id for api calls, App ID in EM */
private String appId;
private String appId = "";
/* tt_app_id for api calls, TikTok App ID from EM */
private BigInteger ttAppId;
private String ttAppId = "";
private String[] ttAppIds = {""};
private BigInteger ttFirstAppId=new BigInteger("0");
/* flush time interval in seconds, default 15, 0 -> disabled */
private int flushTime = 15;
// /* Access-Token for api calls */
Expand All @@ -590,6 +639,8 @@ public static class TTConfig {
/* open LDU mode*/
private boolean lduModeSwitch = false;

private boolean autoIapTrack = false;


/**
* Read configs from <meta-data>
Expand All @@ -614,15 +665,22 @@ public TTConfig setLogLevel(LogLevel ll) {
* set app id
*/
public TTConfig setTTAppId(String ttAppId) {
this.ttAppId = new BigInteger(ttAppId);
this.ttAppId = ttAppId;
try {
ttAppIds = (ttAppId.replace(" ", "")).split(",");
ttFirstAppId = new BigInteger(ttAppIds[0]);
} catch (Throwable throwable) {
}
return this;
}

/**
* set app id
*/
public TTConfig setAppId(String apiId) {
this.appId = apiId;
if (!TextUtils.isEmpty(apiId)) {
this.appId = apiId;
}
return this;
}

Expand Down Expand Up @@ -706,6 +764,18 @@ public TTConfig enableLimitedDataUse() {
lduModeSwitch = true;
return this;
}

/**
* to open the Auto In App Purchase Track
*/
public TTConfig enableAutoIapTrack() {
autoIapTrack = true;
return this;
}

public boolean isAutoIapTrack() {
return autoIapTrack;
}
}

/**
Expand All @@ -725,6 +795,10 @@ public boolean log() {
}
}

public static boolean enableAutoIapTrack() {
return config != null && config.isAutoIapTrack();
}

public interface CrashListener {
void onCrash(Thread thread, Throwable ex);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,13 @@

package com.tiktok.appevents;

import static com.tiktok.TikTokBusinessSdk.enableAutoIapTrack;

import androidx.annotation.NonNull;
import androidx.lifecycle.LifecycleOwner;

import com.tiktok.TikTokBusinessSdk;
import com.tiktok.iap.TTInAppPurchaseWrapper;
import com.tiktok.util.TTLogger;
import com.tiktok.util.TTUtil;
import org.json.JSONObject;
Expand Down Expand Up @@ -47,6 +50,9 @@ public void onPause(@NonNull LifecycleOwner owner) {
bgStart = System.currentTimeMillis();
appEventLogger.stopScheduler();
isPaused = true;
if(enableAutoIapTrack()) {
TTInAppPurchaseWrapper.startBillingClient();
}
}

@Override
Expand Down
37 changes: 32 additions & 5 deletions business-core/src/main/java/com/tiktok/appevents/TTAppEvent.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@
import com.tiktok.util.TTLogger;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.atomic.AtomicLong;

public class TTAppEvent implements Serializable {
Expand All @@ -20,29 +22,36 @@ public static enum TTAppEventType{
identify
}

private static final long serialVersionUID = 1L;

private static final long serialVersionUID = 2L;
private List<String> tiktokAppIds = new ArrayList<>();
private TTAppEventType type;
private String eventName;
private Date timeStamp;
private String propertiesJson;
private String eventId;
private static AtomicLong counter = new AtomicLong(new Date().getTime() + 0L);
private Long uniqueId;
private TTUserInfo userInfo;
private static String TAG = TTAppEventsQueue.class.getCanonicalName();
private static TTLogger logger = new TTLogger(TAG, TikTokBusinessSdk.getLogLevel());

TTAppEvent(TTAppEventType type, String eventName, String propertiesJson) {
this(type, eventName, new Date(), propertiesJson);
TTAppEvent(TTAppEventType type, String eventName, String propertiesJson, String eventId, String[] ttAppId) {
this(type, eventName, new Date(), propertiesJson, eventId, ttAppId);
}

TTAppEvent(TTAppEventType type, String eventName, Date timeStamp, String propertiesJson) {
TTAppEvent(TTAppEventType type, String eventName, Date timeStamp, String propertiesJson, String eventId, String[] ttAppId) {
this.type = type;
this.eventName = eventName;
this.timeStamp = timeStamp;
this.propertiesJson = propertiesJson;
this.eventId = eventId;
this.uniqueId = TTAppEvent.counter.getAndIncrement();
this.userInfo = TTUserInfo.sharedInstance.clone();
if (ttAppId != null && ttAppId.length > 0) {
for (int i = 0; i < ttAppId.length; i++) {
tiktokAppIds.add(ttAppId[i]);
}
}
}

public TTUserInfo getUserInfo() {
Expand All @@ -69,6 +78,14 @@ public void setTimeStamp(Date timeStamp) {
this.timeStamp = timeStamp;
}

public String getEventId() {
return eventId;
}

public void setEventId(String eventId) {
this.eventId = eventId;
}

public String getPropertiesJson() {
return propertiesJson;
}
Expand All @@ -81,13 +98,23 @@ public Long getUniqueId() {
return this.uniqueId;
}

public List<String> getTiktokAppIds() {
return tiktokAppIds;
}

public void setTiktokAppIds(List<String> tiktokAppIds) {
this.tiktokAppIds = tiktokAppIds;
}

@Override
public String toString() {
return "TTAppEvent{" +
"eventName='" + eventName + '\'' +
", timeStamp=" + timeStamp +
", propertiesJson='" + propertiesJson + '\'' +
", eventId='" + eventId + '\'' +
", uniqueId=" + uniqueId +
", tiktokAppIds=" + tiktokAppIds +
'}';
}
}
Loading

0 comments on commit 714388f

Please sign in to comment.