目录
- 检测是手机还是平板
- 判断是否为折叠屏
- 屏幕密度与密度比例
- 屏幕像素
- 物理尺寸
- 刷新率
- 广色域
- 获取内存(Runtime)
- 获取内存(MemoryInfo)
- 磁盘空间(外部存储与内部存储)
- CPU内核数量
- CPU架构
- CPU硬件信息
- 检测设备是否root
- 网络情况
- 总结
最近需要做个项目,里面涉及到一些收集android硬件信息,虽说项目还没开始,但也不影响自己先事先准备起来.
检测是手机还是平板
Android中没有提供特定的方法来判断设备是手机还是平板,只能通过别的方式来间接判断,比如通过判断屏幕尺寸
infoText.text = checkIsTablet() private fun checkIsTablet(): String { val metrics = resources.displayMetrics val widthInches = metrics.widthPixels / metrics.xdpi val heightInches = metrics.heightPixels / metrics.ydpi val diagonalInches = sqrt(widthInches.pow(2.0f) + heightInches.pow(2.0f)) return if (diagonalInches >= 7.0) { "手机还是平板:平板" } else { "手机还是平板:手机" } }
验证一下,分别将这段代码运行在一个手机模拟器上以及平板模拟器上,结果如下
判断是否为折叠屏
其实在折叠屏没出现的时候,判断手机或者是平板使用上述方法还是够用的,但是在折叠屏面前就显得信心不足了,折叠屏一展开,那就是一个长着平板脸的手机,为了识别折叠屏,Android10出来了一个新的感应器类型TYPE_HINGE_ANGLE
,可以通过是否存在这种感应器来识别折叠屏
private fun checkIsFoldScreen(): String { val sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager val hingeAngleSensor = sensorManager.getDefaultSensor(Sensor.TYPE_HINGE_ANGLE) return if (hingeAngleSensor == null) { "是否折叠屏:否" } else { "是否折叠屏: 是" } }
装了一个折叠屏的模拟器,拿来试一下看看能不能识别
如果说想要具体拿到折叠屏的状态,比如是全展开还是半展开,或者收起状态,就要使用Jetpack WindowManager这个库了,分别可以通过以下api拿到不同的状态
不过这个得用真机试了,模拟器上拿不到FoldingFeature
,等我买了折叠屏再试下
屏幕密度与密度比例
这两个值相信基本每个项目都会用到,屏幕密度一般用来判断屏幕适配,加载不同的图片资源,密度比例一般用来单位换算,这俩值都可以通过DisplayMetrics
来获得
infoText.text = checkScreenDpiAndDensity() private fun checkScreenDpiAndDensity(): String { val displayMetric = resources.displayMetrics val dpi = displayMetric.densityDpi val density = displayMetric.density return "屏幕密度:${dpi} 密度比例:${density}" }
屏幕像素
private fun checkScreenPixel(): String { val displayMetrics = DisplayMetrics() if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { display?.getReaandroidlMetrics(displayMetrics) }else{ windowManager.defaultDisplay.getRealMetrics(displayMetrics); } val wpixel = displayMetrics.widthPixels val hPixel = displayMetrics.heightPixels return "像素(宽):${wPixel} 像素(高):${hPixel}" }javascript
物理尺寸
物理尺寸在安卓上单位是英寸,它表示一个屏幕对角线的长度,至于如何计算对角线,就要用到上学时候用到的勾股定理,x,y分别是屏幕的宽高,注意的是由于单位是英寸,所以也要把上面计算出来的像素转换成英寸,具体代码如下
private fun checkPhysicalSize(): String { val displayMetrics = DisplayMetrics() if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { display?.getRealMetrics(displayMetrics) }else{ windowManager.defaultDisplay.getRealMetrics(displayMetrics); } val widthInches = displayMetrics.widthPixels / displayMetrics.xdpi val heightInches = displayMetrics.heightPixels / displayMetrics.ydpi val diagonalInches = sqrt( widthInches.pow(2.0f) + heightInches.pow(2.0f) ) return "物理尺寸 $diagonalInches" }
刷新率
刷新率一般就是指Android屏幕上每秒更新画面的频率,单位是赫兹,正常来讲,普通设备的刷新率都为60赫兹,获取刷新率的代码如下
private fun checkRefreshRate(): String { val mDisplay = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { display }else{ windowManager.defaultDisplay } return "刷新率 ${mDisplay?.refreshRate}" }
广色域
有的设备支持广色域,有的设备仅仅支持标准色域,广色域的意思是屏幕可以显示比标准色域(sRGB)更加丰富的颜色范围,判断一个设备是否支持广色域的方式如下
private fun checkColorGamut(): String { val config: Configuration = resources.configuration if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { val isWideColorGamut: Boolean = config.isScreenWideColorGamut val support = if(isWideColorGamut) "支持" else "不支持" return "是否支持广色域模式:${support}" } return "不支持广色域" }
获取内存(Runtime)
一般来讲应用想获取内存信息,用的最多的就是通过Runtime
来获取,可以通过它获取应用最大可用内存,当前分配的内存,当前空闲内存,已使用内存
infoText.text = checkMemoryRuntime() private fun checkMemoryRuntime(): String { val runtime = Runtime.getRuntime() val maxMemory = runtime.maxMemory() // 应用最大可用内存 val totalMemory = runtime.totalMemory() // 当前分配的内存 val freeMemory = runtime.freeMemory() // 当前空闲内存 val usedMemory = totalMemory - freeMemory // 已使用内存 return "最大可用内存:${maxMemory} 当前分配的内存:${totalMemory} 当前空闲内存:${freeMemory} 已使用内存${usedMemory}" }
获取内存(MemoryInfo)
还有一种方式就是通过获取MemoryInfo来拿到内存信息,比如总内存,当前空闲内存以及判断内存是否过低
infoText.text = checkMemoryMemoInfo() private fun checkMemoryMemoInfo(): String { val activityManager = getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager val memoryInfo js= ActivityManager.MemoryInfo() activityManager.getMemoryInfo(memoryInfo) val totalMem = memoryInfo.totalMem val availMem = memoryInfo.availMem val lowMemory = memoryInfo.lowMemory return "总内存:${totalMem} 当前空闲内存:${availMem} 内存是否过低${lowMemory}" }
磁盘空间(外部存储与内部存储)
可以通过StatFs
来获取外部存储以及内存存储容量
//外部存储 infoText.text = checkExternalStorageInfo() private fun checkExternalStorageInfo(): String { if (Environment.getExternalStorageState() == Environment.MEDIA_MOUNTED) { val path = Environment.getExternalStorageDirectory() // 外部存储根目录 val stat = StatFs(path.path) val blockSize = stat.blockSizeLong val totalBlocks = stat.blockCountLong val availableBlocks = stat.availableBlocksLong val totalSize = blockSize * totalBlocks val availableSize = blockSize * availableBlocks val usedSize = totalSize - availableSize return "外部存储总容量:${totalSize} 外部存储可用容量:${availableSize} 外部存储已用容量:${usedSize}" } return "" }
//内部存储 infoText.text = checkInternalStorageInfo() private fun checkInternalStorageInfo(): String { val path = Environment.getDataDirectory() // 内部存储根目录 val stat = StatFs(path.path) val blockSize = stat.blockSizeLong // 每个block的大小 val totalBlocks = stat.blockCountLong // 总block数 val availableBlocks = stat.availableBlocksLong // 可用block数 val totalSize = blockSize * totalBlocks // 总容量 val availableSize = blockSize * availableBlocks // 可用容量 val usedSize = totalSize - availableSize // 已用容量 return "内部存储总容量:${totalSize} 内部存储可用容量:${availableSize} 内部存储已用容量:${usedSize}" }
CPU内核数量
获取CPU的内核数量很简单,Runtime
类中有现成的方法
infoText.text = checkCPUcoreNumber() private fun checkCPUcoreNumber() = "cpu核心数 : ${Runtime.getRuntime().availableProcessors()}"
CPU架构
infoText.text = checkCPUArchitecture() private fun checkCPUArchitecture() = "cpu架构:${Build.SUPPORTED_ABIS[0]}"
CPU硬件信息
infoText.text = checkCPUHardware() private fun checkCPUHardware() = "硬件信息:${Build.HARDWARE}"
检测设备是否root
同样的没有任何api可以直接去判断设备是否有root权限,我们只能从以下几个方式去判断
- 判断检查是否存在相关root文件
var fileRooted = false val paths = arrayOf( "/system/app/Superuser.apk", "/sbin/su", "/system/bin/su", "/system/xbin/su", "/data/local/xbin/su", "/data/local/bin/su", "/system/sd/xbin/su", "/system/bin/failsafe/su", "/data/local/su", "/su/bin/su" ) for (path in paths) { if (File(path).exists()) { fileRooted = true } }
- 检查是否存在su命令
var suCmdExest = false var process: Process? = null try { process = Runtime.getRuntime().exec(arrayOf("which", "su")) val reader = BufferedReader(InputStreamReader(process.inputStream)) suCmdExest = reader.readLine() != null } catch (e: Exception) { suCmdExest = false } finally { process?.destroy() }
- 检查
Build.TAGS
里面是否存在test-keys
var testKeys = false val buildTags = Build.TAGS testKeys = buildTags != null && buildTags.contains("test-keys")
- 执行su命令
var suCmdExecute = false var suprocess: Process? = null try { suprocess = Runtime.getRuntime().exec("su") val out = suprocess.outputStream out.write("exit\n".toByteArray()) out.flush() out.close() suCmdExecute = suprocess.waitFor() == 0 } catch (e: Java.lang.Exception) { suCmdExecute = false } finally { process?.destroy() }
- Magisk 文件是否存在
var giskFile = false val magiskPaths = arrayOf( "/sbin/.magisk", "/sbin/magisk", "/cache/.disable_magisk", "/cache/magisk.log", "/data/adb/magisk", "/data/adb/modules", "/data/magisk", "/data/magisk.img" ) for (path in magiskPaths) { if (File(path).exists()) { giskFile = true } }
保险起见,可以把上述几个变量放在一起判断设备是否有root权限
val gotRoot = fileRooted || suCmdExest || testKeys || suCmdExecute || giskFile
网络情况
这个也是在应用当中经常会用到的一个属性,判断设备是连接的是wifi,还是连接的是2,3,4,5G网络,首先通过获取 NetworkCapabilities
来判断是否连接的是wifi还是移动网络
private fun checkNetworkType(): String { var net = "" val cManager = getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager val capabilities: NetworkCapabilities? = cManager.getNetworkCapabilities(cManager.activeNetwjsork) capabilities?.let { cb -> if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) { net = "WIFI" } else if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) { net = getMobileNetworkType(cManager) } } return "网络情况:${net}" }
当判断出非wifi网络的时候,再通过getMobileNetworkType
函数来得出具体的网络类型
private fun getMobileNetworkType(cManager: ConnectivityManager): String { val networkInfo = cManager.getNetworkInfo(ConnectivityManager.TYPE_MOBILE) if (networkInfo != null) { val networkType = networkInfo.subtype return when (networkType) { TelephonyManager.NETWORK_TYPE_GPRS, TelephonyManager.NETWORK_TYPE_EDGE -> "2G" TelephonyManager.NETWORK_TYPE_UMTS, TelephonyManager.NETWORK_TYPE_HSPA -> "3G" TelephonyManager.NETWORK_javascriptTYPE_LTE -> "4G" TelephonyManager.NETWORK_TYPE_NR -> "5G" else -> "UNKNOWN" } } return "UNKNOWN" }
总结
文章就到此为止,在拿这些信息的时候,发现有不少api都已经废弃了,所以还是要注意一下尽量别用废弃的api去实现功能,防止以后出问题。
以上就是Android相关硬件信息的获取方式整理汇总的详细内容,更多关于Android硬件信息获取的资料请关注编程客栈(www.devze.com)其它相关文章!
精彩评论