diff --git a/StatisticReporter/src/main/java/com/gamedog/statisticreporter/adjust/AdjustManager.kt b/StatisticReporter/src/main/java/com/gamedog/statisticreporter/adjust/AdjustManager.kt index d4b8a99..e64aa03 100644 --- a/StatisticReporter/src/main/java/com/gamedog/statisticreporter/adjust/AdjustManager.kt +++ b/StatisticReporter/src/main/java/com/gamedog/statisticreporter/adjust/AdjustManager.kt @@ -6,6 +6,7 @@ import android.os.HandlerThread import android.text.TextUtils import com.adjust.sdk.Adjust import com.adjust.sdk.AdjustAdRevenue +import com.adjust.sdk.AdjustAttribution import com.adjust.sdk.AdjustConfig import com.adjust.sdk.AdjustEvent import com.adjust.sdk.LogLevel @@ -15,12 +16,16 @@ import com.adjust.sdk.OnSessionTrackingFailedListener import com.adjust.sdk.OnSessionTrackingSucceededListener import com.ama.core.architecture.BaseApp import com.ama.core.architecture.util.AndroidUtil +import com.ama.core.architecture.util.DateUtil import com.ama.core.architecture.util.SpUtil +import com.gamedog.statisticreporter.StatisticLogger import com.gamedog.statisticreporter.StatisticUtil import com.gamedog.statisticreporter.adjust.AdjustManager.Companion.USER_TYPE_BUY import com.remax.base.ads.AdRevenueData import com.remax.base.ads.AdRevenueManager import com.remax.base.ads.AdRevenueReporter +import com.remax.base.controller.UserChannelController +import com.remax.base.report.DataReportManager import com.remax.bill.BuildConfig @@ -44,6 +49,9 @@ class AdjustManager private constructor() { const val USER_TYPE_BUY = 2 } + + private var initStartTime: Long = 0 + private var mAdjustInitStartMs: Long = 0 private val mAppContext = BaseApp.appContext() private val mSpHelper = SpHelper() @@ -82,12 +90,29 @@ class AdjustManager private constructor() { }) + fun initSdk(appToken: String) { + initStartTime = DateUtil.getCurTimeMs() + + CommonParamsManager.initLoginParams() + StatisticLogger.d("登录参数初始化完成 - login_day: ${CommonParamsManager.loginDay ?: ""}, is_new: ${CommonParamsManager.isNew ?: ""}") + + /// 先设置登录参数到DataReportManager + val loginParams = CommonParamsManager.getAllCommonParams() + val userParams = CommonParamsManager.getUserCommonParams() + DataReportManager.setCommonParams(loginParams) + DataReportManager.setUserParams(userParams) + StatisticLogger.d("登录参数已设置到DataReportManager: $loginParams") + // 初始化埋点 + DataReportManager.reportData("adjust_init", mapOf()) + + val isDebug = BuildConfig.DEBUG val environment = if (/*isDebug*/false) AdjustConfig.ENVIRONMENT_SANDBOX else AdjustConfig.ENVIRONMENT_PRODUCTION val config = AdjustConfig(mAppContext, appToken, environment).apply { setLogLevel(if (isDebug) LogLevel.VERBOSE else LogLevel.WARN) enableSendingInBackground() + enableCostDataInAttribution() /*enableCoppaCompliance() enableCostDataInAttribution()*/ @@ -100,7 +125,7 @@ class AdjustManager private constructor() { } onAttributionChangedListener = OnAttributionChangedListener { attribution-> - val test = 111 + handleAttribution(attribution) } } StatisticUtil.reportEvents(StatisticUtil.KEY_adjust_init) @@ -114,6 +139,10 @@ class AdjustManager private constructor() { if (!mSpHelper.hasIdentityUserType()) { mChecker.startPolling() + } else { + Adjust.getAttribution { + handleAttribution(it) + } } @@ -124,7 +153,84 @@ class AdjustManager private constructor() { } ) } + private fun handleAttribution(attr: AdjustAttribution) { + // 设置公共参数,并限制长度 + CommonParamsManager.adNetwork = (attr.network ?: "").take(10) + CommonParamsManager.campaign = (attr.campaign ?: "").take(20) + CommonParamsManager.adgroup = (attr.adgroup ?: "").take(10) + CommonParamsManager.creative = (attr.creative ?: "").take(20) + StatisticLogger.d("公共参数设置完成 - ad_network: ${CommonParamsManager.adNetwork}, campaign: ${CommonParamsManager.campaign}, adgroup: ${CommonParamsManager.adgroup}, creative: ${CommonParamsManager.creative}") + + // 将公共参数设置到DataReportManager + val commonParams = CommonParamsManager.getAllCommonParams() + val userParams = CommonParamsManager.getUserCommonParams() + DataReportManager.setCommonParams(commonParams) + DataReportManager.setUserParams(userParams) + StatisticLogger.d("公共参数已设置到DataReportManager: $commonParams") + + // 计算从初始化开始到归因回调的总耗时(秒数,向上取整) + val totalDurationSeconds = kotlin.math.ceil((System.currentTimeMillis() - initStartTime) / 1000.0).toInt() + StatisticLogger.d("Adjust初始化到归因回调总耗时: ${totalDurationSeconds}秒") + DataReportManager.reportData("adjust_get_success", mapOf("pass_time" to totalDurationSeconds)) + + // 设置当前用户渠道类型 + val userChannelType = if (StatisticLogger.isLogEnabled()) { + // 内部版本强制设置为买量类型 + StatisticLogger.d("内部版本强制设置为买量类型") + UserChannelController.UserChannelType.PAID + } else { + determineUserChannelType(attr) + } + StatisticLogger.d("根据归因数据判断用户渠道类型: $userChannelType") + + // 设置用户渠道类型 + val success = UserChannelController.setChannel(userChannelType) + if (success) { + StatisticLogger.i("用户渠道类型设置成功: $userChannelType") + } else { + StatisticLogger.w("用户渠道类型已经设置过,无法修改") + } + } + + private fun determineUserChannelType(attribution: AdjustAttribution): UserChannelController.UserChannelType { + // 获取归因数据的关键字段 + val network = attribution.network?.lowercase() + val trackerName = attribution.trackerName?.lowercase() + val campaign = attribution.campaign?.lowercase() + + StatisticLogger.d("归因数据 - network: $network, trackerName: $trackerName, campaign: $campaign") + + // 判断是否为自然渠道的条件 + val isOrganic = when { + // 1. Organic - 有机渠道 + network == "organic" -> { + StatisticLogger.d("检测到Organic渠道") + true + } + // 2. Untrusted Devices - 不可信设备 + network == "untrusted devices" -> { + StatisticLogger.d("检测到Untrusted Devices渠道") + true + } + // 3. Google Organic Search - Google有机搜索 + network == "google organic search" -> { + StatisticLogger.d("检测到Google Organic Search渠道") + true + } + // 4. 其他情况都认为是买量渠道 + else -> { + StatisticLogger.d("检测到买量渠道 - network: $network") + false + } + } + + return if (isOrganic) { + UserChannelController.UserChannelType.NATURAL + } else { + UserChannelController.UserChannelType.PAID + } + } private fun reportAdRevenueInfo(revenueValue: AdRevenueData) { val adjustAdRevenue = AdjustAdRevenue(getRandomFixSourceStr()).apply { diff --git a/StatisticReporter/src/main/java/com/gamedog/statisticreporter/adjust/CommonParamsManager.kt b/StatisticReporter/src/main/java/com/gamedog/statisticreporter/adjust/CommonParamsManager.kt new file mode 100644 index 0000000..fb186f6 --- /dev/null +++ b/StatisticReporter/src/main/java/com/gamedog/statisticreporter/adjust/CommonParamsManager.kt @@ -0,0 +1,145 @@ +package com.gamedog.statisticreporter.adjust + +import com.remax.base.ext.KvStringDelegate +import java.util.Calendar +import java.util.Locale + +/** + * 公共参数管理器 + * 管理数据上报的公共参数,使用KvStringDelegate持久化 + */ +object CommonParamsManager { + + private const val KEY_AD_NETWORK = "common_param_ad_network" + private const val KEY_CAMPAIGN = "common_param_campaign" + private const val KEY_ADGROUP = "common_param_adgroup" + private const val KEY_CREATIVE = "common_param_creative" + private const val KEY_LOGIN_DAY = "common_param_login_day" + private const val KEY_IS_NEW = "common_param_is_new" + private const val KEY_FIRST_INSTALL_DATE = "first_install_date" + + // 使用KvStringDelegate进行持久化存储,默认值为空字符串 + var adNetwork by KvStringDelegate(KEY_AD_NETWORK, "") + var campaign by KvStringDelegate(KEY_CAMPAIGN, "") + var adgroup by KvStringDelegate(KEY_ADGROUP, "") + var creative by KvStringDelegate(KEY_CREATIVE, "") + var loginDay by KvStringDelegate(KEY_LOGIN_DAY, "") + var isNew by KvStringDelegate(KEY_IS_NEW, "") + private var firstInstallDate by KvStringDelegate(KEY_FIRST_INSTALL_DATE, "") + + + /** + * 初始化登录相关参数 + * 在应用启动时调用,自动计算login_day和is_new + */ + fun initLoginParams() { + val currentDate = getCurrentDateString() + val storedFirstInstallDate = firstInstallDate ?: "" + + if (storedFirstInstallDate.isEmpty()) { + // 首次安装,记录安装日期 + firstInstallDate = currentDate + loginDay = "0" + isNew = "Y" + } else { + // 非首次安装,计算登录天数 + val daysDiff = calculateDaysDifference(storedFirstInstallDate, currentDate) + loginDay = daysDiff.toString() + isNew = if (daysDiff == 0) "Y" else "N" + } + } + + /** + * 获取当前日期字符串(格式:yyyy-MM-dd) + * @return 当前日期字符串 + */ + private fun getCurrentDateString(): String { + val calendar = Calendar.getInstance() + val year = calendar.get(Calendar.YEAR) + val month = calendar.get(Calendar.MONTH) + 1 + val day = calendar.get(Calendar.DAY_OF_MONTH) + return String.format(Locale.ENGLISH, "%04d-%02d-%02d", year, month, day) + } + + /** + * 计算两个日期之间的天数差 + * @param startDate 开始日期(格式:yyyy-MM-dd) + * @param endDate 结束日期(格式:yyyy-MM-dd) + * @return 天数差 + */ + private fun calculateDaysDifference(startDate: String, endDate: String): Int { + return try { + val startCalendar = parseDateToCalendar(startDate) + val endCalendar = parseDateToCalendar(endDate) + + if (startCalendar == null || endCalendar == null) { + return 0 + } + + // 重置时间部分,只比较日期 + startCalendar.set(Calendar.HOUR_OF_DAY, 0) + startCalendar.set(Calendar.MINUTE, 0) + startCalendar.set(Calendar.SECOND, 0) + startCalendar.set(Calendar.MILLISECOND, 0) + + endCalendar.set(Calendar.HOUR_OF_DAY, 0) + endCalendar.set(Calendar.MINUTE, 0) + endCalendar.set(Calendar.SECOND, 0) + endCalendar.set(Calendar.MILLISECOND, 0) + + // 计算天数差 + val diffInMillis = endCalendar.timeInMillis - startCalendar.timeInMillis + (diffInMillis / (24 * 60 * 60 * 1000)).toInt() + } catch (e: Exception) { + 0 + } + } + + /** + * 将日期字符串解析为Calendar对象 + * @param dateString 日期字符串(格式:yyyy-MM-dd) + * @return Calendar对象,解析失败返回null + */ + private fun parseDateToCalendar(dateString: String): Calendar? { + return try { + val parts = dateString.split("-") + if (parts.size != 3) return null + + val year = parts[0].toInt() + val month = parts[1].toInt() - 1 // Calendar的月份从0开始 + val day = parts[2].toInt() + + val calendar = Calendar.getInstance() + calendar.set(year, month, day) + calendar + } catch (e: Exception) { + null + } + } + + /** + * 获取所有公共参数 + * @return 公共参数Map + */ + fun getAllCommonParams(): Map { + return mapOf( + "ad_network" to (adNetwork ?: ""), + "campaign" to (campaign ?: ""), + "adgroup" to (adgroup ?: ""), + "creative" to (creative ?: ""), + "login_day" to (loginDay ?: ""), + "is_new" to (isNew ?: "") + ) + } + + fun getUserCommonParams(): Map { + return mapOf( + "user_ad_network" to (adNetwork ?: ""), + "user_campaign" to (campaign ?: ""), + "user_adgroup" to (adgroup ?: ""), + "user_creative" to (creative ?: ""), + "user_login_day" to (loginDay ?: ""), + "user_is_new" to (isNew ?: "") + ) + } +} diff --git a/notification/src/main/java/com/remax/notification/newUtil/events/PowerConnectionReceiver.kt b/notification/src/main/java/com/remax/notification/newUtil/events/PowerConnectionReceiver.kt index d55bb7d..3f78766 100644 --- a/notification/src/main/java/com/remax/notification/newUtil/events/PowerConnectionReceiver.kt +++ b/notification/src/main/java/com/remax/notification/newUtil/events/PowerConnectionReceiver.kt @@ -13,10 +13,10 @@ class PowerConnectionReceiver : BroadcastReceiver() { NotificationTimingController.getInstance() .triggerNotificationIfAllowed(NotificationCheckController.NotificationType.CHARGE) } - Intent.ACTION_POWER_DISCONNECTED -> { + /*Intent.ACTION_POWER_DISCONNECTED -> { NotificationTimingController.getInstance() .triggerNotificationIfAllowed(NotificationCheckController.NotificationType.CHARGE) - } + }*/ } } } \ No newline at end of file