Android 获取设备相关信息

在做某些项目时,需要上传必要的设备信息给服务器用于风控

在此做一下总结。

一.获取的数据

主要包含下面数据

设备id
操作系统版本
设备型号
IMSI
路由器mac地址
设备mac地址
安卓id
经度
纬度
ip地址
谷歌广告id
手机可用内存
apk可用内存
apk可分配的最大内存
手机总内存
cpu主频
屏幕解析度
网络类型
是否调用usb
是否开启模拟器
电池电量
是否root过
设备总存储
设备可用存储
设备uuid
设备imei
sim卡槽状态

二.具体实现代码 

 DeviceUtils.kt

package com.uz.cashloanuzi.grab

import android.Manifest.permission
import android.annotation.SuppressLint
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.content.res.Configuration
import android.content.res.Resources
import android.hardware.usb.UsbManager
import android.location.LocationManager
import android.net.Uri
import android.net.wifi.WifiManager
import android.os.Build
import android.os.StatFs
import android.provider.Settings
import android.telephony.TelephonyManager
import android.text.TextUtils
import androidx.annotation.RequiresPermission
import androidx.core.app.ActivityCompat
import com.google.android.gms.ads.identifier.AdvertisingIdClient
import com.uz.cashloanuzi.base.AppConstant
import com.uz.cashloanuzi.base.BaseApplication.Companion.application
import com.uz.cashloanuzi.grab.ShellUtils.CommandResult
import com.uz.cashloanuzi.utils.LogUtils
import com.uz.cashloanuzi.utils.SPUtils
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import java.io.BufferedReader
import java.io.File
import java.io.FileReader
import java.io.IOException
import java.io.InputStreamReader
import java.math.BigDecimal
import java.math.RoundingMode
import java.net.InetAddress
import java.net.NetworkInterface
import java.net.SocketException
import java.util.Locale
import java.util.UUID

