diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index 6084a9e..ba17f20 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -5,6 +5,7 @@ plugins {
alias(libs.plugins.android.application)
id("com.google.gms.google-services")
id("com.google.firebase.crashlytics")
+ alias(libs.plugins.kotlin.android)
}
val timestamp: String = SimpleDateFormat("MM_dd_HH_mm").format(Date())
android {
@@ -15,9 +16,12 @@ android {
applicationId = "com.ar.ardrawingboard"
minSdk = 23
targetSdk = 35
- versionCode = 2
- versionName = "1.0.1"
- setProperty("archivesBaseName", "AR Drawing Board_V" + versionName + "(${versionCode})_$timestamp")
+ versionCode = 3
+ versionName = "1.0.2"
+ setProperty(
+ "archivesBaseName",
+ "AR Drawing Board_V" + versionName + "(${versionCode})_$timestamp"
+ )
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
}
@@ -38,6 +42,9 @@ android {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
}
+ kotlinOptions {
+ jvmTarget = "11"
+ }
}
dependencies {
@@ -46,6 +53,7 @@ dependencies {
implementation(libs.material)
implementation(libs.activity)
implementation(libs.constraintlayout)
+ implementation(libs.core.ktx)
testImplementation(libs.junit)
androidTestImplementation(libs.ext.junit)
androidTestImplementation(libs.espresso.core)
@@ -53,14 +61,24 @@ dependencies {
implementation("com.github.bumptech.glide:glide:4.16.0")
annotationProcessor("com.github.bumptech.glide:compiler:4.16.0")
- implementation ("androidx.room:room-runtime:2.7.0")
- annotationProcessor ("androidx.room:room-compiler:2.7.0")
+ implementation("androidx.room:room-runtime:2.7.0")
+ annotationProcessor("androidx.room:room-compiler:2.7.0")
- implementation ("androidx.camera:camera-core:1.4.2")
- implementation ("androidx.camera:camera-lifecycle:1.4.2")
- implementation ("androidx.camera:camera-view:1.4.2")
- implementation ("androidx.camera:camera-extensions:1.4.2")
- implementation ("androidx.camera:camera-camera2:1.4.2")
+ implementation("androidx.camera:camera-core:1.4.2")
+ implementation("androidx.camera:camera-lifecycle:1.4.2")
+ implementation("androidx.camera:camera-view:1.4.2")
+ implementation("androidx.camera:camera-extensions:1.4.2")
+ implementation("androidx.camera:camera-camera2:1.4.2")
+
+ //获取gaid
+ implementation("com.google.android.gms:play-services-ads-identifier:18.0.1")
+ implementation("com.google.android.gms:play-services-appset:16.0.1")
+ //开启协程
+ implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.6.2")
+
+
+ implementation("com.squareup.okhttp3:okhttp:4.12.0")
+ implementation("com.squareup.okhttp3:logging-interceptor:4.12.0")
// Import the BoM for the Firebase platform
implementation(platform("com.google.firebase:firebase-bom:33.1.1"))
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index ac5db1a..532e8f6 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -16,9 +16,13 @@
android:name="android.permission.READ_EXTERNAL_STORAGE"
android:maxSdkVersion="32" />
+
+
+
+ val ssid = wifiInfo.ssid // WiFi 名称
+ val bssid = wifiInfo.bssid // 路由器 MAC 地址
+ val ip = wifiInfo.ipAddress
+ val ipAddress: String = Formatter.formatIpAddress(ip) // IP 地址
+// Log.d("WiFi Info", "SSID: $ssid, BSSID: $bssid, IP: $ipAddress")
+
+ jsonObject.put("wifiSSID", ssid)
+ jsonObject.put("wifiBSSID", bssid)
+
+ }
+
+// getLastLocation(context){location->
+// location?.let {
+// val latitude: Double = location.latitude
+// val longitude: Double = location.longitude
+// val accuracy = location.accuracy // 获取精度(米)
+// jsonObject.put("longitude",longitude)
+// jsonObject.put("latitude",latitude)
+//// jsonObject.put("randomOffset",latitude)
+// Log.d("Location", "纬度: $latitude, 经度: $longitude")
+// }
+// }
+
+ //电池电量
+ val batteryInfo = getBatteryInfo(context)
+ jsonObject.put("batteryLevel", batteryInfo)
+
+ //处理器核心数
+ val coreCount = Runtime.getRuntime().availableProcessors()
+ jsonObject.put("availableProcessors", coreCount)
+
+ //系统启动时长
+// val convertTimestampToDate =
+// convertTimestampToDate(System.currentTimeMillis() - SystemClock.elapsedRealtime())
+// val systemUptime = getSystemUptime()
+ jsonObject.put("systemStarTime", SystemClock.elapsedRealtime())
+
+ //应用程序 APK 文件的最后修改时间
+ val installTime = getInstallTime(context)
+ jsonObject.put("apkLastModified", installTime)
+
+ //安装来源
+ val installSource = getInstallSourceNew(context)
+ jsonObject.put("installerPkg", installSource)
+
+
+ Log.d("===================================", jsonObject.toString())
+ return jsonObject.toString()
+
+ }
+
+
+ fun getInstallSource(context: Context): String? {
+ val packageManager = context.packageManager
+ val installer = packageManager.getInstallerPackageName(context.packageName)
+ return installer ?: "未知"
+ }
+
+ fun getInstallSourceNew(context: Context): String? {
+ return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { // API 30+
+ try {
+ val packageManager = context.packageManager
+ val installSourceInfo = packageManager.getInstallSourceInfo(context.packageName)
+ installSourceInfo.installingPackageName // 安装来源
+ } catch (e: PackageManager.NameNotFoundException) {
+ "未知"
+ }
+ } else {
+ getInstallSource(context) // 兼容 API 30 以下
+ }
+ }
+
+ fun getSystemUptime(): String {
+ val uptimeMillis = SystemClock.elapsedRealtime() // 设备启动后的毫秒数
+ val uptimeSeconds = uptimeMillis / 1000
+ val hours = uptimeSeconds / 3600
+ val minutes = uptimeSeconds % 3600 / 60
+ val seconds = uptimeSeconds % 60
+ val uptimeFormatted = "$hours 小时 $minutes 分钟 $seconds 秒"
+ Log.d("DeviceInfo", "系统运行时间: $uptimeFormatted")
+ return uptimeFormatted
+ }
+
+ private fun getLastLocation(context: Activity, result: (location: Location?) -> Unit) {
+// val fusedLocationClient = LocationServices.getFusedLocationProviderClient(context)
+//
+// if (ActivityCompat.checkSelfPermission(
+// context,
+// Manifest.permission.ACCESS_FINE_LOCATION
+// ) != PackageManager.PERMISSION_GRANTED || ActivityCompat.checkSelfPermission(
+// context,
+// Manifest.permission.ACCESS_COARSE_LOCATION
+// ) != PackageManager.PERMISSION_GRANTED
+// ) {
+// Log.e("==================", "无法获取位置权限")
+// return
+// }
+// fusedLocationClient.lastLocation
+// .addOnSuccessListener(context, object : OnSuccessListener {
+// override fun onSuccess(location: Location?) {
+// result.invoke(location)
+// if (location != null) {
+// } else {
+//
+// Log.e("Location", "无法获取位置")
+// }
+// }
+// })
+ }
+
+ fun getInstallTime(context: Context): String {
+ val lastModified = File(context.applicationInfo.sourceDir).lastModified()
+ return convertTimestampToDate(lastModified)
+ }
+
+// fun getInstallSource(context: Context): String? {
+// return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
+// context.packageManager.getInstallSourceInfo(context.applicationInfo.packageName).installingPackageName
+// } else {
+// context.packageManager.getInstallerPackageName(context.applicationInfo.packageName)
+// }
+//
+// }
+
+ fun getBatteryInfo(context: Context): Int {
+ val batteryManager = context.getSystemService(Context.BATTERY_SERVICE) as BatteryManager
+ val batteryLevel =
+ batteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY) // 获取电池电量(0-100%)
+ val isCharging = batteryManager.isCharging // 是否在充电
+
+ return batteryLevel
+ }
+
+ /**
+ * ACCESS_FINE_LOCATION
+ *
+ * ACCESS_WIFI_STATE
+ */
+ fun getWifiInfo(context: Context): WifiInfo {
+ val wifiManager = context.getSystemService(Context.WIFI_SERVICE) as WifiManager
+ return wifiManager.connectionInfo
+
+ }
+
+
+ /**
+ * READ_PHONE_STATE
+ */
+ fun getMobileNetworkInfo(context: Context): TelephonyManager? {
+ val telephonyManager =
+ context.getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager
+ val operatorName = telephonyManager.networkOperatorName // 运营商名称
+
+
+ return telephonyManager
+
+
+// Log.d("Mobile Network", "Operator: $operatorName, Type: $networkType")
+ }
+
+ fun getNet(networkType: Int): String {
+ return when (networkType) {
+ TelephonyManager.NETWORK_TYPE_LTE -> "4G"
+
+ TelephonyManager.NETWORK_TYPE_NR -> "5G(Android 11+)"
+
+ TelephonyManager.NETWORK_TYPE_HSPA -> "3G"
+
+ TelephonyManager.NETWORK_TYPE_GPRS -> "2G"
+ else -> ""
+ }
+ }
+
+ fun getWebViewPackageInfo(context: Activity): PackageInfo? {
+ val packageManager: PackageManager = context.packageManager
+
+ // 如果系统支持直接获取 WebView 包信息 (Android 7.0 及以上)
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ return WebView.getCurrentWebViewPackage()
+ }
+ // 如果不支持,尝试通过常见的 WebView 包名来获取信息
+ val webviewPackageNames = listOf(
+ "com.google.android.webview",
+ "com.android.webview",
+ "com.android.chrome"
+ )
+ for (packageName in webviewPackageNames) {
+ try {
+ val packageInfo = packageManager.getPackageInfo(packageName, 0)
+ if (packageInfo != null) {
+ return packageInfo
+ }
+ } catch (e: PackageManager.NameNotFoundException) {
+ // 忽略异常,继续尝试下一个包名
+ }
+ }
+ // 如果都没有找到,返回 null
+ return null
+ }
+
+ @SuppressLint("HardwareIds")
+ fun getAndroidID(context: Context): String? {
+ return Settings.Secure.getString(context.contentResolver, Settings.Secure.ANDROID_ID)
+ }
+
+
+ fun convertTimestampToDate(timestamp: Long): String {
+ // 创建 SimpleDateFormat 实例
+ val format = "yyyy-MM-dd HH:mm:ss"
+ val dateFormat = SimpleDateFormat(format, Locale.getDefault())
+ dateFormat.timeZone = TimeZone.getTimeZone("GMT") // 设置时区为 UTC,或者根据需要选择其他时区
+
+ // 将时间戳转换为 Date 对象
+ val date = Date(timestamp)
+
+ // 格式化 Date 对象为指定格式的字符串
+ return dateFormat.format(date)
+ }
+
+
+ fun getDeviceId(context: Context): String? =
+ try {
+ // 优先尝试获取 GAID
+ val adInfo = AdvertisingIdClient.getAdvertisingIdInfo(context)
+ if (!adInfo.isLimitAdTrackingEnabled && !adInfo.id.isNullOrEmpty()) {
+ Log.d("DeviceIdHelper", "Using GAID: ${adInfo.id}")
+ adInfo.id
+ } else {
+ Log.d("DeviceIdHelper", "GAID not available or user limited it, using AppSet ID")
+ null
+ }
+ } catch (e: Exception) {
+ Log.e("DeviceIdHelper", "GAID fetch failed: ${e.message}")
+ null
+ }
+
+ // ✅ 回退获取 App Set ID(Android 12+ 替代方案)
+// return@withContext try {
+// val appSetInfo: AppSetIdInfo = AppSet.getClient(context).appSetIdInfo.await()
+// Log.d("DeviceIdHelper", "Using App Set ID: ${appSetInfo.id}")
+// appSetInfo.id
+// } catch (e: Exception) {
+// Log.e("DeviceIdHelper", "App Set ID fetch failed: ${e.message}")
+// null
+// }
+
+}
\ No newline at end of file
diff --git a/app/src/main/res/xml/net.xml b/app/src/main/res/xml/net.xml
new file mode 100644
index 0000000..0ac6102
--- /dev/null
+++ b/app/src/main/res/xml/net.xml
@@ -0,0 +1,6 @@
+
+
+
+ mobile-server.lux-ad.com
+
+
diff --git a/build.gradle.kts b/build.gradle.kts
index 2d9380e..927b126 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -4,4 +4,5 @@ plugins {
id("com.google.gms.google-services") version "4.3.15" apply false
id ("com.google.firebase.crashlytics") version "2.9.2" apply false
+ alias(libs.plugins.kotlin.android) apply false
}
\ No newline at end of file
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index 15a84c8..72687bf 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -7,6 +7,8 @@ appcompat = "1.7.0"
material = "1.12.0"
activity = "1.10.1"
constraintlayout = "2.2.1"
+kotlin = "2.1.20"
+coreKtx = "1.16.0"
[libraries]
junit = { group = "junit", name = "junit", version.ref = "junit" }
@@ -16,7 +18,9 @@ appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "a
material = { group = "com.google.android.material", name = "material", version.ref = "material" }
activity = { group = "androidx.activity", name = "activity", version.ref = "activity" }
constraintlayout = { group = "androidx.constraintlayout", name = "constraintlayout", version.ref = "constraintlayout" }
+core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
[plugins]
android-application = { id = "com.android.application", version.ref = "agp" }
+kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }