运行环境要求:
设备检测工具类
蓝牙检测,需要用到以下权限:
<!-- 如果需要访问蓝牙设备,可能需要以下权限 -->
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<!-- 对于 Android 12 及以上,可能需要声明使用蓝牙扫描的权限 -->
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
检测工具类:
import android.annotation.SuppressLint
import android.app.usage.StorageStatsManager
import android.bluetooth.BluetoothAdapter
import android.content.Context
import android.content.pm.PackageManager
import android.os.Build
import android.os.Environment
import android.os.StatFs
import android.os.storage.StorageManager
import android.util.DisplayMetrics
import android.util.Log
import android.view.WindowManager
import java.io.BufferedReader
import java.io.FileReader
import kotlin.math.ceil
import kotlin.math.sqrt
class DeviceChecker(private val context: Context) {
// CPU 最低要求 1.5 GHz
private val requiredCpuMinGHz = 1.5
// RAM 最低要求 4 GB
private val requiredRamMinGB = 4.0
// ROM 最低要求 32 GB
private val requiredRomMinGB = 32.0
// 蓝牙最低要求 4.0
private val requiredBluetoothMinVersion = "4.0"
// 屏幕尺寸最小要求 10.1 英寸
private val requiredScreenSizeInches = 10.1
// 屏幕分辨率要求 1920x1080
private val requiredResolution = Pair(1080, 1920)
// Android 版本最低要求 10 (Q)
private val requiredAndroidSdk = Build.VERSION_CODES.Q
/**
* 检查设备是否满足所有要求
*/
fun isDeviceCompatible(): Boolean {
return isCpuCompatible() &&
isRamCompatible() &&
isRomCompatible() &&
// isBluetoothCompatible() &&
// isBluetooth4Supported() &&
isBluetooth4SupportedAndEnabled() &&
isScreenSizeCompatible() &&
isScreenResolutionCompatible() &&
isAndroidVersionCompatible()
}
/**
* CPU 频率是否满足 1.5 GHz
*/
fun isCpuCompatible(): Boolean {
val maxCpuGHz = getMaxCpuFrequency()
return maxCpuGHz >= requiredCpuMinGHz
}
private fun getMaxCpuFrequency(): Double {
try {
val maxFreqPath = "/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq"
val reader = BufferedReader(FileReader(maxFreqPath))
val maxFreqStr = reader.readLine().trim()
reader.close()
val maxFreqHz = maxFreqStr.toDoubleOrNull() ?: 0.0
return maxFreqHz / 1_000_000.0 // 转换为 GHz
} catch (e: Exception) {
e.printStackTrace()
}
return 0.0
}
/**
* RAM 空间是否满足 4 GB
*/
fun isRamCompatible(): Boolean {
val totalRamGb = getTotalRamGb()
Log.d("caowj", "Total RAM: $totalRamGb GB")
return ceil(totalRamGb) >= requiredRamMinGB
}
private fun getTotalRamGb(): Double {
val activityManager =
context.getSystemService(Context.ACTIVITY_SERVICE) as android.app.ActivityManager
val memoryInfo = android.app.ActivityManager.MemoryInfo()
activityManager.getMemoryInfo(memoryInfo)
// totalMem 在 Android 8.0 及以上需要权限,可能无法获取
// 使用 Runtime 获取应用内存限制,不代表设备总内存
// 因此,这里尝试读取 /proc/meminfo
return try {
val reader = BufferedReader(FileReader("/proc/meminfo"))
var line: String?
var totalRamKb = 0L
while (reader.readLine().also { line = it } != null) {
if (line?.startsWith("MemTotal") == true) {
val parts = line?.split("\\s+".toRegex())
if (parts!!.size >= 2) {
totalRamKb = parts[1].toLongOrNull() ?: 0L
}
break
}
}
reader.close()
totalRamKb / (1024.0 * 1024.0) // 转换为 GB
} catch (e: Exception) {
e.printStackTrace()
0.0
}
}
// /**
// * 获取设备的总 RAM 大小(单位:GB)
// * 返回值接近厂商标称值(如 4GB)
// */
// private fun getTotalRamSize(context: Context): Double {
// val activityManager = context.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
// return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
// // API 16+ 使用 ActivityManager.MemoryInfo
// val memoryInfo = ActivityManager.MemoryInfo()
// activityManager.getMemoryInfo(memoryInfo)
// memoryInfo.totalMem.toDouble() / (1024 * 1024 * 1024) // 转换为 GB
// } else {
// // 旧版本回退到读取 /proc/meminfo(需要 READ_EXTERNAL_STORAGE 权限)
// readTotalRamFromProcMeminfo()
// }
// }
//
// /** 兼容旧设备,读取 /proc/meminfo 获取总 RAM */
// private fun readTotalRamFromProcMeminfo(): Double {
// return try {
// val reader = java.io.FileReader("/proc/meminfo")
// val buffer = java.io.BufferedReader(reader)
// val line = buffer.readLine() // 示例:MemTotal: 4048232 kB
// buffer.close()
// val memTotalKb = line.substringAfter("MemTotal:").trim().substringBefore(" kB").toLong()
// memTotalKb / (1024 * 1024.0) // 转换为 GB
// } catch (e: Exception) {
// 0.0 // 读取失败时返回 0
// }
// }
/**
* ROM 空间是否满足 32 GB
*/
fun isRomCompatible(): Boolean {
val totalRomGb = getPhysicalStorageSize(context)
Log.d("caowj", "Total ROM: $totalRomGb GB")
return ceil(totalRomGb) >= requiredRomMinGB
}
// /**
// * 只能获取到用户可用空间,和厂标的存储总容量不符
// * → 标称 32GB
// * → 实际约29.8GB(芯片级)
// * → 用户可见约23.5GB(扣除系统分区)
// */
// private fun getTotalInternalStorageGb(): Double {
// val path = Environment.getDataDirectory()
// val stat = StatFs(path.path)
// val blockSize = stat.blockSizeLong
// val totalBlocks = stat.blockCountLong
// val totalBytes = totalBlocks * blockSize
// return totalBytes / (1024.0 * 1024.0 * 1024.0) // 转换为 GB
// }
/**
* 获取最接近厂商标称的存储总容量(单位:GB)
* 完全使用Android公开API实现
* 兼容所有Android版本(API 1+)
*
* → 标称 32GB
* → 实际约29.8GB(芯片级)
* → 用户可见约23.5GB(扣除系统分区)
*/
@SuppressLint("NewApi")
private fun getPhysicalStorageSize(context: Context): Double {
return try {
// 方案1:通过StorageStatsManager获取(API 26+最准确)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val storageStatsManager = context.getSystemService(StorageStatsManager::class.java)
val storageManager = context.getSystemService(StorageManager::class.java)
// 关键修正:直接使用UUID_DEFAULT
storageStatsManager.getTotalBytes(StorageManager.UUID_DEFAULT) / 1_000_000_000.0
}
// 方案2:传统StatFs方式(全版本兼容)
else {
StatFs(Environment.getDataDirectory().path).run {
blockCountLong * blockSizeLong / 1_000_000_000.0
}
}
} catch (e: Exception) {
// 异常时回退到基础计算
StatFs(Environment.getDataDirectory().path).run {
blockCountLong * blockSizeLong / 1_000_000_000.0
}
}
}
@SuppressLint("MissingPermission")
fun isBluetooth4SupportedAndEnabled(): Boolean {
// 1. 检查设备是否支持 BLE
if (!context.packageManager.hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
return false
}
// 2. 获取 BluetoothAdapter
val bluetoothManager =
context.getSystemService(Context.BLUETOOTH_SERVICE) as android.bluetooth.BluetoothManager?
val bluetoothAdapter = bluetoothManager?.adapter
// 3. 检查 BluetoothAdapter 是否可用且已启用
return bluetoothAdapter != null && bluetoothAdapter.isEnabled
}
/**
* 蓝牙版本是否满足 4.0
*/
fun isBluetooth4Supported(): Boolean {
return context.packageManager.hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)
}
/**
* 是否支持蓝牙 4.0 或更高版本
*/
fun isBluetoothCompatible(): Boolean {
return isBluetoothSupported()
// 获取蓝牙版本较为复杂,这里假设支持蓝牙即满足最低要求
// 实际项目中可能需要更复杂的逻辑或依赖设备信息
}
/**
* 检查设备是否支持蓝牙
* @return true 如果设备支持蓝牙,否则返回 false
*/
private fun isBluetoothSupported(): Boolean {
val bluetoothAdapter = BluetoothAdapter.getDefaultAdapter()
return bluetoothAdapter != null
}
/**
* 屏幕尺寸是否满足 10.1 英寸
*/
fun isScreenSizeCompatible(): Boolean {
val screenSizeInches = getScreenSizeInches()
Log.d("caowj", "屏幕尺寸: $screenSizeInches inches")
return screenSizeInches >= requiredScreenSizeInches
}
private fun getScreenSizeInches(): Double {
val windowManager = context.getSystemService(Context.WINDOW_SERVICE) as WindowManager
val display = windowManager.defaultDisplay
val displayMetrics = DisplayMetrics()
display.getRealMetrics(displayMetrics)
val widthPixels = displayMetrics.widthPixels
val heightPixels = displayMetrics.heightPixels
val xdpi = displayMetrics.xdpi
val ydpi = displayMetrics.ydpi
Log.d("DeviceInfo", "Width Pixels: $widthPixels")
Log.d("DeviceInfo", "Height Pixels: $heightPixels")
Log.d("DeviceInfo", "XDPI: $xdpi")
Log.d("DeviceInfo", "YDPI: $ydpi")
// 计算宽度和高度(英寸)
val widthInches = widthPixels / xdpi
val heightInches = heightPixels / ydpi
Log.d("DeviceInfo", "Width Inches: $widthInches")
Log.d("DeviceInfo", "Height Inches: $heightInches")
// 计算对角线尺寸(英寸)
val sizeInches =
sqrt(((widthInches * widthInches + heightInches * heightInches).toDouble()))
Log.d("DeviceInfo", "Screen Size Inches: $sizeInches")
// return sizeInches
return formatDoubleToOneDecimalAsDouble(sizeInches)
}
/**
*屏幕分辨率是否满足 1920x1080
*/
fun isScreenResolutionCompatible(): Boolean {
val (width, height) = getScreenResolution()
Log.d("caowj", "Screen Resolution: $width x $height")
return (width >= requiredResolution.first && height >= requiredResolution.second) || (width >= requiredResolution.second && height >= requiredResolution.first)
}
private fun getScreenResolution(): Pair<Int, Int> {
val windowManager = context.getSystemService(Context.WINDOW_SERVICE) as WindowManager
val displayMetrics = DisplayMetrics()
windowManager.defaultDisplay.getRealMetrics(displayMetrics)
return Pair(displayMetrics.widthPixels, displayMetrics.heightPixels)
}
/**
* Android 版本是否满足 10 (Q)
*/
fun isAndroidVersionCompatible(): Boolean {
return Build.VERSION.SDK_INT >= requiredAndroidSdk
}
/**
* 保留 1位小数
*/
private fun formatDoubleToOneDecimalAsDouble(value: Double): Double {
return String.format("%.1f", value).toDouble()//会四舍五入
}
}
调用示例:
private fun showCompatibilityDetails() {
val deviceChecker = DeviceChecker(this)
if (deviceChecker.isDeviceCompatible()) {
Toast.makeText(this, "设备满足所有要求", Toast.LENGTH_LONG).show()
} else {
Toast.makeText(this, "设备不满足要求,请检查硬件和软件配置", Toast.LENGTH_LONG).show()
// 可选:显示具体哪些不满足
val details = StringBuilder()
details.append("设备兼容性详情:\n")
details.append("CPU: ${if (deviceChecker.isCpuCompatible()) "满足" else "不满足"}\n")
details.append("RAM: ${if (deviceChecker.isRamCompatible()) "满足" else "不满足"}\n")
details.append("ROM: ${if (deviceChecker.isRomCompatible()) "满足" else "不满足"}\n")
details.append("蓝牙: ${if (deviceChecker.isBluetooth4Supported()) "满足" else "不满足"}\n")
details.append("屏幕尺寸: ${if (deviceChecker.isScreenSizeCompatible()) "满足" else "不满足"}\n")
details.append("屏幕分辨率: ${if (deviceChecker.isScreenResolutionCompatible()) "满足" else "不满足"}\n")
details.append("Android 版本: ${if (deviceChecker.isAndroidVersionCompatible()) "满足" else "不满足"}\n")
// 显示详情(例如通过对话框)
// 这里简单使用 Toast,实际项目中建议使用 AlertDialog 或自定义布局
Log.w("caowj", "判断结果:$details")
}
}