class DeviceUtils private constructor() {
    companion object {
        val isDeviceRooted: Boolean
            get() {
                val su = "su"
                val locations = arrayOf(
                    "/system/bin/",
                    "/system/xbin/",
                    "/sbin/",
                    "/system/sd/xbin/",
                    "/system/bin/failsafe/",
                    "/data/local/xbin/",
                    "/data/local/bin/",
                    "/data/local/",
                    "/system/sbin/",
                    "/usr/bin/",
                    "/vendor/bin/"
                )
                for (location in locations) {
                    if (File(location + su).exists()) {
                        return true
                    }
                }
                return false
            }

        val sDKVersionName: String
            get() = Build.VERSION.RELEASE

        val sDKVersionCode: Int
            get() = Build.VERSION.SDK_INT

        @get:SuppressLint("HardwareIds")
        val androidID: String
            get() {
                val id = Settings.Secure.getString(
                    application?.contentResolver,
                    Settings.Secure.ANDROID_ID
                )
                if ("9774d56d682e549c" == id) return ""
                return id ?: ""
            }

        @get:RequiresPermission(allOf = [permission.ACCESS_WIFI_STATE, permission.CHANGE_WIFI_STATE])
        val macAddress: String
            get() {
                val macAddress = getMacAddress(*(null as Array<String?>?)!!)
                if (!TextUtils.isEmpty(macAddress) || wifiEnabled) return macAddress
                wifiEnabled = true
                wifiEnabled = false
                return getMacAddress(*(null as Array<String?>?)!!)
            }

        @set:RequiresPermission(permission.CHANGE_WIFI_STATE)
        private var wifiEnabled: Boolean
            get() {
                @SuppressLint("WifiManagerLeak") val manager = application
                    ?.getSystemService(Context.WIFI_SERVICE) as WifiManager
                    ?: return false
                return manager.isWifiEnabled
            }
            /**
             * Enable or disable wifi.
             *
             * Must hold `<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />`
             *
             * @param enabled True to enabled, false otherwise.
             */
            private set(enabled) {
                @SuppressLint("WifiManagerLeak") val manager =
                    application?.getSystemService(Context.WIFI_SERVICE) as WifiManager
                        ?: return
                if (enabled == manager.isWifiEnabled) return
                manager.setWifiEnabled(enabled)
            }

        /**
         * Return the MAC address.
         *
         * Must hold `<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />`,
         * `<uses-permission android:name="android.permission.INTERNET" />`
         *
         * @return the MAC address
         */
        @RequiresPermission(allOf = [permission.ACCESS_WIFI_STATE])
        fun getMacAddress(vararg excepts: String?): String {
            var macAddress = macAddressByNetworkInterface
            if (isAddressNotInExcepts(macAddress, excepts)) {
                return macAddress
            }
            macAddress = macAddressByInetAddress
            if (isAddressNotInExcepts(macAddress, excepts)) {
                return macAddress
            }
            macAddress = macAddressByWifiInfo
            if (isAddressNotInExcepts(macAddress, excepts)) {
                return macAddress
            }
            macAddress = getMacAddressByFile()
            if (isAddressNotInExcepts(macAddress, excepts)) {
                return macAddress
            }
            return ""
        }

        private fun isAddressNotInExcepts(
            address: String,
            vararg excepts: Array<out String?>
        ): Boolean {
            if (TextUtils.isEmpty(address)) {
                return false
            }
            if ("02:00:00:00:00:00" == address) {
                return false
            }
            for (filter in excepts) {
                if (filter.toString() == address) {
                    return false
                }
            }
            return true
        }

        @get:RequiresPermission(permission.ACCESS_WIFI_STATE)
        private val macAddressByWifiInfo: String
            get() {
                try {
                    val wifi = application?.getApplicationContext()
                        ?.getSystemService(Context.WIFI_SERVICE) as WifiManager
                    if (wifi != null) {
                        val info = wifi.connectionInfo
                        if (info != null) {
                            @SuppressLint("HardwareIds") val macAddress = info.macAddress
                            if (!TextUtils.isEmpty(macAddress)) {
                                return macAddress
                            }
                        }
                    }
                } catch (e: Exception) {
                    e.printStackTrace()
                }
                return "02:00:00:00:00:00"
            }

        private val macAddressByNetworkInterface: String
            get() {
                try {
                    val nis = NetworkInterface.getNetworkInterfaces()
                    while (nis.hasMoreElements()) {
                        val ni = nis.nextElement()
                        if (ni == null || !ni.name.equals("wlan0", ignoreCase = true)) continue
                        val macBytes = ni.hardwareAddress
                        if (macBytes != null && macBytes.size > 0) {
                            val sb = StringBuilder()
                            for (b in macBytes) {
                                sb.append(String.format("%02x:", b))
                            }
                            return sb.substring(0, sb.length - 1)
                        }
                    }
                } catch (e: Exception) {
                    e.printStackTrace()
                }
                return "02:00:00:00:00:00"
            }

        private val macAddressByInetAddress: String
            get() {
                try {
                    val inetAddress = inetAddress
                    if (inetAddress != null) {
                        val ni = NetworkInterface.getByInetAddress(inetAddress)
                        if (ni != null) {
                            val macBytes = ni.hardwareAddress
                            if (macBytes != null && macBytes.size > 0) {
                                val sb = StringBuilder()
                                for (b in macBytes) {
                                    sb.append(String.format("%02x:", b))
                                }
                                return sb.substring(0, sb.length - 1)
                            }
                        }
                    }
                } catch (e: Exception) {
                    e.printStackTrace()
                }
                return "02:00:00:00:00:00"
            }

        private val inetAddress: InetAddress?
            get() {
                try {
                    val nis = NetworkInterface.getNetworkInterfaces()
                    while (nis.hasMoreElements()) {
                        val ni = nis.nextElement()
                        // To prevent phone of xiaomi return "10.0.2.15"
                        if (!ni.isUp) continue
                        val addresses = ni.inetAddresses
                        while (addresses.hasMoreElements()) {
                            val inetAddress = addresses.nextElement()
                            if (!inetAddress.isLoopbackAddress) {
                                val hostAddress = inetAddress.hostAddress
                                if (hostAddress.indexOf(':') < 0) return inetAddress
                            }
                        }
                    }
                } catch (e: SocketException) {
                    e.printStackTrace()
                }
                return null
            }



        @Suppress("DEPRECATED_IDENTITY_EQUALS")
        private fun getMacAddressByFile(): String
        {
            var result: ShellUtils.CommandResult =
                execCmd("getprop wifi.interface", false)
            if (result.result === 0) {
                val name: String = result.successMsg
                result = execCmd("cat /sys/class/net/$name/address", false)
                if (result.result === 0) {
                    val address: String = result.successMsg
                    if (address.isNotEmpty()) {
                        return address
                    }
                }
            }
            return "02:00:00:00:00:00"
        }

        fun execCmd(command: String?, isRooted: Boolean): CommandResult {
            return ShellUtils.execCmd(command, isRooted)
        }


        val manufacturer: String
            /**
             * Return the manufacturer of the product/hardware.
             *
             * e.g. Xiaomi
             *
             * @return the manufacturer of the product/hardware
             */
            get() = Build.MANUFACTURER

        val model: String
            get() {
                var model = Build.MODEL
                model = model?.trim { it <= ' ' }?.replace("\\s*".toRegex(), "") ?: ""
                return model
            }

        val aBIs: Array<String>
            /**
             * Return an ordered list of ABIs supported by this device. The most preferred ABI is the first
             * element in the list.
             *
             * @return an ordered list of ABIs supported by this device
             */
            get() {
                return Build.SUPPORTED_ABIS
            }

        val isTablet: Boolean
            /**
             * Return whether device is tablet.
             *
             * @return `true`: yes<br></br>`false`: no
             */
            get() = ((Resources.getSystem().configuration.screenLayout
                    and Configuration.SCREENLAYOUT_SIZE_MASK)
                    >= Configuration.SCREENLAYOUT_SIZE_LARGE)

        val isEmulator: Boolean
            /**
             * Return whether device is emulator.
             *
             * @return `true`: yes<br></br>`false`: no
             */
            get() {
                val checkProperty = (Build.FINGERPRINT.startsWith("generic")
                        || Build.FINGERPRINT.lowercase(Locale.getDefault()).contains("vbox")
                        || Build.FINGERPRINT.lowercase(Locale.getDefault()).contains("test-keys")
                        || Build.MODEL.contains("google_sdk")
                        || Build.MODEL.contains("Emulator")
                        || Build.MODEL.contains("Android SDK built for x86")
                        || Build.MANUFACTURER.contains("Genymotion")
                        || (Build.BRAND.startsWith("generic") && Build.DEVICE.startsWith("generic"))) || "google_sdk" == Build.PRODUCT
                if (checkProperty) return true

                var operatorName = ""
                val tm =
                    application?.getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager
                if (tm != null) {
                    val name = tm.networkOperatorName
                    if (name != null) {
                        operatorName = name
                    }
                }
                val checkOperatorName = operatorName.equals("android", ignoreCase = true)
                if (checkOperatorName) return true

                val url = "tel:" + "123456"
                val intent = Intent()
                intent.setData(Uri.parse(url))
                intent.setAction(Intent.ACTION_DIAL)
                val checkDial = intent.resolveActivity(application!!.packageManager) == null
                if (checkDial) return true
                if (isEmulatorByCpu) return true

                return false
            }

        private val isEmulatorByCpu: Boolean
            /**
             * Returns whether is emulator by check cpu info.
             * by function of [.readCpuInfo], obtain the device cpu information.
             * then compare whether it is intel or amd (because intel and amd are generally not mobile phone cpu), to determine whether it is a real mobile phone
             *
             * @return `true`: yes<br></br>`false`: no
             */
            get() {
                val cpuInfo = readCpuInfo()
                return cpuInfo.contains("intel") || cpuInfo.contains("amd")
            }

        /**
         * Return Cpu information
         *
         * @return Cpu info
         */
        private fun readCpuInfo(): String {
            var result = ""
            try {
                val args = arrayOf("/system/bin/cat", "/proc/cpuinfo")
                val cmd = ProcessBuilder(*args)
                val process = cmd.start()
                val sb = StringBuilder()
                var readLine: String?
                val responseReader = BufferedReader(InputStreamReader(process.inputStream, "utf-8"))
                while ((responseReader.readLine().also { readLine = it }) != null) {
                    sb.append(readLine)
                }
                responseReader.close()
                result = sb.toString().lowercase(Locale.getDefault())
            } catch (ignored: IOException) {
            }
            return result
        }

        val isDevelopmentSettingsEnabled: Boolean
            /**
             * Whether user has enabled development settings.
             *
             * @return whether user has enabled development settings.
             */
            get() = Settings.Global.getInt(
                application?.contentResolver,
                Settings.Global.DEVELOPMENT_SETTINGS_ENABLED, 0
            ) > 0


        private const val KEY_UDID = "KEY_UDID"

        @Volatile
        private var udid: String? = null

        val uniqueDeviceId: String?
            /**
             * Return the unique device id.
             * <pre>{1}{UUID(macAddress)}</pre>
             * <pre>{2}{UUID(androidId )}</pre>
             * <pre>{9}{UUID(random    )}</pre>
             *
             * @return the unique device id
             */
            get() = getUniqueDeviceId("", true)

        /**
         * Return the unique device id.
         * <pre>android 10 deprecated {prefix}{1}{UUID(macAddress)}</pre>
         * <pre>{prefix}{2}{UUID(androidId )}</pre>
         * <pre>{prefix}{9}{UUID(random    )}</pre>
         *
         * @param prefix The prefix of the unique device id.
         * @return the unique device id
         */
        fun getUniqueDeviceId(prefix: String): String? {
            return getUniqueDeviceId(prefix, true)
        }

        /**
         * Return the unique device id.
         * <pre>{1}{UUID(macAddress)}</pre>
         * <pre>{2}{UUID(androidId )}</pre>
         * <pre>{9}{UUID(random    )}</pre>
         *
         * @param useCache True to use cache, false otherwise.
         * @return the unique device id
         */
        fun getUniqueDeviceId(useCache: Boolean): String? {
            return getUniqueDeviceId("", useCache)
        }

        /**
         * Return the unique device id.
         * <pre>android 10 deprecated {prefix}{1}{UUID(macAddress)}</pre>
         * <pre>{prefix}{2}{UUID(androidId )}</pre>
         * <pre>{prefix}{9}{UUID(random    )}</pre>
         *
         * @param prefix   The prefix of the unique device id.
         * @param useCache True to use cache, false otherwise.
         * @return the unique device id
         */
        fun getUniqueDeviceId(prefix: String, useCache: Boolean): String? {
            if (!useCache) {
                return getUniqueDeviceIdReal(prefix)
            }
            if (udid == null) {
                synchronized(DeviceUtils::class.java) {
                    if (udid == null) {
                        val id = SPUtils.getInstance().getString(KEY_UDID, null)
                        if (id != null) {
                            udid = id
                            return udid
                        }
                        return getUniqueDeviceIdReal(prefix)
                    }
                }
            }
            return udid
        }

        private fun getUniqueDeviceIdReal(prefix: String): String? {
            try {
                val androidId = androidID
                if (!TextUtils.isEmpty(androidId)) {
                    return saveUdid(prefix + 2, androidId)
                }
            } catch (ignore: Exception) { 
            }
            return saveUdid(prefix + 9, "")
        }

        private fun saveUdid(prefix: String, id: String): String? {
            udid = getUdid(prefix, id)
            SPUtils.getInstance().put(KEY_UDID, udid)
            return udid
        }

        private fun getUdid(prefix: String, id: String): String {
            if (id.isEmpty()) {
                return prefix + UUID.randomUUID().toString().replace("-", "")
            }
            return prefix + UUID.nameUUIDFromBytes(id.toByteArray()).toString().replace("-", "")
        }


        @SuppressLint("MissingPermission", "HardwareIds")
        fun getDeviceIdentifier(context: Context): String {
            val telephonyManager =
                context.getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager
            return when {
                Build.VERSION.SDK_INT < Build.VERSION_CODES.O -> {
                    telephonyManager.deviceId
                }

                Build.VERSION.SDK_INT in Build.VERSION_CODES.O until Build.VERSION_CODES.Q -> {
                    telephonyManager.imei
                }

                else -> {
                    Settings.Secure.getString(context.contentResolver, Settings.Secure.ANDROID_ID)
                }
            }
        }

        @SuppressLint("MissingPermission", "HardwareIds")
        fun getIMSI(context: Context): String {
            val telephonyManager =
                context.getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager
            return if (ActivityCompat.checkSelfPermission(
                    context,
                    permission.READ_PHONE_STATE
                ) == PackageManager.PERMISSION_GRANTED
            ) {
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
                    androidID
                } else {
                   try {
                       telephonyManager.subscriberId ?: ""
                   }
                   catch (e:Exception){
                       androidID
                   }
                }
            } else {
                androidID
            }
        }
        fun isUSBConnected(context: Context): Boolean {
            val usbManager = context.getSystemService(Context.USB_SERVICE) as UsbManager
            val usbDevices = usbManager.deviceList

            // Check if any USB devices are connected
            return usbDevices.isNotEmpty()
        }


