parent
							
								
									5927987ff5
								
							
						
					
					
						commit
						3803d53afe
					
				| 
						 | 
					@ -1,3 +1,39 @@
 | 
				
			||||||
 | 
					## v1.0.3
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					##### BugFix
 | 
				
			||||||
 | 
					- bugfix snapshotAnalyticsAudit uploaded > total
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## v1.0.2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					##### Feature
 | 
				
			||||||
 | 
					- init step callback
 | 
				
			||||||
 | 
					- snapshotAnalyticsAudit()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					##### BugFix
 | 
				
			||||||
 | 
					- bugfix http exception
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## v1.0.1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					##### Feature
 | 
				
			||||||
 | 
					- init add uploadIpAddress
 | 
				
			||||||
 | 
					- CronetHelper init try catch
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## v1.0.0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					##### Feature
 | 
				
			||||||
 | 
					- CustomDns add cache
 | 
				
			||||||
 | 
					- init add isEnableCronet
 | 
				
			||||||
 | 
					- UserProperty guru_anm cronet/default
 | 
				
			||||||
 | 
					- PendingEvent 初始化成功前添加的埋点时间戳校正
 | 
				
			||||||
 | 
					- initialize uploadEventBaseUrl fromat check
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## v0.3.2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					##### Feature
 | 
				
			||||||
 | 
					- add fun peakUserProperties
 | 
				
			||||||
 | 
					- add fun getUserProperties
 | 
				
			||||||
 | 
					- add fun setEnableUpload
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## v0.3.1
 | 
					## v0.3.1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
##### Feature
 | 
					##### Feature
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -7,9 +7,11 @@ import android.widget.TextView
 | 
				
			||||||
import guru.core.analytics.GuruAnalytics
 | 
					import guru.core.analytics.GuruAnalytics
 | 
				
			||||||
import guru.core.analytics.data.db.model.EventPriority
 | 
					import guru.core.analytics.data.db.model.EventPriority
 | 
				
			||||||
import guru.core.analytics.data.model.AnalyticsOptions
 | 
					import guru.core.analytics.data.model.AnalyticsOptions
 | 
				
			||||||
