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" }