        @SuppressLint("DefaultLocale")
        fun getLatitude(context: Context): BigDecimal? {
            // 获取位置(经纬度)(需要 LOCATION 权限)
            val locationManager =
                context.getSystemService(Context.LOCATION_SERVICE) as LocationManager
            val location = if (ActivityCompat.checkSelfPermission(
                    context,
                    permission.ACCESS_COARSE_LOCATION
                ) == PackageManager.PERMISSION_GRANTED
            ) {
                locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER)
            } else {
                LogUtils.e("permission","permission.ACCESS_COARSE_LOCATION")
                null
            }
            val latitude = location?.latitude
            return if (latitude != null) {
                BigDecimal(latitude).setScale(5, RoundingMode.HALF_UP)
            } else {
                BigDecimal(AppConstant.DECIMAL_DEFAULT_VALUE)
            }
        }

        @SuppressLint("MissingPermission")
        fun getLongitude(context: Context): BigDecimal? {
            // 获取位置(经纬度)(需要 LOCATION 权限)
            val locationManager =
                context.getSystemService(Context.LOCATION_SERVICE) as LocationManager
            val location = if (ActivityCompat.checkSelfPermission(
                    context,
                    permission.ACCESS_COARSE_LOCATION
                ) == PackageManager.PERMISSION_GRANTED
            ) {
                locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER)
            } else {
                LogUtils.e("permission","permission.ACCESS_COARSE_LOCATION")
                null
            }

            val longitude = location?.longitude
            return if (longitude != null) {
                BigDecimal(longitude).setScale(5, RoundingMode.HALF_UP)
            } else {
                BigDecimal(AppConstant.DECIMAL_DEFAULT_VALUE)
            }
        }


        fun getIpAddress(context: Context): String {
            val wifiManager =
                context.applicationContext.getSystemService(Context.WIFI_SERVICE) as WifiManager
            val wifiInfo = wifiManager.connectionInfo
            return android.text.format.Formatter.formatIpAddress(wifiInfo.ipAddress)
        }


        suspend fun getGaid(context: Context): String? {
            return withContext(Dispatchers.IO) {
                try {
                    val advertisingIdInfo = AdvertisingIdClient.getAdvertisingIdInfo(context)
                    advertisingIdInfo.id
                } catch (e: Exception) {
                    e.printStackTrace()
                    null
                }
            }
        }

        fun getPhoneAvailableMemory(): Double {
            // 手机可用内存
            val runtime = Runtime.getRuntime()
            return (runtime.freeMemory() / 1024 / 1024).toDouble()
        }

        fun getApkAvailableMemory(): Double {
            // APK 可用内存
            val runtime = Runtime.getRuntime()
            return (runtime.totalMemory() / 1024 / 1024).toDouble()
        }

        fun getApkMaxMemory(): Double {
            val runtime = Runtime.getRuntime()
            // APK 可分配的最大内存
            return (runtime.maxMemory() / 1024 / 1024).toDouble()
        }

        fun getSimState(context: Context): Int {
            val telephonyManager =
                context.getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager
            val simState = telephonyManager.simState
            return simState
        }

        fun getTotalMemory(): Double {
            val totalMemory = BufferedReader(FileReader("/proc/meminfo")).useLines { lines ->
                lines.firstOrNull { it.startsWith("MemTotal:") }?.replace("\\D+".toRegex(), "")
                    ?.toLong()?.div(1024)
            }
            return totalMemory?.toDouble() ?: 0.0
        }

        fun getCpuFrequency(): Long {
            return BufferedReader(FileReader("/proc/cpuinfo")).useLines { lines ->
                lines.firstOrNull { it.startsWith("BogoMIPS") }?.replace("\\D+".toRegex(), "")
                    ?.toLong()
            } ?: 0
        }

        fun getScreenResolution(context: Context): String {
            val metrics = context.resources.displayMetrics
            return "${metrics.widthPixels}x${metrics.heightPixels}"
        }

        fun getBatteryPercent(context: Context): Int {
            return context.registerReceiver(
                null,
                android.content.IntentFilter(android.content.Intent.ACTION_BATTERY_CHANGED)
            )
                ?.getIntExtra(android.os.BatteryManager.EXTRA_LEVEL, -1) ?: -1
        }

        //磁盘
        fun getRomTotalSpace(context: Context): Double {
            val stat = StatFs(context.filesDir.path)
            val totalStorage = stat.totalBytes / 1024 / 1024 // in MB
            return totalStorage.toDouble()
        }

        //可用磁盘
        fun getAvailableRomStorage(context: Context): Double {
            val stat = StatFs(context.filesDir.path)
            // 设备可用存储
            val availableStorage = stat.availableBytes / 1024 / 1024 // in MB
            return availableStorage.toDouble()
        }

        //路由器地址
        fun getRouterMacAddress(context: Context): String? {
            val wifiManager =
                context.applicationContext.getSystemService(Context.WIFI_SERVICE) as WifiManager
            val wifiInfo = wifiManager.connectionInfo

            return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
                // Starting from Android 9 (Pie), this method returns "02:00:00:00:00:00" for privacy reasons
                wifiInfo.bssid
            } else {
                // On Android 8.1 and lower, the BSSID (MAC address of the access point) is available directly
                wifiInfo.bssid
            }
        }

        fun getNetworkType(context: Context): Int {
            val telephonyManager =
                context.getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager
            return if (ActivityCompat.checkSelfPermission(
                    context,
                    permission.READ_PHONE_STATE
                ) != PackageManager.PERMISSION_GRANTED
            ) {
                LogUtils.e("permission","permission.READ_PHONE_STATE")
                return -1
            } else
                telephonyManager.networkType
        }

        suspend fun getDeviceInfo(context: Context): Map<String, Any> {
            val map: MutableMap<String, Any> = HashMap()
            map["deviceId"] = getUniqueDeviceId(true) ?: ""
            map["os"] = Build.VERSION.RELEASE
            map["imsi"] = getIMSI(context)
            map["deviceMac"] = getMacAddress("")
            map["routerMac"] = getRouterMacAddress(context) ?: ""
            map["androidId"] = androidID
            map["lng"] = getLongitude(context)?:AppConstant.DECIMAL_DEFAULT_VALUE
            map["lat"] = getLatitude(context)?:AppConstant.DECIMAL_DEFAULT_VALUE
            map["ip"] = getIpAddress(context)
            map["googleAdvertisingId"] = getGaid(context) ?: ""
            map["cpu_speed"] = getCpuFrequency()
            map["screenResolution"] = getScreenResolution(context)//分辨率
            map["emulator"] = isEmulator //模拟器
            map["batterypercent"] = getBatteryPercent(context)//模拟器
            map["romTotalSpace"] = getRomTotalSpace(context)//磁盘总大小
            map["romFreeSpace"] = getAvailableRomStorage(context)//可用磁盘大小
            map["uuid"] = UUID.randomUUID().toString()//UUID
            map["simState"] = getSimState(context)//simState
            map["mobilePhoneModel"] = model//设备型号
            map["ramTotalSpace"] = getTotalMemory()//内存总大小
            map["romFreeSpace"] = getPhoneAvailableMemory()//手机可用内存
            map["runtime_available_memory"] = getApkAvailableMemory()//apk可用内存
            map["runtime_max_memory"] = getApkMaxMemory()//apk可用最大内存
            map["network"] = getNetworkType(context).toString()
            map["usb_enabled"] = isUSBConnected(context)
            map["root"] = isDeviceRooted
            map["imei"] = getUniqueDeviceId(true) ?: ""
            LogUtils.e("imei 11111111", getUniqueDeviceId(true))
            return map
        }
    }
}