import guru.core.analytics.handler.AnalyticsCode
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
class MainActivity : AppCompatActivity() {
 | 
					class MainActivity : AppCompatActivity() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private var enableUpload = true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override fun onCreate(savedInstanceState: Bundle?) {
 | 
					    override fun onCreate(savedInstanceState: Bundle?) {
 | 
				
			||||||
        super.onCreate(savedInstanceState)
 | 
					        super.onCreate(savedInstanceState)
 | 
				
			||||||
        setContentView(R.layout.activity_main)
 | 
					        setContentView(R.layout.activity_main)
 | 
				
			||||||
| 
						 | 
					@ -36,6 +38,8 @@ class MainActivity : AppCompatActivity() {
 | 
				
			||||||
            .setXAppId("test_x_app_id")
 | 
					            .setXAppId("test_x_app_id")
 | 
				
			||||||
            .setXDeviceInfo("test_x_device_info")
 | 
					            .setXDeviceInfo("test_x_device_info")
 | 
				
			||||||
            .setMainProcess("com.example.guruanalytics")
 | 
					            .setMainProcess("com.example.guruanalytics")
 | 
				
			||||||
 | 
					            .isEnableCronet(true)
 | 
				
			||||||
 | 
					            .setUploadIpAddress(listOf("3.210.96.186", "34.196.69.199"))
 | 
				
			||||||
            .build()
 | 
					            .build()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        findViewById<TextView>(R.id.tvLogEvent).setOnClickListener {
 | 
					        findViewById<TextView>(R.id.tvLogEvent).setOnClickListener {
 | 
				
			||||||
| 
						 | 
					@ -76,9 +80,31 @@ class MainActivity : AppCompatActivity() {
 | 
				
			||||||
            GuruAnalytics.INSTANCE.setUploadEventBaseUrl(this, "https://www.castbox.fm/")
 | 
					            GuruAnalytics.INSTANCE.setUploadEventBaseUrl(this, "https://www.castbox.fm/")
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        val tvEnable = findViewById<TextView>(R.id.tvEnable)
 | 
				
			||||||
 | 
					        tvEnable?.setOnClickListener {
 | 
				
			||||||
 | 
					            val enable = !enableUpload
 | 
				
			||||||
 | 
					            GuruAnalytics.INSTANCE.setEnableUpload(enable)
 | 
				
			||||||
 | 
					            enableUpload = enable
 | 
				
			||||||
 | 
					            tvEnable.text = if (enableUpload) "Enable Upload" else "Disable Upload"
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        GuruAnalytics.INSTANCE.setScreen("main")
 | 
					        GuruAnalytics.INSTANCE.setScreen("main")
 | 
				
			||||||
        GuruAnalytics.INSTANCE.setAdId("AD_ID_01")
 | 
					        GuruAnalytics.INSTANCE.setAdId("AD_ID_01")
 | 
				
			||||||
        GuruAnalytics.INSTANCE.setUserProperty("uid", "110051")
 | 
					        GuruAnalytics.INSTANCE.setUserProperty("uid", "110051")
 | 
				
			||||||
 | 
					        GuruAnalytics.INSTANCE.setUserProperty("age", "12")
 | 
				
			||||||
 | 
					        GuruAnalytics.INSTANCE.setUserProperty("sex", "male")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        val properties = GuruAnalytics.INSTANCE.peakUserProperties()
 | 
				
			||||||
 | 
					        Log.i("peakUserProperties", "properties:$properties")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        GuruAnalytics.INSTANCE.getUserProperties {
 | 
				
			||||||
 | 
					            Log.i("getUserProperties", "properties:$it")
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        tvEnable?.postDelayed({
 | 
				
			||||||
 | 
					            val snapshot = GuruAnalytics.INSTANCE.snapshotAnalyticsAudit()
 | 
				
			||||||
 | 
					            Log.i("snapshotAnalyticsAudit", "snapshot:$snapshot")
 | 
				
			||||||
 | 
					        }, 10_000)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private val eventHandler: (Int, String?) -> Unit = { code, ext ->
 | 
					    private val eventHandler: (Int, String?) -> Unit = { code, ext ->
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -70,4 +70,13 @@
 | 
				
			||||||
        android:text="Update BaseUrl"
 | 
					        android:text="Update BaseUrl"
 | 
				
			||||||
        android:layout_gravity="center_horizontal" />
 | 
					        android:layout_gravity="center_horizontal" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <TextView
 | 
				
			||||||
 | 
					        android:id="@+id/tvEnable"
 | 
				
			||||||
 | 
					        android:layout_width="wrap_content"
 | 
				
			||||||
 | 
					        android:layout_height="wrap_content"
 | 
				
			||||||
 | 
					        android:layout_marginTop="30dp"
 | 
				
			||||||
 | 
					        android:padding="10dp"
 | 
				
			||||||
 | 
					        android:text="Enable Upload"
 | 
				
			||||||
 | 
					        android:layout_gravity="center_horizontal" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
</LinearLayout>
 | 
					</LinearLayout>
 | 
				
			||||||
| 
						 | 
					@ -53,7 +53,9 @@ dependencies {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    implementation okhttpDependencies
 | 
					    implementation okhttpDependencies
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    implementation process
 | 
					    implementation processDependencies
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    implementation workerDependencies
 | 
					    implementation workerDependencies
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    implementation cronetDependencies
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -21,6 +21,8 @@ ext {
 | 
				
			||||||
    preferenceVersion = '1.2.0'
 | 
					    preferenceVersion = '1.2.0'
 | 
				
			||||||
    processVersion = '2.4.0'
 | 
					    processVersion = '2.4.0'
 | 
				
			||||||
    workVersion = '2.7.1'
 | 
					    workVersion = '2.7.1'
 | 
				
			||||||
 | 
					    cronetOkhttpVersion = '0.1.0'
 | 
				
			||||||
 | 
					    playServicesCronetVersion = '18.0.1'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    kaptDependencies = [
 | 
					    kaptDependencies = [
 | 
				
			||||||
            "androidx.room:room-compiler:$roomVersion",
 | 
					            "androidx.room:room-compiler:$roomVersion",
 | 
				
			||||||
| 
						 | 
					@ -54,7 +56,12 @@ ext {
 | 
				
			||||||
            "androidx.work:work-rxjava2:$workVersion"
 | 
					            "androidx.work:work-rxjava2:$workVersion"
 | 
				
			||||||
    ]
 | 
					    ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    process = [
 | 
					    processDependencies = [
 | 
				
			||||||
            "androidx.lifecycle:lifecycle-process:$processVersion"
 | 
					            "androidx.lifecycle:lifecycle-process:$processVersion"
 | 
				
			||||||
    ]
 | 
					    ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    cronetDependencies = [
 | 
				
			||||||
 | 
					            "com.google.net.cronet:cronet-okhttp:$cronetOkhttpVersion",
 | 
				
			||||||
 | 
					            "com.google.android.gms:play-services-cronet:$playServicesCronetVersion"
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -18,7 +18,7 @@ publishing {    // Repositories *to* which Gradle can publish artifacts
 | 
				
			||||||
        maven(MavenPublication) {
 | 
					        maven(MavenPublication) {
 | 
				
			||||||
            groupId 'guru.core.analytics'
 | 
					            groupId 'guru.core.analytics'
 | 
				
			||||||
            artifactId 'guru_analytics'
 | 
					            artifactId 'guru_analytics'
 | 
				
			||||||
            version '0.3.1'             // Your package version
 | 
					            version '1.0.3'             // Your package version
 | 
				
			||||||
//                artifact publishArtifact    //Example: *./target/myJavaClasses.jar*
 | 
					//                artifact publishArtifact    //Example: *./target/myJavaClasses.jar*
 | 
				
			||||||
//            artifact "build/outputs/aar/aar-test-release.aar"//aar包的目录
 | 
					//            artifact "build/outputs/aar/aar-test-release.aar"//aar包的目录
 | 
				
			||||||
            afterEvaluate { artifact(tasks.getByName("bundleReleaseAar")) }
 | 
					            afterEvaluate { artifact(tasks.getByName("bundleReleaseAar")) }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -56,6 +56,12 @@ object Constants {
 | 
				
			||||||
        const val COIN = "coin"
 | 
					        const val COIN = "coin"
 | 
				
			||||||
        const val EXP = "exp"
 | 
					        const val EXP = "exp"
 | 
				
			||||||
        const val HP = "hp"
 | 
					        const val HP = "hp"
 | 
				
			||||||
 | 
					        const val GURU_ANM = "guru_anm"
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    object AnmState {
 | 
				
			||||||
 | 
					        const val CRONET = "cronet"
 | 
				
			||||||
 | 
					        const val DEFAULT = "default"
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    object DeviceType {
 | 
					    object DeviceType {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -4,7 +4,6 @@ import android.content.Context
 | 
				
			||||||
import guru.core.analytics.data.db.model.EventStatistic
 | 
					import guru.core.analytics.data.db.model.EventStatistic
 | 
				
			||||||
import guru.core.analytics.data.model.AnalyticsInfo
 | 
					import guru.core.analytics.data.model.AnalyticsInfo
 | 
				
			||||||
import guru.core.analytics.data.model.AnalyticsOptions
 | 
					import guru.core.analytics.data.model.AnalyticsOptions
 | 
				
			||||||
import guru.core.analytics.handler.AnalyticsCode
 | 
					 | 
				
			||||||
import guru.core.analytics.impl.GuruAnalyticsImpl
 | 
					import guru.core.analytics.impl.GuruAnalyticsImpl
 | 
				
			||||||
import java.io.File
 | 
					import java.io.File
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -21,13 +20,15 @@ abstract class GuruAnalytics {
 | 
				
			||||||
        eventExpiredInDays: Int? = 7,
 | 
					        eventExpiredInDays: Int? = 7,
 | 
				
			||||||
        debug: Boolean = false,
 | 
					        debug: Boolean = false,
 | 
				
			||||||
        persistableLog: Boolean = true,
 | 
					        persistableLog: Boolean = true,
 | 
				
			||||||
        listener: ((Int, String?) -> Unit)? = null,
 | 
					        eventHandlerCallback: ((Int, String?) -> Unit)? = null,
 | 
				
			||||||
        isInitPeriodicWork: Boolean = false,
 | 
					        isInitPeriodicWork: Boolean = false,
 | 
				
			||||||
        uploadEventBaseUrl: String? = null,
 | 
					        uploadEventBaseUrl: String? = null,
 | 
				
			||||||
        fgEventPeriodInSeconds: Long? = null,
 | 
					        fgEventPeriodInSeconds: Long? = null,
 | 
				
			||||||
        xAppId: String? = null,
 | 
					        xAppId: String? = null,
 | 
				
			||||||
        xDeviceInfo: String? = null,
 | 
					        xDeviceInfo: String? = null,
 | 
				
			||||||
        mainProcess: String? = null,
 | 
					        mainProcess: String? = null,
 | 
				
			||||||
 | 
					        isEnableCronet: Boolean? = null,
 | 
				
			||||||
 | 
					        uploadIpAddress: List<String>? = null,
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    abstract fun setUploadEventBaseUrl(context: Context, updateEventBaseUrl: String)
 | 
					    abstract fun setUploadEventBaseUrl(context: Context, updateEventBaseUrl: String)
 | 
				
			||||||
| 
						 | 
					@ -71,6 +72,17 @@ abstract class GuruAnalytics {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    abstract fun removeUserProperties(keys: Set<String>)
 | 
					    abstract fun removeUserProperties(keys: Set<String>)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    abstract fun getUserProperties(callback: (Map<String, String>) -> Unit)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * setUserProperty后立即获取, 可能无法获取到最新设置的值
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    abstract fun peakUserProperties(): Map<String, String>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    abstract fun setEnableUpload(enable: Boolean)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    abstract fun snapshotAnalyticsAudit(): String
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    companion object {
 | 
					    companion object {
 | 
				
			||||||
        val INSTANCE: GuruAnalytics by lazy() {
 | 
					        val INSTANCE: GuruAnalytics by lazy() {
 | 
				
			||||||
            GuruAnalyticsImpl()
 | 
					            GuruAnalyticsImpl()
 | 
				
			||||||
| 
						 | 
					@ -116,6 +128,12 @@ abstract class GuruAnalytics {
 | 
				
			||||||
        fun setMainProcess(process: String) =
 | 
					        fun setMainProcess(process: String) =
 | 
				
			||||||
            apply { analyticsInfo.mainProcess = process }
 | 
					            apply { analyticsInfo.mainProcess = process }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        fun isEnableCronet(isEnableCronet: Boolean) =
 | 
				
			||||||
 | 
					            apply { analyticsInfo.isEnableCronet = isEnableCronet }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        fun setUploadIpAddress(uploadIpAddress: List<String>) =
 | 
				
			||||||
 | 
					            apply { analyticsInfo.uploadIpAddress = uploadIpAddress }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        fun build(): GuruAnalytics {
 | 
					        fun build(): GuruAnalytics {
 | 
				
			||||||
            analyticsInfo.run {
 | 
					            analyticsInfo.run {
 | 
				
			||||||
                INSTANCE.initialize(
 | 
					                INSTANCE.initialize(
 | 
				
			||||||
| 
						 | 
					@ -133,6 +151,8 @@ abstract class GuruAnalytics {
 | 
				
			||||||
                    xAppId,
 | 
					                    xAppId,
 | 
				
			||||||
                    xDeviceInfo,
 | 
					                    xDeviceInfo,
 | 
				
			||||||
                    mainProcess,
 | 
					                    mainProcess,
 | 
				
			||||||
 | 
					                    isEnableCronet,
 | 
				
			||||||
 | 
					                    uploadIpAddress,
 | 
				
			||||||
                )
 | 
					                )
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            return INSTANCE
 | 
					            return INSTANCE
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,20 +1,28 @@
 | 
				
			||||||
package guru.core.analytics.data.api
 | 
					package guru.core.analytics.data.api
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import android.content.Context
 | 
					import android.content.Context
 | 
				
			||||||
 | 
					import android.net.Uri
 | 
				
			||||||
import android.os.SystemClock
 | 
					import android.os.SystemClock
 | 
				
			||||||
import guru.core.analytics.data.api.logging.LoggingInterceptor
 | 
					import guru.core.analytics.data.api.cronet.CastboxCronetInterceptor
 | 
				
			||||||
import guru.core.analytics.data.api.dns.CustomDns
 | 
					import guru.core.analytics.data.api.dns.CustomDns
 | 
				
			||||||
import guru.core.analytics.data.api.dns.GoogleDnsApi
 | 
					import guru.core.analytics.data.api.dns.GoogleDnsApi
 | 
				
			||||||
import guru.core.analytics.data.api.dns.GoogleDnsApiHost
 | 
					import guru.core.analytics.data.api.dns.GoogleDnsApiHost
 | 
				
			||||||
import guru.core.analytics.data.api.logging.Level
 | 
					import guru.core.analytics.data.api.logging.Level
 | 
				
			||||||
 | 
					import guru.core.analytics.data.api.logging.LoggingInterceptor
 | 
				
			||||||
import guru.core.analytics.data.local.PreferencesManager
 | 
					import guru.core.analytics.data.local.PreferencesManager
 | 
				
			||||||
import guru.core.analytics.handler.AnalyticsCode
 | 
					import guru.core.analytics.handler.AnalyticsCode
 | 
				
			||||||
import guru.core.analytics.handler.EventHandler
 | 
					import guru.core.analytics.handler.EventHandler
 | 
				
			||||||
import guru.core.analytics.utils.AndroidUtils
 | 
					import guru.core.analytics.utils.AndroidUtils
 | 
				
			||||||
import guru.core.analytics.utils.DateTimeUtils
 | 
					import guru.core.analytics.utils.DateTimeUtils
 | 
				
			||||||
import guru.core.analytics.utils.GsonUtil
 | 
					import guru.core.analytics.utils.GsonUtil
 | 
				
			||||||
import okhttp3.*
 | 
					import okhttp3.Dispatcher
 | 
				
			||||||
 | 
					import okhttp3.Headers
 | 
				
			||||||
 | 
					import okhttp3.Interceptor
 | 
				
			||||||
 | 
					import okhttp3.OkHttpClient
 | 
				
			||||||
 | 
					import okhttp3.Protocol
 | 
				
			||||||
 | 
					import okhttp3.Request
 | 
				
			||||||
import okhttp3.Response
 | 
					import okhttp3.Response
 | 
				
			||||||
 | 
					import okhttp3.ResponseBody
 | 
				
			||||||
import okhttp3.ResponseBody.Companion.toResponseBody
 | 
					import okhttp3.ResponseBody.Companion.toResponseBody
 | 
				
			||||||
import okhttp3.internal.platform.Platform
 | 
					import okhttp3.internal.platform.Platform
 | 
				
			||||||
import retrofit2.Converter
 | 
					import retrofit2.Converter
 | 
				
			||||||
| 
						 | 
					@ -35,6 +43,8 @@ object ServiceLocator {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private val headerParams = mutableMapOf<String, String>()
 | 
					    private val headerParams = mutableMapOf<String, String>()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private var uploadIpAddress: List<String>? = null
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fun addHeaderParam(key: String, value: String?) {
 | 
					    fun addHeaderParam(key: String, value: String?) {
 | 
				
			||||||
        if (value.isNullOrBlank()) return
 | 
					        if (value.isNullOrBlank()) return
 | 
				
			||||||
        headerParams[key] = value
 | 
					        headerParams[key] = value
 | 
				
			||||||
| 
						 | 
					@ -44,20 +54,24 @@ object ServiceLocator {
 | 
				
			||||||
        this.debug = debug
 | 
					        this.debug = debug
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fun provideGuruRepository(context: Context, baseUrl: String? = null): GuruRepository {
 | 
					    fun setUploadIpAddress(ipList: List<String>?) {
 | 
				
			||||||
 | 
					        uploadIpAddress = ipList
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fun provideGuruRepository(context: Context, baseUri: Uri? = null): GuruRepository {
 | 
				
			||||||
        synchronized(this) {
 | 
					        synchronized(this) {
 | 
				
			||||||
            return guruRepository
 | 
					            return guruRepository
 | 
				
			||||||
                ?: createQuotesRepository(context, baseUrl).apply { guruRepository = this }
 | 
					                ?: createQuotesRepository(context, baseUri).apply { guruRepository = this }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private fun createQuotesRepository(context: Context, baseUrl: String? = null): GuruRepository {
 | 
					    private fun createQuotesRepository(context: Context, baseUri: Uri? = null): GuruRepository {
 | 
				
			||||||
        return DefaultGuruRepository(provideAnalyticsApi(context, baseUrl))
 | 
					        return DefaultGuruRepository(provideAnalyticsApi(context, baseUri))
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private fun provideAnalyticsApi(context: Context, baseUrl: String? = null): AnalyticsApi {
 | 
					    private fun provideAnalyticsApi(context: Context, baseUri: Uri? = null): AnalyticsApi {
 | 
				
			||||||
        val finalBaseUrl = if (!baseUrl.isNullOrEmpty()) {
 | 
					        val finalBaseUrl = if (baseUri != null) {
 | 
				
			||||||
            baseUrl
 | 
					            baseUri.toString()
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            val cacheBaseUrl = PreferencesManager.getInstance(context).uploadEventBaseUrl
 | 
					            val cacheBaseUrl = PreferencesManager.getInstance(context).uploadEventBaseUrl
 | 
				
			||||||
            if (cacheBaseUrl.isNullOrEmpty()) AnalyticsApiHost.BASE_URL else cacheBaseUrl
 | 
					            if (cacheBaseUrl.isNullOrEmpty()) AnalyticsApiHost.BASE_URL else cacheBaseUrl
 | 
				
			||||||
| 
						 | 
					@ -114,20 +128,22 @@ object ServiceLocator {
 | 
				
			||||||
                maxRequests = 128
 | 
					                maxRequests = 128
 | 
				
			||||||
                maxRequestsPerHost = 10
 | 
					                maxRequestsPerHost = 10
 | 
				
			||||||
            })
 | 
					            })
 | 
				
			||||||
            .dns(CustomDns(context))
 | 
					            .dns(CustomDns(context, uploadIpAddress))
 | 
				
			||||||
            .connectTimeout(20L, TimeUnit.SECONDS)
 | 
					            .connectTimeout(20L, TimeUnit.SECONDS)
 | 
				
			||||||
            .readTimeout(readTimeOut, TimeUnit.SECONDS)
 | 
					            .readTimeout(readTimeOut, TimeUnit.SECONDS)
 | 
				
			||||||
            .writeTimeout(writeTimeOut, TimeUnit.SECONDS)
 | 
					            .writeTimeout(writeTimeOut, TimeUnit.SECONDS)
 | 
				
			||||||
            .addInterceptor(createCacheControlInterceptor(context))
 | 
					            .addInterceptor(createCacheControlInterceptor(context))
 | 
				
			||||||
            .addInterceptor(createAnalyticsApiInterceptor())
 | 
					            .addInterceptor(createAnalyticsApiInterceptor())
 | 
				
			||||||
            .addInterceptor(createLoggingInterceptor())
 | 
					            .addInterceptor(createLoggingInterceptor())
 | 
				
			||||||
 | 
					            .addInterceptor(createCronetInterceptor())
 | 
				
			||||||
        return builder.build()
 | 
					        return builder.build()
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private fun createDnsOkHttpClient(context: Context): OkHttpClient {
 | 
					    private fun createDnsOkHttpClient(context: Context): OkHttpClient {
 | 
				
			||||||
        val builder = OkHttpClient.Builder()
 | 
					        val builder = OkHttpClient.Builder()
 | 
				
			||||||
            .addInterceptor(createCacheControlInterceptor(context))
 | 
					            .addInterceptor(createCacheControlInterceptor(context))
 | 
				
			||||||
        builder.addInterceptor(createLoggingInterceptor())
 | 
					            .addInterceptor(createLoggingInterceptor())
 | 
				
			||||||
 | 
					            .addInterceptor(createCronetInterceptor())
 | 
				
			||||||
        return builder.build()
 | 
					        return builder.build()
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -140,6 +156,14 @@ object ServiceLocator {
 | 
				
			||||||
            .build()
 | 
					            .build()
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Add the Cronet interceptor last, otherwise the subsequent interceptors will be skipped.
 | 
				
			||||||
 | 
					     * https://github.com/google/cronet-transport-for-okhttp
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    private fun createCronetInterceptor(): Interceptor {
 | 
				
			||||||
 | 
					        return CastboxCronetInterceptor()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private fun createCacheControlInterceptor(context: Context) = Interceptor { chain ->
 | 
					    private fun createCacheControlInterceptor(context: Context) = Interceptor { chain ->
 | 
				
			||||||
        try {
 | 
					        try {
 | 
				
			||||||
            val originalResponse = chain.proceed(chain.request())
 | 
					            val originalResponse = chain.proceed(chain.request())
 | 
				
			||||||
| 
						 | 
					@ -162,10 +186,7 @@ object ServiceLocator {
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        } catch (e: Exception) {
 | 
					        } catch (e: Exception) {
 | 
				
			||||||
            EventHandler.INSTANCE.notifyEventHandler(AnalyticsCode.ERROR_CACHE_CONTROL, e.message)
 | 
					            EventHandler.INSTANCE.notifyEventHandler(AnalyticsCode.ERROR_CACHE_CONTROL, e.message)
 | 
				
			||||||
            return@Interceptor exceptionResponse(
 | 
					            throw e
 | 
				
			||||||
                e,
 | 
					 | 
				
			||||||
                chain.request()
 | 
					 | 
				
			||||||
            )
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -174,7 +195,6 @@ object ServiceLocator {
 | 
				
			||||||
            val request = chain.request()
 | 
					            val request = chain.request()
 | 
				
			||||||
            val startTime = SystemClock.elapsedRealtime()
 | 
					            val startTime = SystemClock.elapsedRealtime()
 | 
				
			||||||
            val builder = request.newBuilder()
 | 
					            val builder = request.newBuilder()
 | 
				
			||||||
                .addHeader(CONTENT_TYPE, "application/json")
 | 
					 | 
				
			||||||
                .addHeader(CONTENT_ENCODING, "gzip")
 | 
					                .addHeader(CONTENT_ENCODING, "gzip")
 | 
				
			||||||
                .addHeader(X_EVENT_TYPE, "event")
 | 
					                .addHeader(X_EVENT_TYPE, "event")
 | 
				
			||||||
            headerParams.forEach {
 | 
					            headerParams.forEach {
 | 
				
			||||||
| 
						 | 
					@ -182,17 +202,13 @@ object ServiceLocator {
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            val newRequest = builder.build()
 | 
					            val newRequest = builder.build()
 | 
				
			||||||
            try {
 | 
					            try {
 | 
				
			||||||
                val response = chain.proceed(newRequest)
 | 
					                chain.proceed(newRequest).also { response ->
 | 
				
			||||||
                    val responseTime = (SystemClock.elapsedRealtime() - startTime) / 2
 | 
					                    val responseTime = (SystemClock.elapsedRealtime() - startTime) / 2
 | 
				
			||||||
                    calibrationTime(responseTime, response.headers)
 | 
					                    calibrationTime(responseTime, response.headers)
 | 
				
			||||||
                if (response.isSuccessful) {
 | 
					 | 
				
			||||||
                    successResponse(response)
 | 
					 | 
				
			||||||
                } else {
 | 
					 | 
				
			||||||
                    httpErrorResponse(response)
 | 
					 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            } catch (e: Exception) {
 | 
					            } catch (e: Exception) {
 | 
				
			||||||
                EventHandler.INSTANCE.notifyEventHandler(AnalyticsCode.ERROR_API, e.message)
 | 
					                EventHandler.INSTANCE.notifyEventHandler(AnalyticsCode.ERROR_API, e.message)
 | 
				
			||||||
                return@Interceptor exceptionResponse(e, newRequest)
 | 
					                throw e
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -205,40 +221,6 @@ object ServiceLocator {
 | 
				
			||||||
        DateTimeUtils.initServerTime(date.time + responseTime)
 | 
					        DateTimeUtils.initServerTime(date.time + responseTime)
 | 
				
			||||||
        minResponseTime = responseTime
 | 
					        minResponseTime = responseTime
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					 | 
				
			||||||
    private fun successResponse(response: Response): Response {
 | 
					 | 
				
			||||||
        val body: ResponseBody?
 | 
					 | 
				
			||||||
        var bodyString: String?
 | 
					 | 
				
			||||||
        response.body.let {
 | 
					 | 
				
			||||||
            bodyString = it?.string()
 | 
					 | 
				
			||||||
            body = bodyString?.toResponseBody(it!!.contentType())
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        return response.newBuilder()
 | 
					 | 
				
			||||||
            .body(body)
 | 
					 | 
				
			||||||
            .build()
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    private fun httpErrorResponse(response: Response): Response {
 | 
					 | 
				
			||||||
        val body =
 | 
					 | 
				
			||||||
            "{\"code\": ${response.code}, \"msg\": \"${response.message}\", \"data\": null}".toResponseBody()
 | 
					 | 
				
			||||||
        response.close()
 | 
					 | 
				
			||||||
        EventHandler.INSTANCE.notifyEventHandler(AnalyticsCode.ERROR_RESPONSE, response.code.toString())
 | 
					 | 
				
			||||||
        return response.newBuilder()
 | 
					 | 
				
			||||||
            .code(1)
 | 
					 | 
				
			||||||
            .body(body)
 | 
					 | 
				
			||||||
            .build()
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    private fun exceptionResponse(e: Exception, request: Request): Response {
 | 
					 | 
				
			||||||
        val content = "{\"code\": -1, \"msg\": \"${e.message}\", \"data\": null}"
 | 
					 | 
				
			||||||
        return Response.Builder()
 | 
					 | 
				
			||||||
            .code(1)
 | 
					 | 
				
			||||||
            .request(request)
 | 
					 | 
				
			||||||
            .protocol(Protocol.HTTP_1_1)
 | 
					 | 
				
			||||||
            .message("${e.message}")
 | 
					 | 
				
			||||||
            .body(content.toResponseBody())
 | 
					 | 
				
			||||||
            .build()
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const val CONTENT_TYPE = "Content-Type"
 | 
					const val CONTENT_TYPE = "Content-Type"
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,27 @@
 | 
				
			||||||
 | 
					package guru.core.analytics.data.api.cronet
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import guru.core.analytics.handler.AnalyticsCode
 | 
				
			||||||
 | 
					import guru.core.analytics.handler.EventHandler
 | 
				
			||||||
 | 
					import okhttp3.Interceptor
 | 
				
			||||||
 | 
					import okhttp3.Response
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class CastboxCronetInterceptor : Interceptor {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    override fun intercept(chain: Interceptor.Chain): Response {
 | 
				
			||||||
 | 
					        val originalRequest = chain.request()
 | 
				
			||||||
 | 
					        return if (CronetHelper.cronetInterceptor != null) {
 | 
				
			||||||
 | 
					            return try {
 | 
				
			||||||
 | 
					                CronetHelper.cronetInterceptor!!.intercept(chain)
 | 
				
			||||||
 | 
					            } catch (e: Exception) {
 | 
				
			||||||
 | 
					                EventHandler.INSTANCE.notifyEventHandler(
 | 
				
			||||||
 | 
					                    AnalyticsCode.ERROR_CRONET_INTERCEPTOR,
 | 
				
			||||||
 | 
					                    e.message
 | 
				
			||||||
 | 
					                )
 | 
				
			||||||
 | 
					                throw e
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            chain.proceed(originalRequest)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,37 @@
 | 
				
			||||||
 | 
					package guru.core.analytics.data.api.cronet
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import android.content.Context
 | 
				
			||||||
 | 
					import com.google.android.gms.net.CronetProviderInstaller
 | 
				
			||||||
 | 
					import com.google.net.cronet.okhttptransport.CronetInterceptor
 | 
				
			||||||
 | 
					import guru.core.analytics.handler.AnalyticsCode
 | 
				
			||||||
 | 
					import guru.core.analytics.handler.EventHandler
 | 
				
			||||||
 | 
					import org.chromium.net.CronetEngine
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					object CronetHelper {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    var cronetInterceptor: CronetInterceptor? = null
 | 
				
			||||||
 | 
					        private set
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fun init(context: Context, isEnable: Boolean?, callback:((Boolean) -> Unit)? = null) {
 | 
				
			||||||
 | 
					        if (isEnable == true) {
 | 
				
			||||||
 | 
					            try {
 | 
				
			||||||
 | 
					                CronetProviderInstaller.installProvider(context).addOnSuccessListener {
 | 
				
			||||||
 | 
					                    val cronetEngine = CronetEngine.Builder(context).build()
 | 
				
			||||||
 | 
					                    cronetInterceptor = CronetInterceptor.newBuilder(cronetEngine).build()
 | 
				
			||||||
 | 
					                    callback?.invoke(true)
 | 
				
			||||||
 | 
					                    EventHandler.INSTANCE.notifyEventHandler(AnalyticsCode.CRONET_INIT_SUCCESS)
 | 
				
			||||||
 | 
					                }.addOnFailureListener {
 | 
				
			||||||
 | 
					                    cronetInterceptor = null
 | 
				
			||||||
 | 
					                    callback?.invoke(false)
 | 
				
			||||||
 | 
					                    EventHandler.INSTANCE.notifyEventHandler(AnalyticsCode.CRONET_INIT_FAIL, it.message)
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            } catch (e: Exception) {
 | 
				
			||||||
 | 
					                callback?.invoke(false)
 | 
				
			||||||
 | 
					                EventHandler.INSTANCE.notifyEventHandler(AnalyticsCode.CRONET_INIT_EXCEPTION, e.message)
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            cronetInterceptor = null
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -1,28 +1,47 @@
 | 
				
			||||||
package guru.core.analytics.data.api.dns
 | 
					package guru.core.analytics.data.api.dns
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import android.content.Context
 | 
					import android.content.Context
 | 
				
			||||||
 | 
					import com.google.gson.reflect.TypeToken
 | 
				
			||||||
import guru.core.analytics.data.api.ServiceLocator
 | 
					import guru.core.analytics.data.api.ServiceLocator
 | 
				
			||||||
 | 
					import guru.core.analytics.data.local.PreferencesManager
 | 
				
			||||||
import guru.core.analytics.handler.AnalyticsCode
 | 
					import guru.core.analytics.handler.AnalyticsCode
 | 
				
			||||||
import guru.core.analytics.handler.EventHandler
 | 
					import guru.core.analytics.handler.EventHandler
 | 
				
			||||||
 | 
					import guru.core.analytics.utils.GsonUtil
 | 
				
			||||||
import kotlinx.coroutines.runBlocking
 | 
					import kotlinx.coroutines.runBlocking
 | 
				
			||||||
import okhttp3.Dns
 | 
					import okhttp3.Dns
 | 
				
			||||||
import java.net.InetAddress
 | 
					import java.net.InetAddress
 | 
				
			||||||
import java.net.UnknownHostException
 | 
					import java.net.UnknownHostException
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class CustomDns(private val context: Context) : Dns {
 | 
					class CustomDns(private val context: Context, private val uploadIpAddress: List<String>? = null) : Dns {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private val cachedHostAddress by lazy {
 | 
				
			||||||
 | 
					        val hostAddressJson = PreferencesManager.getInstance(context).hostAddressJson
 | 
				
			||||||
 | 
					        return@lazy runCatching {
 | 
				
			||||||
 | 
					            if (!hostAddressJson.isNullOrBlank()) {
 | 
				
			||||||
 | 
					                val mapType = object: TypeToken<Map<String, List<String>>>() {}.type
 | 
				
			||||||
 | 
					                GsonUtil.gson.fromJson(hostAddressJson, mapType) as? MutableMap<String, List<String>>
 | 
				
			||||||
 | 
					            } else null
 | 
				
			||||||
 | 
					        }.getOrNull() ?: mutableMapOf()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override fun lookup(hostname: String): List<InetAddress> {
 | 
					    override fun lookup(hostname: String): List<InetAddress> {
 | 
				
			||||||
        return try {
 | 
					        return try {
 | 
				
			||||||
            Dns.SYSTEM.lookup(hostname)
 | 
					            Dns.SYSTEM.lookup(hostname).also { list ->
 | 
				
			||||||
 | 
					                cacheHostAddress(hostname, list.map { it.hostAddress })
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
        } catch (e: UnknownHostException) {
 | 
					        } catch (e: UnknownHostException) {
 | 
				
			||||||
            try {
 | 
					            try {
 | 
				
			||||||
                lookupByGoogleDns(hostname)
 | 
					                lookupByGoogleDns(hostname)
 | 
				
			||||||
 | 
					            } catch (e: UnknownHostException) {
 | 
				
			||||||
 | 
					                try {
 | 
				
			||||||
 | 
					                    lookupByCacheAndRemote(hostname)
 | 
				
			||||||
                } catch (e: UnknownHostException) {
 | 
					                } catch (e: UnknownHostException) {
 | 
				
			||||||
                    EventHandler.INSTANCE.notifyEventHandler(AnalyticsCode.ERROR_DNS, e.message)
 | 
					                    EventHandler.INSTANCE.notifyEventHandler(AnalyticsCode.ERROR_DNS, e.message)
 | 
				
			||||||
                    lookupByRemoteConfig(hostname)
 | 
					                    lookupByRemoteConfig(hostname)
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private fun lookupByGoogleDns(hostname: String): List<InetAddress> {
 | 
					    private fun lookupByGoogleDns(hostname: String): List<InetAddress> {
 | 
				
			||||||
        val dnsApi = ServiceLocator.provideGoogleDnsApi(context)
 | 
					        val dnsApi = ServiceLocator.provideGoogleDnsApi(context)
 | 
				
			||||||
| 
						 | 
					@ -32,7 +51,11 @@ class CustomDns(private val context: Context) : Dns {
 | 
				
			||||||
                ?.mapNotNull { it.data }
 | 
					                ?.mapNotNull { it.data }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        if (!ipList.isNullOrEmpty()) {
 | 
					        if (!ipList.isNullOrEmpty()) {
 | 
				
			||||||
            return ipList.map { InetAddress.getByAddress(convert(it)) }
 | 
					            cacheHostAddress(hostname, ipList)
 | 
				
			||||||
 | 
					            val resultIpList = ipList.mapNotNull { convert(it) }
 | 
				
			||||||
 | 
					            if (resultIpList.isNotEmpty()) {
 | 
				
			||||||
 | 
					                return resultIpList
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        throw UnknownHostException("Broken Google dns lookup of $hostname")
 | 
					        throw UnknownHostException("Broken Google dns lookup of $hostname")
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -41,13 +64,44 @@ class CustomDns(private val context: Context) : Dns {
 | 
				
			||||||
//        val dnsConfig = RemoteConfig.getDnsConfig()
 | 
					//        val dnsConfig = RemoteConfig.getDnsConfig()
 | 
				
			||||||
//        val ipList = dnsConfig?.get(hostname)
 | 
					//        val ipList = dnsConfig?.get(hostname)
 | 
				
			||||||
//        if (ipList != null && ipList.isNotEmpty()) {
 | 
					//        if (ipList != null && ipList.isNotEmpty()) {
 | 
				
			||||||
//            return ipList.map { InetAddress.getByAddress(convert(it)) }
 | 
					//            return ipList.mapNotNull { convert(it) }
 | 
				
			||||||
//        }
 | 
					//        }
 | 
				
			||||||
        throw UnknownHostException("Broken remote config lookup of $hostname")
 | 
					        throw UnknownHostException("Broken remote config lookup of $hostname")
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private fun convert(ip: String): ByteArray {
 | 
					    private fun convert(ip: String): InetAddress? {
 | 
				
			||||||
        val ipArray = ip.split(".").map { Integer.parseInt(it).toByte() }
 | 
					        return runCatching {
 | 
				
			||||||
        return ipArray.toByteArray()
 | 
					            val byteArr = ip.split(".").map { Integer.parseInt(it).toByte() }.toByteArray()
 | 
				
			||||||
 | 
					            InetAddress.getByAddress(byteArr)
 | 
				
			||||||
 | 
					        }.getOrNull()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private fun cacheHostAddress(hostname: String, hostAddressList: List<String?>) {
 | 
				
			||||||
 | 
					        val addressList = hostAddressList.filterNotNull()
 | 
				
			||||||
 | 
					        if (addressList.isEmpty()) return
 | 
				
			||||||
 | 
					        try {
 | 
				
			||||||
 | 
					            val cacheHostAddressList = cachedHostAddress[hostname]?.sorted()
 | 
				
			||||||
 | 
					            if (addressList.sorted() != cacheHostAddressList) {
 | 
				
			||||||
 | 
					                cachedHostAddress[hostname] = addressList
 | 
				
			||||||
 | 
					                PreferencesManager.getInstance(context).hostAddressJson = GsonUtil.gson.toJson(cachedHostAddress)
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        } catch (e: Exception) {
 | 
				
			||||||
 | 
					            EventHandler.INSTANCE.notifyEventHandler(AnalyticsCode.ERROR_DNS_CACHE, e.message)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private fun lookupByCacheAndRemote(hostname: String): List<InetAddress> {
 | 
				
			||||||
 | 
					        val ipList = uploadIpAddress?.toMutableList() ?: mutableListOf()
 | 
				
			||||||
 | 
					        val cacheIpList = cachedHostAddress[hostname]
 | 
				
			||||||
 | 
					        if (!cacheIpList.isNullOrEmpty()) {
 | 
				
			||||||
 | 
					            ipList.addAll(cacheIpList)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (ipList.isNotEmpty()) {
 | 
				
			||||||
 | 
					            val resultIpList = ipList.mapNotNull { convert(it) }
 | 
				
			||||||
 | 
					            if (resultIpList.isNotEmpty()) {
 | 
				
			||||||
 | 
					                return resultIpList
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        throw UnknownHostException("Broken cache dns lookup of $hostname")
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -48,4 +48,5 @@ class PreferencesManager private constructor(
 | 
				
			||||||
    var eventCountUploaded: Int? by bind("event_count_uploaded", 0)
 | 
					    var eventCountUploaded: Int? by bind("event_count_uploaded", 0)
 | 
				
			||||||
    var uploadEventBaseUrl: String? by bind("update_event_base_url", "")
 | 
					    var uploadEventBaseUrl: String? by bind("update_event_base_url", "")
 | 
				
			||||||
    var totalDurationFgEvent: Long? by bind("total_duration_fg_event", 0L)
 | 
					    var totalDurationFgEvent: Long? by bind("total_duration_fg_event", 0L)
 | 
				
			||||||
 | 
					    var hostAddressJson: String? by bind("host_address", "")
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -14,4 +14,6 @@ internal data class AnalyticsInfo(
 | 
				
			||||||
    var xAppId: String? = null,
 | 
					    var xAppId: String? = null,
 | 
				
			||||||
    var xDeviceInfo: String? = null,
 | 
					    var xDeviceInfo: String? = null,
 | 
				
			||||||
    var mainProcess: String? = null,
 | 
					    var mainProcess: String? = null,
 | 
				
			||||||
 | 
					    var isEnableCronet: Boolean? = null,
 | 
				
			||||||
 | 
					    var uploadIpAddress: List<String>? = null,
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,59 @@
 | 
				
			||||||
 | 
					package guru.core.analytics.data.model
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import androidx.annotation.Keep
 | 
				
			||||||
 | 
					import com.google.gson.annotations.SerializedName
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@Keep
 | 
				
			||||||
 | 
					data class GuruAnalyticsAuditSnapshot(
 | 
				
			||||||
 | 
					    @SerializedName("initialized") val initialized: Boolean = false,
 | 
				
			||||||
 | 
					    @SerializedName("engineInitialized") val engineInitialized: Boolean = false,
 | 
				
			||||||
 | 
					    @SerializedName("useCronet") val useCronet: Boolean = false,
 | 
				
			||||||
 | 
					    @SerializedName("eventDispatcherStarted") val eventDispatcherStarted: Boolean = false,
 | 
				
			||||||
 | 
					    @SerializedName("fgHelperInitialized") val fgHelperInitialized: Boolean = false,
 | 
				
			||||||
 | 
					    @SerializedName("connectionState") val connectionState: Boolean = false,
 | 
				
			||||||
 | 
					    @SerializedName("total") val total: Int = 0,
 | 
				
			||||||
 | 
					    @SerializedName("deleted") val deleted: Int = 0,
 | 
				
			||||||
 | 
					    @SerializedName("uploaded") val uploaded: Int = 0,
 | 
				
			||||||
 | 
					    @SerializedName("sessionUploaded") val sessionUploaded: Int = 0,
 | 
				
			||||||
 | 
					    @SerializedName("sessionDeleted") val sessionDeleted: Int = 0,
 | 
				
			||||||
 | 
					    @SerializedName("sessionTotal") val sessionTotal: Int = 0,
 | 
				
			||||||
 | 
					    @SerializedName("uploadReady") val uploadReady: Boolean = false,
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					object GuruAnalyticsAudit {
 | 
				
			||||||
 | 
					    var initialized: Boolean = false
 | 
				
			||||||
 | 
					    var engineInitialized: Boolean = false
 | 
				
			||||||
 | 
					    var useCronet: Boolean = false
 | 
				
			||||||
 | 
					    var eventDispatcherStarted: Boolean = false
 | 
				
			||||||
 | 
					    var fgHelperInitialized: Boolean = false
 | 
				
			||||||
 | 
					    var connectionState: Boolean = false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // 整体的
 | 
				
			||||||
 | 
					    var total: Int = 0
 | 
				
			||||||
 | 
					    var deleted: Int = 0
 | 
				
			||||||
 | 
					    var uploaded: Int = 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // 当前这一次
 | 
				
			||||||
 | 
					    var sessionUploaded: Int = 0
 | 
				
			||||||
 | 
					    var sessionDeleted: Int = 0
 | 
				
			||||||
 | 
					    var sessionTotal: Int = 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    var uploadReady: Boolean = false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fun snapshot() = GuruAnalyticsAuditSnapshot(
 | 
				
			||||||
 | 
					        initialized = initialized,
 | 
				
			||||||
 | 
					        engineInitialized = engineInitialized,
 | 
				
			||||||
 | 
					        useCronet = useCronet,
 | 
				
			||||||
 | 
					        eventDispatcherStarted = eventDispatcherStarted,
 | 
				
			||||||
 | 
					        fgHelperInitialized = fgHelperInitialized,
 | 
				
			||||||
 | 
					        connectionState = connectionState,
 | 
				
			||||||
 | 
					        total = total,
 | 
				
			||||||
 | 
					        deleted = deleted,
 | 
				
			||||||
 | 
					        uploaded = uploaded,
 | 
				
			||||||
 | 
					        sessionUploaded = sessionUploaded,
 | 
				
			||||||
 | 
					        sessionDeleted = sessionDeleted,
 | 
				
			||||||
 | 
					        sessionTotal = sessionTotal,
 | 
				
			||||||
 | 
					        uploadReady = uploadReady
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -10,6 +10,7 @@ import guru.core.analytics.utils.DateTimeUtils
 | 
				
			||||||
import guru.core.analytics.utils.GsonUtil
 | 
					import guru.core.analytics.utils.GsonUtil
 | 
				
			||||||
import io.reactivex.subjects.BehaviorSubject
 | 
					import io.reactivex.subjects.BehaviorSubject
 | 
				
			||||||
import java.util.*
 | 
					import java.util.*
 | 
				
			||||||
 | 
					import java.util.concurrent.ConcurrentHashMap
 | 
				
			||||||
 | 
					
 | 
				
			||||||
object EventInfoStore {
 | 
					object EventInfoStore {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -18,9 +19,11 @@ object EventInfoStore {
 | 
				
			||||||
        UUID.randomUUID().toString()
 | 
					        UUID.randomUUID().toString()
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private val propertiesSubject: BehaviorSubject<LinkedHashMap<String, String>> =
 | 
					    private val propertiesSubject: BehaviorSubject<ConcurrentHashMap<String, String>> =
 | 
				
			||||||
        BehaviorSubject.createDefault(
 | 
					        BehaviorSubject.createDefault(
 | 
				
			||||||
            linkedMapOf()
 | 
					            ConcurrentHashMap<String, String>().apply {
 | 
				
			||||||
 | 
					                this[Constants.Properties.GURU_ANM] = Constants.AnmState.DEFAULT
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private val supplementEventParamsSubject: BehaviorSubject<Map<String, Any>> =
 | 
					    private val supplementEventParamsSubject: BehaviorSubject<Map<String, Any>> =
 | 
				
			||||||
| 
						 | 
					@ -39,8 +42,8 @@ object EventInfoStore {
 | 
				
			||||||
            idsSubject.onNext(value)
 | 
					            idsSubject.onNext(value)
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private var properties: LinkedHashMap<String, String>
 | 
					    var properties: ConcurrentHashMap<String, String>
 | 
				
			||||||
        get() = propertiesSubject.value ?: linkedMapOf()
 | 
					        get() = propertiesSubject.value ?: ConcurrentHashMap()
 | 
				
			||||||
        set(value) {
 | 
					        set(value) {
 | 
				
			||||||
            propertiesSubject.onNext(value)
 | 
					            propertiesSubject.onNext(value)
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
| 
						 | 
					@ -104,7 +107,12 @@ object EventInfoStore {
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fun deriveEvent(event: EventItem, priority: Int = EventPriority.DEFAULT, uploading: Boolean = false): EventEntity {
 | 
					    fun deriveEvent(
 | 
				
			||||||
 | 
					        event: EventItem,
 | 
				
			||||||
 | 
					        priority: Int = EventPriority.DEFAULT,
 | 
				
			||||||
 | 
					        uploading: Boolean = false,
 | 
				
			||||||
 | 
					        elapsed: Long = 0
 | 
				
			||||||
 | 
					    ): EventEntity {
 | 
				
			||||||
        val eventMap = mutableMapOf<String, ParamValue>()
 | 
					        val eventMap = mutableMapOf<String, ParamValue>()
 | 
				
			||||||
        if (!event.itemCategory.isNullOrBlank()) {
 | 
					        if (!event.itemCategory.isNullOrBlank()) {
 | 
				
			||||||
            eventMap[Constants.Event.ITEM_CATEGORY] = ParamValue(s = event.itemCategory)
 | 
					            eventMap[Constants.Event.ITEM_CATEGORY] = ParamValue(s = event.itemCategory)
 | 
				
			||||||
| 
						 | 
					@ -124,8 +132,9 @@ object EventInfoStore {
 | 
				
			||||||
            eventMap[entry.key] = createParamValue(entry.value)
 | 
					            eventMap[entry.key] = createParamValue(entry.value)
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        val eventId = UUID.randomUUID().toString()
 | 
					        val eventId = UUID.randomUUID().toString()
 | 
				
			||||||
 | 
					        val eventTs = DateTimeUtils.eventAt() - elapsed
 | 
				
			||||||
        val eventData = Event(
 | 
					        val eventData = Event(
 | 
				
			||||||
            timestamp = DateTimeUtils.eventAt(),
 | 
					            timestamp = eventTs,
 | 
				
			||||||
            info = ids,
 | 
					            info = ids,
 | 
				
			||||||
            event = event.eventName,
 | 
					            event = event.eventName,
 | 
				
			||||||
            param = eventMap,
 | 
					            param = eventMap,
 | 
				
			||||||
| 
						 | 
					@ -139,7 +148,7 @@ object EventInfoStore {
 | 
				
			||||||
            json = eventJson,
 | 
					            json = eventJson,
 | 
				
			||||||
            ext = "",
 | 
					            ext = "",
 | 
				
			||||||
            status = if (uploading) 1 else 0,
 | 
					            status = if (uploading) 1 else 0,
 | 
				
			||||||
            at = DateTimeUtils.eventAt(),
 | 
					            at = eventTs,
 | 
				
			||||||
            version = Constants.VERSION,
 | 
					            version = Constants.VERSION,
 | 
				
			||||||
            event = event.eventName,
 | 
					            event = event.eventName,
 | 
				
			||||||
            priority = priority
 | 
					            priority = priority
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -9,11 +9,15 @@ enum class AnalyticsCode(val code: Int) {
 | 
				
			||||||
    UPLOAD_SUCCESS(13),         // 上报事件成功
 | 
					    UPLOAD_SUCCESS(13),         // 上报事件成功
 | 
				
			||||||
    UPLOAD_FAIL(14),            // 上报事件失败
 | 
					    UPLOAD_FAIL(14),            // 上报事件失败
 | 
				
			||||||
    PERIODIC_WORK_ENQUEUE(15),  // 开启PeriodicWork
 | 
					    PERIODIC_WORK_ENQUEUE(15),  // 开启PeriodicWork
 | 
				
			||||||
 | 
					    ENABLE_UPLOAD(16),          // 修改是否允许上传埋点状态
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    NETWORK_AVAILABLE(21),      // 网络状态可用
 | 
					    NETWORK_AVAILABLE(21),      // 网络状态可用
 | 
				
			||||||
    NETWORK_LOST(22),           // 网络状态不可用
 | 
					    NETWORK_LOST(22),           // 网络状态不可用
 | 
				
			||||||
    LIFECYCLE_START(23),        // app可见
 | 
					    LIFECYCLE_START(23),        // app可见
 | 
				
			||||||
    LIFECYCLE_PAUSE(24),        // app不可见
 | 
					    LIFECYCLE_PAUSE(24),        // app不可见
 | 
				
			||||||
 | 
					    CRONET_INIT_SUCCESS(25),    // 开启Cronet成功
 | 
				
			||||||
 | 
					    CRONET_INIT_FAIL(26),       // 开启Cronet失败
 | 
				
			||||||
 | 
					    CRONET_INIT_EXCEPTION(27),  // 开启Cronet报错
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ERROR_API(101),              // 调用api出错
 | 
					    ERROR_API(101),              // 调用api出错
 | 
				
			||||||
    ERROR_RESPONSE(102),         // api返回结果错误
 | 
					    ERROR_RESPONSE(102),         // api返回结果错误
 | 
				
			||||||
| 
						 | 
					@ -22,7 +26,20 @@ enum class AnalyticsCode(val code: Int) {
 | 
				
			||||||
    ERROR_LOAD_MARK(105),        // 从数据库取事件以及更改事件状态为正在上报出错
 | 
					    ERROR_LOAD_MARK(105),        // 从数据库取事件以及更改事件状态为正在上报出错
 | 
				
			||||||
    ERROR_DNS(106),              // dns 错误
 | 
					    ERROR_DNS(106),              // dns 错误
 | 
				
			||||||
    ERROR_ZIP(107),              // zip 错误
 | 
					    ERROR_ZIP(107),              // zip 错误
 | 
				
			||||||
 | 
					    ERROR_DNS_CACHE(108),        // zip 错误
 | 
				
			||||||
 | 
					    ERROR_CRONET_INTERCEPTOR(109),// cronet拦截器
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    EVENT_FIRST_OPEN(1001),       // first_open 事件
 | 
					    EVENT_FIRST_OPEN(1001),       // first_open 事件
 | 
				
			||||||
    EVENT_FG(1002),               // fg 事件
 | 
					    EVENT_FG(1002),               // fg 事件
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // 初始化进度
 | 
				
			||||||
 | 
					    INIT_STEP_1(100001),
 | 
				
			||||||
 | 
					    INIT_STEP_2(100002),
 | 
				
			||||||
 | 
					    INIT_STEP_3(100003),
 | 
				
			||||||
 | 
					    INIT_STEP_4(100004),
 | 
				
			||||||
 | 
					    INIT_STEP_5(100005),
 | 
				
			||||||
 | 
					    INIT_STEP_6(100006),
 | 
				
			||||||
 | 
					    INIT_STEP_7(100007),
 | 
				
			||||||
 | 
					    INIT_STEP_8(100008),
 | 
				
			||||||
 | 
					    INIT_STEP_9(100009),
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -1,16 +1,26 @@
 | 
				
			||||||
package guru.core.analytics.impl
 | 
					package guru.core.analytics.impl
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import android.os.SystemClock
 | 
				
			||||||
import guru.core.analytics.data.db.GuruAnalyticsDatabase
 | 
					import guru.core.analytics.data.db.GuruAnalyticsDatabase
 | 
				
			||||||
import guru.core.analytics.data.model.AnalyticsOptions
 | 
					import guru.core.analytics.data.model.AnalyticsOptions
 | 
				
			||||||
import guru.core.analytics.data.model.EventItem
 | 
					import guru.core.analytics.data.model.EventItem
 | 
				
			||||||
 | 
					import guru.core.analytics.data.model.GuruAnalyticsAudit
 | 
				
			||||||
import guru.core.analytics.data.store.EventInfoStore
 | 
					import guru.core.analytics.data.store.EventInfoStore
 | 
				
			||||||
import timber.log.Timber
 | 
					import timber.log.Timber
 | 
				
			||||||
import java.util.concurrent.ConcurrentLinkedQueue
 | 
					import java.util.concurrent.ConcurrentLinkedQueue
 | 
				
			||||||
import java.util.concurrent.atomic.AtomicBoolean
 | 
					import java.util.concurrent.atomic.AtomicBoolean
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class PendingEvent(
 | 
				
			||||||
 | 
					    val item: EventItem,
 | 
				
			||||||
 | 
					    val options: AnalyticsOptions
 | 
				
			||||||
 | 
					) {
 | 
				
			||||||
 | 
					    val at = SystemClock.elapsedRealtime()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
object EventDispatcher : EventDeliver {
 | 
					object EventDispatcher : EventDeliver {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private val pendingEvents = ConcurrentLinkedQueue<Pair<EventItem, AnalyticsOptions>>()
 | 
					    private val pendingEvents = ConcurrentLinkedQueue<PendingEvent>()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private val started = AtomicBoolean(false)
 | 
					    private val started = AtomicBoolean(false)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -18,8 +28,12 @@ object EventDispatcher : EventDeliver {
 | 
				
			||||||
        Timber.d("EventDispatcher dispatchPendingEvent ${pendingEvents.size}!")
 | 
					        Timber.d("EventDispatcher dispatchPendingEvent ${pendingEvents.size}!")
 | 
				
			||||||
        if (pendingEvents.isNotEmpty()) {
 | 
					        if (pendingEvents.isNotEmpty()) {
 | 
				
			||||||
            while (true) {
 | 
					            while (true) {
 | 
				
			||||||
                val pair = pendingEvents.poll() ?: return
 | 
					                val pendingEvent = pendingEvents.poll() ?: return
 | 
				
			||||||
                val event = EventInfoStore.deriveEvent(pair.first, priority = pair.second.priority)
 | 
					                val event = EventInfoStore.deriveEvent(
 | 
				
			||||||
 | 
					                    pendingEvent.item,
 | 
				
			||||||
 | 
					                    priority = pendingEvent.options.priority,
 | 
				
			||||||
 | 
					                    elapsed = SystemClock.elapsedRealtime() - pendingEvent.at
 | 
				
			||||||
 | 
					                )
 | 
				
			||||||
                GuruAnalyticsDatabase.getInstance().eventDao().addEvent(event)
 | 
					                GuruAnalyticsDatabase.getInstance().eventDao().addEvent(event)
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
| 
						 | 
					@ -29,6 +43,7 @@ object EventDispatcher : EventDeliver {
 | 
				
			||||||
        if (started.compareAndSet(false, true)) {
 | 
					        if (started.compareAndSet(false, true)) {
 | 
				
			||||||
            Timber.d("EventDispatcher started!")
 | 
					            Timber.d("EventDispatcher started!")
 | 
				
			||||||
            dispatchPendingEvent()
 | 
					            dispatchPendingEvent()
 | 
				
			||||||
 | 
					            GuruAnalyticsAudit.eventDispatcherStarted = true
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -40,7 +55,7 @@ object EventDispatcher : EventDeliver {
 | 
				
			||||||
            GuruAnalyticsDatabase.getInstance().eventDao().addEvent(event)
 | 
					            GuruAnalyticsDatabase.getInstance().eventDao().addEvent(event)
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            Timber.d("EventDispatcher deliverEvent pending!")
 | 
					            Timber.d("EventDispatcher deliverEvent pending!")
 | 
				
			||||||
            pendingEvents.offer(item to options)
 | 
					            pendingEvents.offer(PendingEvent(item, options))
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,6 +1,7 @@
 | 
				
			||||||
package guru.core.analytics.impl
 | 
					package guru.core.analytics.impl
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import android.content.Context
 | 
					import android.content.Context
 | 
				
			||||||
 | 
					import android.net.Uri
 | 
				
			||||||
import guru.core.analytics.Constants
 | 
					import guru.core.analytics.Constants
 | 
				
			||||||
import guru.core.analytics.GuruAnalytics
 | 
					import guru.core.analytics.GuruAnalytics
 | 
				
			||||||
import guru.core.analytics.data.api.GuruRepository
 | 
					import guru.core.analytics.data.api.GuruRepository
 | 
				
			||||||
| 
						 | 
					@ -12,6 +13,7 @@ import guru.core.analytics.data.db.model.EventStatistic
 | 
				
			||||||
import guru.core.analytics.data.local.PreferencesManager
 | 
					import guru.core.analytics.data.local.PreferencesManager
 | 
				
			||||||
import guru.core.analytics.data.model.AnalyticsOptions
 | 
					import guru.core.analytics.data.model.AnalyticsOptions
 | 
				
			||||||
import guru.core.analytics.data.model.EventItem
 | 
					import guru.core.analytics.data.model.EventItem
 | 
				
			||||||
 | 
					import guru.core.analytics.data.model.GuruAnalyticsAudit
 | 
				
			||||||
import guru.core.analytics.data.store.EventInfoStore
 | 
					import guru.core.analytics.data.store.EventInfoStore
 | 
				
			||||||
import guru.core.analytics.handler.AnalyticsCode
 | 
					import guru.core.analytics.handler.AnalyticsCode
 | 
				
			||||||
import guru.core.analytics.handler.EventHandler
 | 
					import guru.core.analytics.handler.EventHandler
 | 
				
			||||||
| 
						 | 
					@ -39,10 +41,10 @@ internal class EventEngine internal constructor(
 | 
				
			||||||
    private val batchLimit: Int = DEFAULT_BATCH_LIMIT,
 | 
					    private val batchLimit: Int = DEFAULT_BATCH_LIMIT,
 | 
				
			||||||
    private val uploadPeriodInSeconds: Long = DEFAULT_UPLOAD_PERIOD_IN_SECONDS,
 | 
					    private val uploadPeriodInSeconds: Long = DEFAULT_UPLOAD_PERIOD_IN_SECONDS,
 | 
				
			||||||
    private val eventExpiredInDays: Int = DEFAULT_EVENT_EXPIRED_IN_DAYS,
 | 
					    private val eventExpiredInDays: Int = DEFAULT_EVENT_EXPIRED_IN_DAYS,
 | 
				
			||||||
    private val uploadEventBaseUrl: String? = null,
 | 
					    private val uploadEventBaseUri: Uri? = null,
 | 
				
			||||||
) : EventDeliver {
 | 
					) : EventDeliver {
 | 
				
			||||||
    private val guruRepository: GuruRepository by lazy {
 | 
					    private val guruRepository: GuruRepository by lazy {
 | 
				
			||||||
        ServiceLocator.provideGuruRepository(context.applicationContext, baseUrl = uploadEventBaseUrl)
 | 
					        ServiceLocator.provideGuruRepository(context.applicationContext, baseUri = uploadEventBaseUri)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private val preferencesManager by lazy {
 | 
					    private val preferencesManager by lazy {
 | 
				
			||||||
| 
						 | 
					@ -83,6 +85,13 @@ internal class EventEngine internal constructor(
 | 
				
			||||||
    private val forceUploadSubject: PublishSubject<Boolean> = PublishSubject.create()
 | 
					    private val forceUploadSubject: PublishSubject<Boolean> = PublishSubject.create()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private val started = AtomicBoolean(false)
 | 
					    private val started = AtomicBoolean(false)
 | 
				
			||||||
 | 
					    private var enableUpload = true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fun setEnableUpload(enable: Boolean) {
 | 
				
			||||||
 | 
					        enableUpload = enable
 | 
				
			||||||
 | 
					        val extMap = mapOf("enable" to enable)
 | 
				
			||||||
 | 
					        EventHandler.INSTANCE.notifyEventHandler(AnalyticsCode.ENABLE_UPLOAD, extMap)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fun start(startUploadDelay: Long?) {
 | 
					    fun start(startUploadDelay: Long?) {
 | 
				
			||||||
        if (started.compareAndSet(false, true)) {
 | 
					        if (started.compareAndSet(false, true)) {
 | 
				
			||||||
| 
						 | 
					@ -96,6 +105,7 @@ internal class EventEngine internal constructor(
 | 
				
			||||||
                val extMap = mapOf("startUploadDelayInSecond" to startUploadDelay)
 | 
					                val extMap = mapOf("startUploadDelayInSecond" to startUploadDelay)
 | 
				
			||||||
                EventHandler.INSTANCE.notifyEventHandler(AnalyticsCode.STATE_START_WORK, extMap)
 | 
					                EventHandler.INSTANCE.notifyEventHandler(AnalyticsCode.STATE_START_WORK, extMap)
 | 
				
			||||||
            }, startUploadDelay ?: 0, TimeUnit.SECONDS)
 | 
					            }, startUploadDelay ?: 0, TimeUnit.SECONDS)
 | 
				
			||||||
 | 
					            GuruAnalyticsAudit.engineInitialized = true
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -146,6 +156,7 @@ internal class EventEngine internal constructor(
 | 
				
			||||||
                    logDebug("pendingEvent ${it.size}")
 | 
					                    logDebug("pendingEvent ${it.size}")
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
        val networkFlowable = ConnectionStateMonitor.connectStateFlowable.doOnNext {
 | 
					        val networkFlowable = ConnectionStateMonitor.connectStateFlowable.doOnNext {
 | 
				
			||||||
 | 
					            GuruAnalyticsAudit.connectionState = it
 | 
				
			||||||
            logDebug("network $it")
 | 
					            logDebug("network $it")
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        val forceFlowable = forceUploadSubject.toFlowable(BackpressureStrategy.DROP)
 | 
					        val forceFlowable = forceUploadSubject.toFlowable(BackpressureStrategy.DROP)
 | 
				
			||||||
| 
						 | 
					@ -157,6 +168,7 @@ internal class EventEngine internal constructor(
 | 
				
			||||||
                logDebug("pollEvent filter $it")
 | 
					                logDebug("pollEvent filter $it")
 | 
				
			||||||
                return@filter it
 | 
					                return@filter it
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					            .filter { enableUpload }
 | 
				
			||||||
            .flatMap { uploadEvents(500) }
 | 
					            .flatMap { uploadEvents(500) }
 | 
				
			||||||
            .subscribe()
 | 
					            .subscribe()
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
| 
						 | 
					@ -174,7 +186,10 @@ internal class EventEngine internal constructor(
 | 
				
			||||||
            // 记录删除的事件数量
 | 
					            // 记录删除的事件数量
 | 
				
			||||||
            if (pair.first > 0) {
 | 
					            if (pair.first > 0) {
 | 
				
			||||||
                val eventCountDeleted = preferencesManager.eventCountDeleted ?: 0
 | 
					                val eventCountDeleted = preferencesManager.eventCountDeleted ?: 0
 | 
				
			||||||
                preferencesManager.eventCountDeleted = eventCountDeleted + pair.first
 | 
					                val deleted = eventCountDeleted + pair.first
 | 
				
			||||||
 | 
					                preferencesManager.eventCountDeleted = deleted
 | 
				
			||||||
 | 
					                GuruAnalyticsAudit.deleted = deleted
 | 
				
			||||||
 | 
					                GuruAnalyticsAudit.sessionDeleted += pair.first
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                val extMap = mapOf(
 | 
					                val extMap = mapOf(
 | 
				
			||||||
                    "expiredCount" to pair.first,
 | 
					                    "expiredCount" to pair.first,
 | 
				
			||||||
| 
						 | 
					@ -192,6 +207,7 @@ internal class EventEngine internal constructor(
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    internal fun uploadEvents(count: Int): Flowable<List<EventEntity>> {
 | 
					    internal fun uploadEvents(count: Int): Flowable<List<EventEntity>> {
 | 
				
			||||||
        val eventDao = GuruAnalyticsDatabase.getInstance().eventDao()
 | 
					        val eventDao = GuruAnalyticsDatabase.getInstance().eventDao()
 | 
				
			||||||
 | 
					        GuruAnalyticsAudit.uploadReady = true
 | 
				
			||||||
        logDebug("uploadEvents: $count")
 | 
					        logDebug("uploadEvents: $count")
 | 
				
			||||||
        return Flowable.just(count).map { eventDao.loadAndMarkUploadEvents(it) }
 | 
					        return Flowable.just(count).map { eventDao.loadAndMarkUploadEvents(it) }
 | 
				
			||||||
            .onErrorReturn {
 | 
					            .onErrorReturn {
 | 
				
			||||||
| 
						 | 
					@ -232,7 +248,10 @@ internal class EventEngine internal constructor(
 | 
				
			||||||
            .doOnSuccess {
 | 
					            .doOnSuccess {
 | 
				
			||||||
                // 记录上传成功的数量
 | 
					                // 记录上传成功的数量
 | 
				
			||||||
                val eventCountUploaded = preferencesManager.eventCountUploaded ?: 0
 | 
					                val eventCountUploaded = preferencesManager.eventCountUploaded ?: 0
 | 
				
			||||||
                preferencesManager.eventCountUploaded = eventCountUploaded + entities.size
 | 
					                val uploaded = eventCountUploaded + entities.size
 | 
				
			||||||
 | 
					                preferencesManager.eventCountUploaded = uploaded
 | 
				
			||||||
 | 
					                GuruAnalyticsAudit.uploaded = uploaded
 | 
				
			||||||
 | 
					                GuruAnalyticsAudit.sessionUploaded += entities.size
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                val extMap = mapOf(
 | 
					                val extMap = mapOf(
 | 
				
			||||||
                    "count" to entities.size,
 | 
					                    "count" to entities.size,
 | 
				
			||||||
| 
						 | 
					@ -288,7 +307,10 @@ internal class EventEngine internal constructor(
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private fun increaseEventCount() {
 | 
					    private fun increaseEventCount() {
 | 
				
			||||||
        val eventCountAll = preferencesManager.eventCountAll ?: 0
 | 
					        val eventCountAll = preferencesManager.eventCountAll ?: 0
 | 
				
			||||||
        preferencesManager.eventCountAll = eventCountAll + 1
 | 
					        val total = eventCountAll + 1
 | 
				
			||||||
 | 
					        preferencesManager.eventCountAll = total
 | 
				
			||||||
 | 
					        GuruAnalyticsAudit.total = total
 | 
				
			||||||
 | 
					        GuruAnalyticsAudit.sessionTotal ++
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override fun deliverProperty(name: String, value: String) {
 | 
					    override fun deliverProperty(name: String, value: String) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -5,6 +5,7 @@ import android.os.SystemClock
 | 
				
			||||||
import guru.core.analytics.Constants
 | 
					import guru.core.analytics.Constants
 | 
				
			||||||
import guru.core.analytics.GuruAnalytics
 | 
					import guru.core.analytics.GuruAnalytics
 | 
				
			||||||
import guru.core.analytics.data.local.PreferencesManager
 | 
					import guru.core.analytics.data.local.PreferencesManager
 | 
				
			||||||
 | 
					import guru.core.analytics.data.model.GuruAnalyticsAudit
 | 
				
			||||||
import guru.core.analytics.handler.AnalyticsCode
 | 
					import guru.core.analytics.handler.AnalyticsCode
 | 
				
			||||||
import guru.core.analytics.handler.EventHandler
 | 
					import guru.core.analytics.handler.EventHandler
 | 
				
			||||||
import io.reactivex.Flowable
 | 
					import io.reactivex.Flowable
 | 
				
			||||||
| 
						 | 
					@ -75,6 +76,7 @@ internal class FgHelper(context: Context) {
 | 
				
			||||||
            }, {
 | 
					            }, {
 | 
				
			||||||
                Timber.tag("FgHelper").e(it)
 | 
					                Timber.tag("FgHelper").e(it)
 | 
				
			||||||
            })
 | 
					            })
 | 
				
			||||||
 | 
					        GuruAnalyticsAudit.fgHelperInitialized = true
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fun stop() {
 | 
					    fun stop() {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,16 +1,19 @@
 | 
				
			||||||
package guru.core.analytics.impl
 | 
					package guru.core.analytics.impl
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import android.content.Context
 | 
					import android.content.Context
 | 
				
			||||||
 | 
					import android.net.Uri
 | 
				
			||||||
import androidx.annotation.RequiresPermission
 | 
					import androidx.annotation.RequiresPermission
 | 
				
			||||||
import androidx.work.*
 | 
					import androidx.work.*
 | 
				
			||||||
import guru.core.analytics.Constants
 | 
					import guru.core.analytics.Constants
 | 
				
			||||||
import guru.core.analytics.GuruAnalytics
 | 
					import guru.core.analytics.GuruAnalytics
 | 
				
			||||||
import guru.core.analytics.data.api.ServiceLocator
 | 
					import guru.core.analytics.data.api.ServiceLocator
 | 
				
			||||||
 | 
					import guru.core.analytics.data.api.cronet.CronetHelper
 | 
				
			||||||
import guru.core.analytics.data.db.GuruAnalyticsDatabase
 | 
					import guru.core.analytics.data.db.GuruAnalyticsDatabase
 | 
				
			||||||
import guru.core.analytics.data.db.model.EventStatistic
 | 
					import guru.core.analytics.data.db.model.EventStatistic
 | 
				
			||||||
import guru.core.analytics.data.local.PreferencesManager
 | 
					import guru.core.analytics.data.local.PreferencesManager
 | 
				
			||||||
import guru.core.analytics.data.model.AnalyticsOptions
 | 
					import guru.core.analytics.data.model.AnalyticsOptions
 | 
				
			||||||
import guru.core.analytics.data.model.EventItem
 | 
					import guru.core.analytics.data.model.EventItem
 | 
				
			||||||
 | 
					import guru.core.analytics.data.model.GuruAnalyticsAudit
 | 
				
			||||||
import guru.core.analytics.data.store.DeviceInfoStore
 | 
					import guru.core.analytics.data.store.DeviceInfoStore
 | 
				
			||||||
import guru.core.analytics.data.store.EventInfoStore
 | 
					import guru.core.analytics.data.store.EventInfoStore
 | 
				
			||||||
import guru.core.analytics.handler.AnalyticsCode
 | 
					import guru.core.analytics.handler.AnalyticsCode
 | 
				
			||||||
| 
						 | 
					@ -18,6 +21,7 @@ import guru.core.analytics.handler.EventHandler
 | 
				
			||||||
import guru.core.analytics.log.PersistentTree
 | 
					import guru.core.analytics.log.PersistentTree
 | 
				
			||||||
import guru.core.analytics.utils.AndroidUtils
 | 
					import guru.core.analytics.utils.AndroidUtils
 | 
				
			||||||
import guru.core.analytics.utils.EventChecker
 | 
					import guru.core.analytics.utils.EventChecker
 | 
				
			||||||
 | 
					import guru.core.analytics.utils.GsonUtil
 | 
				
			||||||
import guru.core.analytics.utils.SystemProperties
 | 
					import guru.core.analytics.utils.SystemProperties
 | 
				
			||||||
import timber.log.Timber
 | 
					import timber.log.Timber
 | 
				
			||||||
import java.io.File
 | 
					import java.io.File
 | 
				
			||||||
| 
						 | 
					@ -75,24 +79,55 @@ internal class GuruAnalyticsImpl : GuruAnalytics() {
 | 
				
			||||||
        fgEventPeriodInSeconds: Long?,
 | 
					        fgEventPeriodInSeconds: Long?,
 | 
				
			||||||
        xAppId: String?,
 | 
					        xAppId: String?,
 | 
				
			||||||
        xDeviceInfo: String?,
 | 
					        xDeviceInfo: String?,
 | 
				
			||||||
        mainProcess: String?
 | 
					        mainProcess: String?,
 | 
				
			||||||
 | 
					        isEnableCronet: Boolean?,
 | 
				
			||||||
 | 
					        uploadIpAddress: List<String>?,
 | 
				
			||||||
    ) {
 | 
					    ) {
 | 
				
			||||||
        if (initialized.compareAndSet(false, true)) {
 | 
					        if (initialized.compareAndSet(false, true)) {
 | 
				
			||||||
            delivers.add(EventDispatcher)
 | 
					            delivers.add(EventDispatcher)
 | 
				
			||||||
            eventHandlerCallback?.let { EventHandler.INSTANCE.addEventHandler(it) }
 | 
					            eventHandlerCallback?.let { EventHandler.INSTANCE.addEventHandler(it) }
 | 
				
			||||||
 | 
					            EventHandler.INSTANCE.notifyEventHandler(AnalyticsCode.INIT_STEP_1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            val debugApp = SystemProperties.read("debug.guru.analytics.app")
 | 
					            val debugApp = SystemProperties.read("debug.guru.analytics.app")
 | 
				
			||||||
            val forceDebug = debugApp == context.packageName
 | 
					            val forceDebug = debugApp == context.packageName
 | 
				
			||||||
            if (forceDebug || persistableLog) {
 | 
					            if (forceDebug || persistableLog) {
 | 
				
			||||||
                Timber.plant(PersistentTree(context, debug = debug))
 | 
					                Timber.plant(PersistentTree(context, debug = debug))
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            debugMode = debug
 | 
					            EventHandler.INSTANCE.notifyEventHandler(AnalyticsCode.INIT_STEP_2)
 | 
				
			||||||
            Timber.d("[$internalVersion]initialize batchLimit:$batchLimit uploadPeriodInSecond:$uploadPeriodInSeconds startUploadDelayInSecond:$startUploadDelayInSecond eventExpiredInDays:$eventExpiredInDays debug:$debug")
 | 
					
 | 
				
			||||||
 | 
					            val debugUrl = SystemProperties.read("debug.guru.analytics.url")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            debugMode = forceDebug || debug
 | 
				
			||||||
 | 
					            Timber.d("[$internalVersion]initialize batchLimit:$batchLimit uploadPeriodInSecond:$uploadPeriodInSeconds startUploadDelayInSecond:$startUploadDelayInSecond eventExpiredInDays:$eventExpiredInDays debug:$debugMode debugUrl:$debugUrl")
 | 
				
			||||||
            GuruAnalyticsDatabase.initialize(context.applicationContext)
 | 
					            GuruAnalyticsDatabase.initialize(context.applicationContext)
 | 
				
			||||||
 | 
					            EventHandler.INSTANCE.notifyEventHandler(AnalyticsCode.INIT_STEP_3)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            val baseUrl = if (forceDebug && debugUrl.isNotEmpty()) debugUrl else uploadEventBaseUrl
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            DeviceInfoStore.setDeviceInfo(context)
 | 
					            DeviceInfoStore.setDeviceInfo(context)
 | 
				
			||||||
            ServiceLocator.setDebug(debug)
 | 
					            ServiceLocator.setDebug(debug)
 | 
				
			||||||
            ServiceLocator.addHeaderParam("X-APP-ID", xAppId)
 | 
					            ServiceLocator.addHeaderParam("X-APP-ID", xAppId)
 | 
				
			||||||
            ServiceLocator.addHeaderParam("X-DEVICE-INFO", xDeviceInfo)
 | 
					            ServiceLocator.addHeaderParam("X-DEVICE-INFO", xDeviceInfo)
 | 
				
			||||||
 | 
					            ServiceLocator.setUploadIpAddress(uploadIpAddress)
 | 
				
			||||||
 | 
					            EventHandler.INSTANCE.notifyEventHandler(AnalyticsCode.INIT_STEP_4)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            CronetHelper.init(context, isEnableCronet) {
 | 
				
			||||||
 | 
					                if (it) {
 | 
				
			||||||
 | 
					                    setUserProperty(Constants.Properties.GURU_ANM, Constants.AnmState.CRONET)
 | 
				
			||||||
 | 
					                    GuruAnalyticsAudit.useCronet = true
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            EventHandler.INSTANCE.notifyEventHandler(AnalyticsCode.INIT_STEP_5)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var uploadEventBaseUri: Uri? = null
 | 
				
			||||||
 | 
					            if (!baseUrl.isNullOrBlank()) {
 | 
				
			||||||
 | 
					                uploadEventBaseUri =
 | 
				
			||||||
 | 
					                    kotlin.runCatching { Uri.parse(baseUrl) }.getOrNull()
 | 
				
			||||||
 | 
					                if (uploadEventBaseUri?.scheme?.startsWith("http") != true) {
 | 
				
			||||||
 | 
					                    throw IllegalArgumentException("initialize updateEventBaseUrl:${baseUrl} incorrect format")
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            EventHandler.INSTANCE.notifyEventHandler(AnalyticsCode.INIT_STEP_6)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            engine = EventEngine(
 | 
					            engine = EventEngine(
 | 
				
			||||||
                context,
 | 
					                context,
 | 
				
			||||||
| 
						 | 
					@ -102,10 +137,11 @@ internal class GuruAnalyticsImpl : GuruAnalytics() {
 | 
				
			||||||
                eventExpiredInDays = EventEngine.DEFAULT_EVENT_EXPIRED_IN_DAYS.coerceAtLeast(
 | 
					                eventExpiredInDays = EventEngine.DEFAULT_EVENT_EXPIRED_IN_DAYS.coerceAtLeast(
 | 
				
			||||||
                    eventExpiredInDays ?: EventEngine.DEFAULT_EVENT_EXPIRED_IN_DAYS
 | 
					                    eventExpiredInDays ?: EventEngine.DEFAULT_EVENT_EXPIRED_IN_DAYS
 | 
				
			||||||
                ),
 | 
					                ),
 | 
				
			||||||
                uploadEventBaseUrl = uploadEventBaseUrl,
 | 
					                uploadEventBaseUri = uploadEventBaseUri
 | 
				
			||||||
            ).apply {
 | 
					            ).apply {
 | 
				
			||||||
                start(startUploadDelayInSecond)
 | 
					 | 
				
			||||||
                delivers.add(this)
 | 
					                delivers.add(this)
 | 
				
			||||||
 | 
					                start(startUploadDelayInSecond)
 | 
				
			||||||
 | 
					                EventHandler.INSTANCE.notifyEventHandler(AnalyticsCode.INIT_STEP_7)
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            if (isInitPeriodicWork) {
 | 
					            if (isInitPeriodicWork) {
 | 
				
			||||||
                val process = AndroidUtils.getProcessName(context)
 | 
					                val process = AndroidUtils.getProcessName(context)
 | 
				
			||||||
| 
						 | 
					@ -120,6 +156,7 @@ internal class GuruAnalyticsImpl : GuruAnalytics() {
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					            EventHandler.INSTANCE.notifyEventHandler(AnalyticsCode.INIT_STEP_8)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            val extMap = mapOf(
 | 
					            val extMap = mapOf(
 | 
				
			||||||
                "version_code" to internalVersion,
 | 
					                "version_code" to internalVersion,
 | 
				
			||||||
| 
						 | 
					@ -127,12 +164,17 @@ internal class GuruAnalyticsImpl : GuruAnalytics() {
 | 
				
			||||||
                "uploadPeriodInSecond" to uploadPeriodInSeconds,
 | 
					                "uploadPeriodInSecond" to uploadPeriodInSeconds,
 | 
				
			||||||
                "startUploadDelayInSecond" to startUploadDelayInSecond,
 | 
					                "startUploadDelayInSecond" to startUploadDelayInSecond,
 | 
				
			||||||
                "eventExpiredInDays" to eventExpiredInDays,
 | 
					                "eventExpiredInDays" to eventExpiredInDays,
 | 
				
			||||||
 | 
					                "uploadEventBaseUri" to uploadEventBaseUri.toString(),
 | 
				
			||||||
 | 
					                "enabledCronet" to (isEnableCronet ?: false),
 | 
				
			||||||
 | 
					                "unloadIpAddress" to (uploadIpAddress?.joinToString("|") ?: ""),
 | 
				
			||||||
                "debug" to debug,
 | 
					                "debug" to debug,
 | 
				
			||||||
            )
 | 
					            )
 | 
				
			||||||
            EventHandler.INSTANCE.notifyEventHandler(AnalyticsCode.STATE_INITIALIZED, extMap)
 | 
					            EventHandler.INSTANCE.notifyEventHandler(AnalyticsCode.STATE_INITIALIZED, extMap)
 | 
				
			||||||
            if (!uploadEventBaseUrl.isNullOrEmpty()) {
 | 
					            if (!uploadEventBaseUrl.isNullOrEmpty()) {
 | 
				
			||||||
                PreferencesManager.getInstance(context).uploadEventBaseUrl = uploadEventBaseUrl
 | 
					                PreferencesManager.getInstance(context).uploadEventBaseUrl = baseUrl
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					            EventHandler.INSTANCE.notifyEventHandler(AnalyticsCode.INIT_STEP_9)
 | 
				
			||||||
 | 
					            GuruAnalyticsAudit.initialized = true
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -265,6 +307,25 @@ internal class GuruAnalyticsImpl : GuruAnalytics() {
 | 
				
			||||||
        removeProperties(keys)
 | 
					        removeProperties(keys)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    override fun getUserProperties(callback: (Map<String, String>) -> Unit) {
 | 
				
			||||||
 | 
					        deliverExecutor.execute {
 | 
				
			||||||
 | 
					            callback.invoke(EventInfoStore.properties)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    override fun peakUserProperties(): Map<String, String> {
 | 
				
			||||||
 | 
					        return EventInfoStore.properties
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    override fun setEnableUpload(enable: Boolean) {
 | 
				
			||||||
 | 
					        engine?.setEnableUpload(enable)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    override fun snapshotAnalyticsAudit(): String {
 | 
				
			||||||
 | 
					        val snapshot = GuruAnalyticsAudit.snapshot()
 | 
				
			||||||
 | 
					        return GsonUtil.gson.toJson(snapshot)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private fun deliverEvent(item: EventItem, options: AnalyticsOptions) {
 | 
					    private fun deliverEvent(item: EventItem, options: AnalyticsOptions) {
 | 
				
			||||||
        Timber.tag("GuruAnalytics").d("deliverEvent ${item.eventName}!")
 | 
					        Timber.tag("GuruAnalytics").d("deliverEvent ${item.eventName}!")
 | 
				
			||||||
        deliverExecutor.execute {
 | 
					        deliverExecutor.execute {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -11,6 +11,7 @@ object ApiParamUtils {
 | 
				
			||||||
     * 组装接口上传需要的json参数
 | 
					     * 组装接口上传需要的json参数
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    fun generateApiParam(events: List<EventEntity>): String {
 | 
					    fun generateApiParam(events: List<EventEntity>): String {
 | 
				
			||||||
 | 
					        /// todo: 版本需要根据当前的更新
 | 
				
			||||||
        val deviceInfoJson = GsonUtil.gson.toJson(DeviceInfoStore.deviceInfo)
 | 
					        val deviceInfoJson = GsonUtil.gson.toJson(DeviceInfoStore.deviceInfo)
 | 
				
			||||||
        return "{\"version\":${Constants.VERSION},\"events\":[${events.joinToString(",") { it.json }}],\"deviceInfo\":$deviceInfoJson}"
 | 
					        return "{\"version\":${Constants.VERSION},\"events\":[${events.joinToString(",") { it.json }}],\"deviceInfo\":$deviceInfoJson}"
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -19,7 +19,7 @@ object GZipUtils {
 | 
				
			||||||
            out.toByteArray()
 | 
					            out.toByteArray()
 | 
				
			||||||
        } catch (e: IOException) {
 | 
					        } catch (e: IOException) {
 | 
				
			||||||
            EventHandler.INSTANCE.notifyEventHandler(AnalyticsCode.ERROR_ZIP, e.message)
 | 
					            EventHandler.INSTANCE.notifyEventHandler(AnalyticsCode.ERROR_ZIP, e.message)
 | 
				
			||||||
            null
 | 
					            throw e
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue