Commit 58f2aad8 authored by wanglei's avatar wanglei

[同步]上报和请求配置

parent bd20c08e
......@@ -22,7 +22,7 @@
-dontwarn javax.annotation.Nullable
#-keep class com.base.locationsharewhite.bean.** { *; }
-keep class com.base.appzxhy.bean.** { *; }
-keep class com.google.gson.reflect.** { *; }
-keep class * extends com.google.gson.reflect.TypeToken
-keep class com.google.gson.stream.** { *; }
......
......@@ -3,39 +3,37 @@ package com.base.appzxhy
import android.app.Activity
import android.app.Application
import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.text.TextUtils
import android.util.Log
import com.base.appzxhy.business.helper.EventUtils
import com.base.appzxhy.business.helper.InstallHelps
import com.base.appzxhy.business.helper.NewComUtils
import com.base.appzxhy.business.service.StayJobService.Companion.startJob
import com.base.appzxhy.utils.ActivityManagerUtils
import com.base.appzxhy.utils.AppPreferences
import com.base.appzxhy.utils.LogEx
import com.base.appzxhy.utils.SolarEngineUtils.initSolarEngine
import com.base.appzxhy.utils.SolarEngineUtils.solarkey
import com.facebook.FacebookSdk
import com.google.android.gms.ads.identifier.AdvertisingIdClient
import com.google.gson.Gson
import com.hjq.language.MultiLanguages
import com.hjq.language.OnLanguageListener
import com.reyun.solar.engine.SolarEngineManager
import org.json.JSONObject
import java.util.Locale
import java.util.UUID
import com.base.appzxhy.ConstObject.appLanguageSp
import com.base.appzxhy.ConstObject.appLanguageCountrySp
import com.base.appzxhy.bean.config.AdConfigBean
import com.base.appzxhy.bean.config.ConfigBean
import com.base.appzxhy.bean.config.PopupConfigBean
import com.base.appzxhy.SpConstObject.appLanguageSp
import com.base.appzxhy.SpConstObject.appLanguageCountrySp
import com.base.appzxhy.business.ads.AdsMgr
import com.base.appzxhy.business.helper.NewComUtils.spConfig
import com.base.appzxhy.business.push.fcm.FCMManager
import com.base.appzxhy.business.push.notification.MyNotificationManager
import com.base.appzxhy.business.push.receiver.AlarmReceiver.Companion.startAlarm
import com.base.appzxhy.business.push.receiver.ScreenStatusReceiver
import com.base.appzxhy.business.push.timer.TimerManager.Companion.changeTimer
import com.base.appzxhy.business.push.work.RepeatingWorker.Companion.schedulePeriodicWork
import com.base.appzxhy.business.service.StayJobService.Companion.startStayJobService
import com.base.appzxhy.ui.splash.SplashActivity
import com.base.appzxhy.utils.SolarEngineUtils.initSolarEngine
import com.base.appzxhy.utils.SolarEngineUtils.solarkey
import com.facebook.FacebookSdk
import com.facebook.appevents.AppEventsLogger
import com.reyun.solar.engine.SolarEngineManager
class MyApplication : Application() {
......@@ -66,9 +64,16 @@ class MyApplication : Application() {
appContext = this
initUUid()
initUUid()
initGid()
initApp()
initLifeListener()
initLanguage()
}
private fun initLanguage() {
// 初始化语种切换框架
MultiLanguages.init(this)
......@@ -90,6 +95,7 @@ class MyApplication : Application() {
})
}
private fun initGid() {
Thread {
val info: AdvertisingIdClient.Info = AdvertisingIdClient.getAdvertisingIdInfo(applicationContext)
......@@ -114,29 +120,35 @@ class MyApplication : Application() {
private fun initApp() {
AdsMgr.init(appContext)
initPush()
initAppConfig()
initFacebook()
initSolar()
}
private fun initPush() {
kotlin.runCatching {
startJob()
startStayJobService()
}
//初始化广告相关业务
AdsMgr.init(appContext)
FacebookSdk.sdkInitialize(applicationContext)
// val token = AppPreferences.getInstance().getString("token", "")
val topic = GlobalConfig.PACKAGE_NAME + "_push"
// LogEx.logDebug(TAG, "topic=${topic} token=$token")
FCMManager.initFirebase(this)
FCMManager.subscribeToTopic(topic)
initAppConfig()
SolarEngineManager.getInstance().preInit(this, solarkey)
initLifeListener()
changeTimer()
ScreenStatusReceiver.registerScreenStatusReceiver(this)
// PackageStatusReceiver.registerPackageStatusReceiver(this)
// BatteryStatusReceiver.registerBatteryStatusReceiver(this)
// BatteryReceiver.registerBatteryReceiver(this)
//workManager
schedulePeriodicWork(appContext)
......@@ -147,23 +159,32 @@ class MyApplication : Application() {
//开启通知队列
MyNotificationManager.startNotificationQueue()
}
appContext.initSolarEngine(true)
private fun initAppConfig() {
//初始化sp的配置
NewComUtils.parseConfigBean(spConfig)
NewComUtils.requestCfgCallBackMap.put("changeTimer") {
LogEx.logDebug(TAG, "requestCfgCallBackMap changeTimer")
changeTimer()
}
InstallHelps.init {
NewComUtils.requestCfg()
}
}
private fun initAppConfig() {
Thread {
val config = AppPreferences.getInstance().getString("config", "")
if (config.isNotEmpty()) {
initConfig(config)
}
private fun initFacebook() {
//初始化facebook sdk
FacebookSdk.sdkInitialize(applicationContext)
AppEventsLogger.activateApp(this)
}
InstallHelps.init {
initRemoteConfig()
}
}.start()
private fun initSolar() {
SolarEngineManager.getInstance().preInit(this, solarkey)
appContext.initSolarEngine(true)
}
......@@ -199,13 +220,13 @@ class MyApplication : Application() {
LogEx.logDebug(TAG, "flag=$flag" + " activity:" + activity.localClassName)
if (flag) {
// topActivity?.startActivity(
// Intent(
// topActivity, SplashActivity::class.java
// ).apply {
// putExtra("isHotLaunch", true)
// putExtra("type", -1)
// })
topActivity?.startActivity(
Intent(
topActivity, SplashActivity::class.java
).apply {
putExtra("isHotLaunch", true)
putExtra("type", -1)
})
}
}
lastTimeResume = 0
......@@ -215,7 +236,6 @@ class MyApplication : Application() {
PAUSED_VALUE = 1
}
override fun onActivityPaused(activity: Activity) {
PAUSED_VALUE = 2
lastTimePause = System.currentTimeMillis()
......@@ -233,45 +253,4 @@ class MyApplication : Application() {
})
}
private fun initRemoteConfig() {
NewComUtils.requestCfg { config ->
LogEx.logDebug("requestCfg", "config=$config")
if (config != null) {
AppPreferences.getInstance().put("config", config)
initConfig(config)
} else {
EventUtils.event("configNull")
}
}
}
private fun initConfig(config: String) {
// kotlin.runCatching {
val configBean = Gson().fromJson(config, ConfigBean::class.java)
val jsonObject = JSONObject()
jsonObject.put("ut", configBean.ut)
EventUtils.event("user_type", ext = jsonObject)
//配置
ConfigBean.configBean = configBean
//广告
AdConfigBean.adsConfigBean = configBean.adConfigBean
LogEx.logDebug("initConfig", "adsConfigBean=${configBean.adConfigBean.functionInShowAd}")
//通知配置
PopupConfigBean.popupConfigBean = configBean.popupConfigBean
LogEx.logDebug("initConfig", "popupConfigBean=${configBean.popupConfigBean.popupCount}")
//启动定时器
changeTimer()
// }
}
}
\ No newline at end of file
......@@ -3,7 +3,18 @@ package com.base.appzxhy
import com.base.appzxhy.utils.AppPreferences
import java.util.Locale
object ConstObject {
object SpConstObject {
//是否已经点击start
var ifAgreePrivacy = false
get() {
return AppPreferences.getInstance().getBoolean("ifAgreePrivacy", field)
}
set(value) {
field = value
AppPreferences.getInstance().put("ifAgreePrivacy", value, true)
}
var isGuided = false
get() {
......
......@@ -15,8 +15,8 @@ import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import androidx.lifecycle.lifecycleScope
import androidx.viewbinding.ViewBinding
import com.base.appzxhy.ConstObject.appLanguageCountrySp
import com.base.appzxhy.ConstObject.appLanguageSp
import com.base.appzxhy.SpConstObject.appLanguageCountrySp
import com.base.appzxhy.SpConstObject.appLanguageSp
import com.base.appzxhy.R
import com.base.appzxhy.business.helper.EventUtils
import com.base.appzxhy.ui.main.MainActivity
......
......@@ -3,24 +3,63 @@ package com.base.appzxhy.business.helper
import android.os.Build
import com.base.appzxhy.BuildConfig
import com.base.appzxhy.GlobalConfig
import com.base.appzxhy.business.helper.ReportUtils.doPost
import com.base.appzxhy.SpConstObject.ifAgreePrivacy
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"
var ifAgreePrivacy = true
get() {
return AppPreferences.getInstance().getBoolean("ifAgreePrivacy", field)
}
set(value) {
field = value
AppPreferences.getInstance().put("ifAgreePrivacy", value, true)
private val client = OkHttpClient.Builder().apply {
if (BuildConfig.DEBUG) {
addInterceptor(HttpLoggingInterceptor().apply {
level = HttpLoggingInterceptor.Level.BODY
})
}
}.build()
private val url by lazy {
val pkg = GlobalConfig.PACKAGE_NAME
val url = StringBuilder(
"${GlobalConfig.URL_EVENT}/${
pkg.filter { it.isLowerCase() }.substring(4, 9)
}sp"
)
url.append("?pkg=$pkg")
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,
......@@ -28,59 +67,40 @@ object EventUtils {
ext: JSONObject? = null,
) {
if (!ifAgreePrivacy) {
if (BuildConfig.DEBUG || !ifAgreePrivacy || ConfigBean.configBean.noEventKey.contains(key)) {
return
}
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 = ""
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")
}
LogEx.logDebug(TAG, "url=$url")
doPost(
url,
HashMap(),
paramJson
)
}.start()
}
private val url by lazy {
val pkg = GlobalConfig.PACKAGE_NAME
val url = StringBuilder(
"${GlobalConfig.URL_EVENT}/${
pkg.filter { it.isLowerCase() }.substring(4, 9)
}sp"
)
url.append("?pkg=$pkg")
url.toString()
override fun onResponse(call: Call, response: Response) {
if (response.code == 200 && response.isSuccessful) {
LogEx.logDebug(TAG, "onResponse 200")
}
}
})
}
}
\ No newline at end of file
}
......@@ -4,25 +4,53 @@ import android.util.Base64
import android.util.Log
import com.base.appzxhy.BuildConfig
import com.base.appzxhy.GlobalConfig
import com.base.appzxhy.bean.config.AdConfigBean
import com.base.appzxhy.bean.config.ConfigBean
import com.base.appzxhy.bean.config.PopupConfigBean
import com.base.appzxhy.utils.AppPreferences
import com.base.appzxhy.utils.LogEx
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.io.BufferedReader
import java.io.InputStreamReader
import java.net.HttpURLConnection
import java.net.URL
import com.google.gson.Gson
import okhttp3.Call
import okhttp3.Callback
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.Response
import org.json.JSONObject
import java.io.IOException
import java.util.Locale
import java.util.concurrent.TimeUnit
import java.util.concurrent.atomic.AtomicBoolean
object NewComUtils {
private val TAG = "NewComUtils"
private const val API_URL = GlobalConfig.URL_API
private const val PACKAGE_NAME_PREFIX = GlobalConfig.PACKAGE_NAME
private const val DATA_KEY = "data"
private val url: String by lazy {
//sp配置缓存
var spConfig = ""
get() {
return AppPreferences.getInstance().getString("spConfig", field)
}
set(value) {
field = value
AppPreferences.getInstance().put("spConfig", value, true)
}
//上次请求时间
private var lastRequestTime = 0L
get() {
return AppPreferences.getInstance().getLong("lastRequestTime", field)
}
set(value) {
field = value
AppPreferences.getInstance().put("lastRequestTime", value, true)
}
fun getUrl(): String {
val packageName = GlobalConfig.PACKAGE_NAME
val appCode = packageName.substringAfter(PACKAGE_NAME_PREFIX).take(5).toLowerCase(Locale.getDefault())
......@@ -39,62 +67,146 @@ object NewComUtils {
"&aid=${AppPreferences.getInstance().getString("uuid", "")}"
if (BuildConfig.DEBUG) {
s = "$s&mode=3"
s = "$s&mode=4"
}
s
// mode =3 google mode=2 facebook mode=1 自然,mode=4 测试
// mode =3 google mode=2 facebook mode=1 自然,mode=4 测试
// &mode=3
return s
}
//请求中的回调
var requestCfgIng = AtomicBoolean(false)
fun requestCfg(callback: (json: String?) -> Unit) {
CoroutineScope(Dispatchers.IO).launch {
val response = doGet()
if (response == null) {
withContext(Dispatchers.Main) {
callback(null)
}
return@launch
}
fun canRequestCfg(): Boolean {
val passHour = (System.currentTimeMillis() - lastRequestTime) / 3600000
val data = extractData(response)
if (data == null) {
withContext(Dispatchers.Main) {
callback(null)
}
return@launch
}
if (BuildConfig.DEBUG) {
lastRequestTime = 0L
}
val decryptedData = AESHelper.decrypt(data)
withContext(Dispatchers.Main) {
callback(decryptedData)
}
if (lastRequestTime != 0L && passHour < ConfigBean.configBean.getConfigInterval) {
Log.e(TAG, "请求间隔 passHour=$passHour")
return false
}
return true
}
private fun doGet(): String? {
val urlPath = url
LogEx.logDebug(TAG, "url=$url")
try {
val conn: HttpURLConnection = URL(urlPath).openConnection() as HttpURLConnection
conn.setRequestMethod("GET")
conn.connectTimeout = 150000
if (200 == conn.getResponseCode()) {
val json = BufferedReader(InputStreamReader(conn.inputStream)).readLine()
LogEx.logDebug(TAG, "json=$json")
return json
}
} catch (e: Exception) {
e.printStackTrace()
Log.d("okhttp", e.toString())
fun requestCfg() {
requestCfgIng.set(true)
if (!canRequestCfg()) {
return
}
return null
val urlPath = getUrl()
LogEx.logDebug(TAG, "url=$urlPath")
val request = Request.Builder()
.url(urlPath)
.get()
.build()
client.newCall(request).enqueue(object : Callback {
override fun onFailure(call: Call, e: IOException) {
e.printStackTrace()
Log.d(TAG, "onFailure $e")
handleCfgCallBack()
}
override fun onResponse(call: Call, response: Response) {
if (response.isSuccessful) {
val json = response.body?.string() ?: ""
LogEx.logDebug(TAG, "json=$json")
val data = extractData(json)
if (data != null) {
lastRequestTime = System.currentTimeMillis()
val decryptedData = AESHelper.decrypt(data)
LogEx.logDebug(TAG, "decryptedData=$decryptedData")
parseConfigBean(decryptedData)
}
}
handleCfgCallBack()
}
})
}
private val client = OkHttpClient.Builder()
.connectTimeout(10, TimeUnit.SECONDS)
.callTimeout(10, TimeUnit.SECONDS)
.readTimeout(10, TimeUnit.SECONDS)
.writeTimeout(10, TimeUnit.SECONDS)
.build()
private fun extractData(response: String): String? {
val regex = Regex("\"$DATA_KEY\":\"(.*?)\"")
val match = regex.find(response)
return match?.groupValues?.get(1)
}
fun parseConfigBean(config: String) {
if (config.isNotEmpty()) {
try {
val configBean = Gson().fromJson(config, ConfigBean::class.java)
val jsonObject = JSONObject()
jsonObject.put("ut", configBean.ut)
EventUtils.event("user_type", ext = jsonObject)
//配置
ConfigBean.configBean = configBean
//广告
AdConfigBean.adsConfigBean = configBean.adConfigBean
LogEx.logDebug("initConfig", "adsConfigBean=${configBean.adConfigBean.isAdShow} ut=${configBean.ut}", true)
//通知配置
PopupConfigBean.popupConfigBean = configBean.popupConfigBean
LogEx.logDebug("initConfig", "popupConfigBean=${configBean.popupConfigBean.popupCount}", true)
if (spConfig != config) {
spConfig = config
}
} catch (e: Exception) {
e.printStackTrace()
EventUtils.event("parseConfigBean_error", value = config)
}
}
}
var requestCfgCallBackMap = hashMapOf<String, () -> Unit>()
private fun handleCfgCallBack() {
requestCfgIng.set(false)
LogEx.logDebug(TAG, "handleCfgCallBack")
val key1 = "adCallBack"
requestCfgCallBackMap.get(key1)?.let {
it.invoke()
requestCfgCallBackMap.remove(key1)
}
val key2 = "changeTimer"
requestCfgCallBackMap.get(key2)?.let {
it.invoke()
requestCfgCallBackMap.remove(key2)
}
}
}
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\":{}}";
}
}
......@@ -39,7 +39,7 @@ class StayJobService : JobService() {
private var startJobTime = 0L
private val minimumLatency = if (BuildConfig.DEBUG) 5000L else 5000L
fun Context.startJob() {
fun Context.startStayJobService() {
if (isRunning) return
LogEx.logDebug(TAG, "startJob")
startJobTime = System.currentTimeMillis()
......
......@@ -6,5 +6,12 @@ import com.base.appzxhy.databinding.ActivityMainBinding
class MainActivity : BaseActivity<ActivityMainBinding>(ActivityMainBinding::inflate) {
override fun initView() {
super.initView()
}
override fun initListener() {
super.initListener()
}
}
\ No newline at end of file
......@@ -4,7 +4,8 @@
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/main"
android:layout_width="match_parent"
android:layout_height="match_parent">
android:layout_height="match_parent"
android:background="@color/white">
<androidx.viewpager2.widget.ViewPager2
android:id="@+id/viewPager2"
......
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