ShellUtils.kt(mac地址需要)

package com.uz.cashloanuzi.grab;

import androidx.annotation.NonNull;

import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.List;

public final class ShellUtils {

    private static final String LINE_SEP = System.getProperty("line.separator");

    private ShellUtils() {
        throw new UnsupportedOperationException("u can't instantiate me...");
    }


    public static CommandResult execCmd(final String command, final boolean isRooted) {
        return execCmd(new String[]{command}, isRooted, true);
    }

    /**
     * Execute the command.
     *
     * @param commands        The commands.
     * @param isRooted        True to use root, false otherwise.
     * @param isNeedResultMsg True to return the message of result, false otherwise.
     * @return the single {@link CommandResult} instance
     */
    public static CommandResult execCmd(final String[] commands,
                                        final boolean isRooted,
                                        final boolean isNeedResultMsg) {
        return execCmd(commands, null, isRooted, isNeedResultMsg);
    }

    /**
     * Execute the command.
     *
     * @param commands        The commands.
     * @param envp            Array of strings, each element of which
     *                        has environment variable settings in the format
     *                        <i>name</i>=<i>value</i>, or
     *                        <tt>null</tt> if the subprocess should inherit
     *                        the environment of the current process.
     * @param isRooted        True to use root, false otherwise.
     * @param isNeedResultMsg True to return the message of result, false otherwise.
     * @return the single {@link CommandResult} instance
     */
    public static CommandResult execCmd(final String[] commands,
                                        final String[] envp,
                                        final boolean isRooted,
                                        final boolean isNeedResultMsg) {
        int result = -1;
        if (commands == null || commands.length == 0) {
            return new CommandResult(result, "", "");
        }
        Process process = null;
        BufferedReader successResult = null;
        BufferedReader errorResult = null;
        StringBuilder successMsg = null;
        StringBuilder errorMsg = null;
        DataOutputStream os = null;
        try {
            process = Runtime.getRuntime().exec(isRooted ? "su" : "sh", envp, null);
            os = new DataOutputStream(process.getOutputStream());
            for (String command : commands) {
                if (command == null) continue;
                os.write(command.getBytes());
                os.writeBytes(LINE_SEP);
                os.flush();
            }
            os.writeBytes("exit" + LINE_SEP);
            os.flush();
            result = process.waitFor();
            if (isNeedResultMsg) {
                successMsg = new StringBuilder();
                errorMsg = new StringBuilder();
                successResult = new BufferedReader(
                        new InputStreamReader(process.getInputStream(), "UTF-8")
                );
                errorResult = new BufferedReader(
                        new InputStreamReader(process.getErrorStream(), "UTF-8")
                );
                String line;
                if ((line = successResult.readLine()) != null) {
                    successMsg.append(line);
                    while ((line = successResult.readLine()) != null) {
                        successMsg.append(LINE_SEP).append(line);
                    }
                }
                if ((line = errorResult.readLine()) != null) {
                    errorMsg.append(line);
                    while ((line = errorResult.readLine()) != null) {
                        errorMsg.append(LINE_SEP).append(line);
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (os != null) {
                    os.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                if (successResult != null) {
                    successResult.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                if (errorResult != null) {
                    errorResult.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            if (process != null) {
                process.destroy();
            }
        }
        return new CommandResult(
                result,
                successMsg == null ? "" : successMsg.toString(),
                errorMsg == null ? "" : errorMsg.toString()
        );
    }

    /**
     * The result of command.
     */
    public static class CommandResult {
        public int    result;
        public String successMsg;
        public String errorMsg;

        public CommandResult(final int result, final String successMsg, final String errorMsg) {
            this.result = result;
            this.successMsg = successMsg;
            this.errorMsg = errorMsg;
        }

        @Override
        public String toString() {
            return "result: " + result + "\n" +
                    "successMsg: " + successMsg + "\n" +
                    "errorMsg: " + errorMsg;
        }
    }
}

三.一些备注

1.设备ID  deviceId 和 imei

关于设备ID,很久之前可以直接获取IMEI,后面因为Android迭代,这玩意儿现在都拿不到了。

因为需要敏感权限"android.permission.READ_PRIVILEGED_PHONE_STATE" 

这权限很多时候谷歌是不会允许普通应用拿到的。我现在返回的是AndroidID

    fun getDeviceIdentifier(context: Context): String {
            val telephonyManager =
                context.getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager
            return when {
                Build.VERSION.SDK_INT < Build.VERSION_CODES.O -> {
                    telephonyManager.deviceId
                }

                Build.VERSION.SDK_INT in Build.VERSION_CODES.O until Build.VERSION_CODES.Q -> {
                    telephonyManager.imei
                }

                else -> {
                    Settings.Secure.getString(context.contentResolver, Settings.Secure.ANDROID_ID)
                }
            }
        }
2.相关权限

这上面主要需要READ_PHONE_STATE和ACCESS_WIFI_STATE及ACCESS_COARSE_LOCATION这三个权限,需要在manifest进行声明哦,这三个权限在谷歌审核比较好过

3.备注

里面还有一些方法因为项目需求没有用到,所以我也没有删。

当然,风控有时候也不止需要这些数据,后面再进行补充吧,上面得方法里得具体数据是啥意思可以看我上面得注释。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

&岁月不待人&

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值