Commit 9d0c1a11 authored by wanglei's avatar wanglei

[商业化]优化上报的卡顿问题

parent b869a12c
......@@ -14,7 +14,7 @@ import org.json.JSONObject
*/
object SolarEngineEvent {
fun eventSolar(ad: Any?, valueMicros: Long) = Thread {
fun eventSolar(ad: Any?, valueMicros: Long) {
val json = JSONObject()
//变现平台
......@@ -72,20 +72,21 @@ object SolarEngineEvent {
}
try {
val seAdImpEventModel = SEAdImpEventModel(
adNetworkPlatform,
mediationPlatform,
adType,
adNetworkAppID,
adNetworkADID,
ecpm,
currencyType,
true,
json
)
SolarEngineManager.getInstance().trackAdImpression(seAdImpEventModel)
} catch (e: Exception) {
//
}
val seAdImpEventModel = SEAdImpEventModel(
adNetworkPlatform,
mediationPlatform,
adType,
adNetworkAppID,
adNetworkADID,
ecpm,
currencyType,
true,
json
)
SolarEngineManager.getInstance().trackAdImpression(seAdImpEventModel)
}.start()
}
}
\ No newline at end of file
......@@ -25,6 +25,11 @@ import com.google.android.gms.ads.rewarded.RewardedAd
import com.google.firebase.analytics.FirebaseAnalytics
import com.google.firebase.analytics.ktx.analytics
import com.google.firebase.ktx.Firebase
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.MainScope
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.launch
import org.json.JSONObject
import java.math.BigDecimal
import java.util.Currency
......@@ -34,16 +39,17 @@ class AdmobEvent : AdEvent {
override val TAG: String = "AdmobEvent"
val scope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
constructor(adUnit: String, from: String) : super() {
this.adUnit = adUnit
this.from = from
}
fun pullAd(
responseInfo: ResponseInfo?,
error: LoadAdError? = null,
) {
) = MainScope().launch(Dispatchers.IO) {
var key = "ad_pull"
val obj = JSONObject()
obj.put("req_id", reqId)
......@@ -72,11 +78,10 @@ class AdmobEvent : AdEvent {
key = "ad_pull_error"
}
EventUtils.event(key, ext = obj)
LogEx.logDebug(TAG, "ad_pull obj=$obj")
LogEx.logDebug(TAG, "$key obj=$obj")
}
fun clickAd(responseInfo: ResponseInfo?) {
fun clickAd(responseInfo: ResponseInfo?) = scope.launch {
val response = responseInfo?.adapterResponses?.getOrNull(0)
val obj = JSONObject()
......@@ -100,7 +105,7 @@ class AdmobEvent : AdEvent {
}
}
fun showAd(responseInfo: ResponseInfo?, activity: Activity? = null) {
fun showAd(responseInfo: ResponseInfo?, activity: Activity? = null) = scope.launch {
val response = responseInfo?.adapterResponses?.getOrNull(0)
val obj = JSONObject()
obj.put("req_id", reqId)
......@@ -123,37 +128,59 @@ class AdmobEvent : AdEvent {
LogEx.logDebug(TAG, "ad_show $obj")
}
class EventOnPaidEventListener(private val ad: Any?) : OnPaidEventListener {
inner class EventOnPaidEventListener(private val ad: Any?) : OnPaidEventListener {
override fun onPaidEvent(adValue: AdValue) {
ad ?: return
SolarEngineEvent.eventSolar(ad, adValue.valueMicros)
onPaidEvent2(ad, adValue)
}
fun onPaidEvent2(ad: Any?, adValue: AdValue) {
scope.launch {
try {
val flag = eventAdRatio()
if (flag) {
SolarEngineEvent.eventSolar(ad, adValue.valueMicros)
eventFireBase(adValue)
eventEvent(adValue)
}
} catch (e: Exception) {
EventUtils.event("onPaidEvent_Error")
}
}
}
fun eventAdRatio(): Boolean {
val adRatio = AdConfigBean.adsConfigBean.adRatio
val random = Random.Default.nextInt(1, 100)
if (random > adRatio) {
taichiSharedPreferencesEditor.putFloat("TaichiTroasCache", 0f)
taichiSharedPreferencesEditor.commit()
EventUtils.event("ad_price_limit")
return
return false
}
return true
}
/**
* 上报给firebase
*/
fun eventFireBase(adValue: AdValue) {
val valueMicros = adValue.valueMicros
val currencyCode = adValue.currencyCode
val precision = adValue.precisionType
val currentImpressionRevenue = adValue.valueMicros.toDouble() / 1000000.0
val fbLogger = AppEventsLogger.newLogger(MyApplication.appContext)
fbLogger.logPurchase(BigDecimal.valueOf(valueMicros / 1000000), Currency.getInstance(currencyCode))
//sp里面的价格值
val previousTaichiTroasCache = taichiPref.getFloat("TaichiTroasCache", 0f)
val obj = JSONObject()
obj.put("valueMicros", valueMicros)
obj.put("currencyCode", currencyCode)
obj.put("precision", precision)
//当前缓存加个值
val currentTaichiTroasCache = (previousTaichiTroasCache + currentImpressionRevenue).toFloat()
Firebase.analytics.logEvent("ad_price", Bundle().apply {
putDouble("valueMicros", valueMicros / 1000000.0)
})
//价值上报阀值
val taichiAdValue = AdConfigBean.adsConfigBean.taichiAdValue / 100f
val params = Bundle()
val currentImpressionRevenue = adValue.valueMicros.toDouble() / 1000000.0
params.putDouble(FirebaseAnalytics.Param.VALUE, currentImpressionRevenue)
params.putString(FirebaseAnalytics.Param.CURRENCY, "USD")
LogEx.logDebug("EventOnPaidEventListener", "precisionType=${adValue.precisionType}")
......@@ -165,31 +192,51 @@ class AdmobEvent : AdEvent {
else -> "Invalid"
}
params.putString("precisionType", precisionType)
Firebase.analytics.logEvent("Ad_Impression_Revenue", params)
val previousTaichiTroasCache = taichiPref.getFloat("TaichiTroasCache", 0f)
val currentTaichiTroasCache = (previousTaichiTroasCache +
currentImpressionRevenue).toFloat()
val taichiAdValue = AdConfigBean.adsConfigBean.taichiAdValue / 100f
val fbLogger = AppEventsLogger.newLogger(MyApplication.appContext)
//上报
fbLogger.logPurchase(BigDecimal.valueOf(currentImpressionRevenue), Currency.getInstance(currencyCode))
//上报ad_price
Firebase.analytics.logEvent("ad_price", Bundle().apply {
putDouble("valueMicros", valueMicros / 1000000.0)
})
//上报Ad_Impression_Revenue
Firebase.analytics.logEvent("Ad_Impression_Revenue", params)
//上报Total_Ads_Revenue_001
if (currentTaichiTroasCache >= taichiAdValue) {//如果超过0.01就触发一次tROAS taichi事件
val roasbundle = Bundle()
roasbundle.putDouble(
FirebaseAnalytics.Param.VALUE,
currentTaichiTroasCache.toDouble()
)
roasbundle.putDouble(FirebaseAnalytics.Param.VALUE, currentTaichiTroasCache.toDouble())
roasbundle.putString(FirebaseAnalytics.Param.CURRENCY, "USD")
Firebase.analytics.logEvent("Total_Ads_Revenue_001", roasbundle)
taichiSharedPreferencesEditor.putFloat("TaichiTroasCache", 0f)//重新清零,开始计算
val logger = AppEventsLogger.newLogger(MyApplication.appContext)
val parameters = Bundle()
parameters.putString(AppEventsConstants.EVENT_PARAM_CURRENCY, "USD")
logger.logEvent("ad_value", currentTaichiTroasCache.toDouble(), parameters)
fbLogger.logEvent("ad_value", currentTaichiTroasCache.toDouble(), parameters)
} else {
taichiSharedPreferencesEditor.putFloat("TaichiTroasCache", currentTaichiTroasCache)
}
taichiSharedPreferencesEditor.commit()
}
/**
* 上报给服务器
*/
fun eventEvent(adValue: AdValue) {
val valueMicros = adValue.valueMicros
val currencyCode = adValue.currencyCode
val precision = adValue.precisionType
val obj = JSONObject()
obj.put("valueMicros", valueMicros)
obj.put("currencyCode", currencyCode)
obj.put("precision", precision)
var key = "ad_price"
when (ad) {
......@@ -313,10 +360,11 @@ class AdmobEvent : AdEvent {
}
}
EventUtils.event(key, ext = obj)
}
}
fun adShowError(adError: AdError) {
fun adShowError(adError: AdError) = scope.launch {
val obj = JSONObject()
obj.put("req_id", reqId)
obj.put("reason", adError.message)
......
......@@ -4,66 +4,33 @@ import android.os.Build
import com.base.appzxhy.BuildConfig
import com.base.appzxhy.SpConstObject.ifAgreePrivacy
import com.base.appzxhy.GlobalConfig
import com.base.appzxhy.business.helper.ReportUtils.doPost
import com.base.appzxhy.bean.config.ConfigBean
import com.base.appzxhy.utils.AppPreferences
import com.base.appzxhy.utils.LogEx
import org.json.JSONException
import okhttp3.Call
import okhttp3.Callback
import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.RequestBody.Companion.toRequestBody
import okhttp3.Response
import okhttp3.logging.HttpLoggingInterceptor
import org.json.JSONObject
import java.io.IOException
import java.util.TimeZone
object EventUtils {
private val TAG = "EventUtils"
fun event(
key: String,
value: String? = null,
ext: JSONObject? = null,
) {
private val TAG = "EventUtils"
if (!ifAgreePrivacy) {
return
private val client = OkHttpClient.Builder().apply {
if (BuildConfig.DEBUG) {
addInterceptor(HttpLoggingInterceptor().apply {
level = HttpLoggingInterceptor.Level.BODY
})
}
}.build()
Thread {
var paramJson: String? = ""
try {
val pkg = GlobalConfig.PACKAGE_NAME
val s = JSONObject()
.put("action", key)
.put("value", value)
.put("ext", ext)
val s2 = JSONObject()
.put("${pkg}_3", AppPreferences.getInstance().getString("Equipment", ""))
.put("${pkg}_4", AppPreferences.getInstance().getString("Manufacturer", ""))
.put("${pkg}_5", Build.VERSION.SDK_INT)
.put("${pkg}_9", AppPreferences.getInstance().getString("uuid", ""))
.put("${pkg}_10", AppPreferences.getInstance().getString("gid", ""))
.put("${pkg}_13", "android")
.put("${pkg}_15", "google")
.put("${pkg}_14", BuildConfig.VERSION_CODE)
.put("${pkg}_8", BuildConfig.VERSION_NAME)
.put("${pkg}_24", BuildConfig.BUILD_TYPE)
.put("${pkg}_34", TimeZone.getDefault().getID())
val data = JSONObject()
.put("data", s)
.put("bp", s2)
.toString()
LogEx.logDebug(TAG, "uuid=${AppPreferences.getInstance().getString("uuid", "")}")
LogEx.logDebug(TAG, "gid=${AppPreferences.getInstance().getString("gid", "")}")
paramJson = AESHelper.encrypt(data)
} catch (e: JSONException) {
paramJson = ""
}
LogEx.logDebug(TAG, "url=$url")
doPost(
url,
HashMap(),
paramJson
)
}.start()
}
private val url by lazy {
val pkg = GlobalConfig.PACKAGE_NAME
......@@ -76,4 +43,64 @@ object EventUtils {
url.toString()
}
// 获取配置参数
fun getConfigParams(): JSONObject {
val packageName = GlobalConfig.PACKAGE_NAME
val jsonObject = JSONObject()
jsonObject.put("${packageName}_4", Build.MANUFACTURER) // 手机厂商
jsonObject.put("${packageName}_5", Build.VERSION.SDK_INT) // android系统版本号
jsonObject.put("${packageName}_8", BuildConfig.VERSION_NAME) // APP版本号,如:1.1.2
jsonObject.put("${packageName}_9", AppPreferences.getInstance().getString("uuid", "")) // Android id
jsonObject.put("${packageName}_10", AppPreferences.getInstance().getString("gid", "")) // Google advertiser id
jsonObject.put("${packageName}_13", "android") // platform 默认android
jsonObject.put("${packageName}_14", BuildConfig.VERSION_CODE)// android版本,如:13
jsonObject.put("${packageName}_15", "google") // 渠道标识
jsonObject.put("${packageName}_24", BuildConfig.BUILD_TYPE) // 环境
val timeZone: TimeZone = TimeZone.getDefault()
jsonObject.put("${packageName}_34", timeZone.id) // 手机本地时区,值如下格式:America/New_York
return jsonObject
}
fun event(
key: String,
value: String? = null,
ext: JSONObject? = null,
) {
if (BuildConfig.DEBUG || !ifAgreePrivacy || ConfigBean.configBean.noEventKey.contains(key)) {
return
}
val s = JSONObject()
.put("action", key)
.put("value", value)
.put("ext", ext)
val data = JSONObject()
.put("data", s)
.put("bp", getConfigParams())
.toString()
val body = AESHelper.encrypt(data)
.toRequestBody("application/json;charset=utf-8".toMediaTypeOrNull())
val request = Request.Builder()
.url(url)
.post(body)
.build()
client.newCall(request).enqueue(object : Callback {
override fun onFailure(call: Call, e: IOException) {
LogEx.logDebug(TAG, "onFailure")
}
override fun onResponse(call: Call, response: Response) {
if (response.code == 200 && response.isSuccessful) {
LogEx.logDebug(TAG, "onResponse 200")
}
}
})
}
}
\ No newline at end of file
package com.base.appzxhy.business.helper;
import android.text.TextUtils;
import com.base.appzxhy.utils.LogEx;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Map;
public class ReportUtils {
private static String TAG = "ReportUtils";
public static String doPost(String urlPath, Map<String, String> paramsMap, String json) {
try {
HttpURLConnection conn = (HttpURLConnection) new URL(urlPath).openConnection();
conn.setRequestMethod("POST");
conn.setDoOutput(true);
conn.setConnectTimeout(5000);
if (!TextUtils.isEmpty(json)) {
conn.setRequestProperty("Content-Type", "application/json");
conn.setRequestProperty("Content-Length", Integer.toString(json.getBytes().length));
conn.getOutputStream().write(json.getBytes());
}
StringBuilder result = new StringBuilder();
for (Map.Entry<String, String> entry : paramsMap.entrySet()) {
result.append("&").append(entry.getKey()).append("=").append(entry.getValue());
}
if (result.length() > 0) {
try {
conn.getOutputStream().write(result.substring(1).getBytes());
} catch (Exception e) {
}
} else {
// conn.getOutputStream().write(result.substring(0).getBytes());
}
if (conn.getResponseCode() == 200) {
String s = new BufferedReader(new InputStreamReader(conn.getInputStream())).readLine();
if (!TextUtils.isEmpty(s)) {
} else {
s = "";
}
LogEx.INSTANCE.logDebug(TAG, "code=200", false);
return s;
} else {
LogEx.INSTANCE.logDebug(TAG, "code!=200", false);
}
} catch (Exception e) {
e.printStackTrace();
}
return "{ \"success\": false,\n \"errorMsg\": \"后台服务器开小差了!\",\n \"result\":{}}";
}
}
package com.base.appzxhy.business.push.notification
import android.os.Handler
import android.os.HandlerThread
import com.base.appzxhy.MyApplication
import com.base.appzxhy.bean.push.NotificationSendBean
import com.base.appzxhy.bean.config.PopupConfigBean.Companion.popupConfigBean
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.async
import kotlinx.coroutines.cancel
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
/**
* 通知悬停
*/
object NotificationHoverUtils {
private val TAG = "NotificationHoverUtils"
private var handlerThread: HandlerThread? = null
private var handler: Handler? = null
private val scope = CoroutineScope(SupervisorJob() + Dispatchers.Default)
private var notificationJobs = mutableListOf<Job>()
/**
* 发送悬停通知
*/
fun sendHoverNotification(sendBean: NotificationSendBean) {
val hoverStatus = popupConfigBean.popupHoverStatus
val hoverCount = popupConfigBean.popupHoverCount
val hoverDelay = popupConfigBean.popupHoverDelay.toLong()
if (!hoverStatus) return
stopNotificationHandler()
if (handlerThread == null) {
handlerThread = HandlerThread("NotificationHandlerThread")
handlerThread?.start()
}
if (!hoverStatus) return
// 创建 Handler
if (handler == null) {
handlerThread?.let {
val looper = it.getLooper() ?: return
handler = Handler(looper)
}
}
// 取消之前的任务
stopNotificationHandler()
for (i in 1..hoverCount) {
val time = i * hoverDelay
handler?.postDelayed(Runnable {
// LogEx.logDebug(TAG, "handler ${MyApplication.PAUSED_VALUE}")
if (MyApplication.PAUSED_VALUE == 1) {
handler?.removeCallbacksAndMessages(null)
} else {
NotificationUiUtil.sendCustomNotification(sendBean)
val job = scope.launch {
delay(time)
if (MyApplication.PAUSED_VALUE != 1) {
async(Dispatchers.Main) {
NotificationUiUtil.sendCustomNotification(sendBean)
}.await()
}
}, time)
}
notificationJobs.add(job)
}
}
private fun stopNotificationHandler() {
// 停止 HandlerThread
if (handler != null) {
handler?.removeCallbacksAndMessages(null)
}
if (handlerThread != null) {
handlerThread?.quit()
handlerThread = null
}
handler = null
// 取消所有协程任务
notificationJobs.forEach { it.cancel() }
notificationJobs.clear()
}
/**
* 清理资源
*/
fun destroy() {
stopNotificationHandler()
scope.cancel()
}
}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment