在做某些项目时,需要上传必要的设备信息给服务器用于风控
在此做一下总结。
一.获取的数据
主要包含下面数据
设备id |
操作系统版本 |
设备型号 |
IMSI |
路由器mac地址 |
设备mac地址 |
安卓id |
经度 |
纬度 |
ip地址 |
谷歌广告id |
手机可用内存 |
apk可用内存 |
apk可分配的最大内存 |
手机总内存 |
cpu主频 |
屏幕解析度 |
网络类型 |
是否调用usb |
是否开启模拟器 |
电池电量 |
是否root过 |
设备总存储 |
设备可用存储 |
设备uuid |
设备imei |
sim卡槽状态 |
二.具体实现代码
DeviceUtils.kt
package com.uz.cashloanuzi.grabimport 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.UUIDclass DeviceUtils private constructor() {companion object {val isDeviceRooted: Booleanget() {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: Stringget() = Build.VERSION.RELEASEval sDKVersionCode: Intget() = Build.VERSION.SDK_INT@get:SuppressLint("HardwareIds")val androidID: Stringget() {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: Stringget() {val macAddress = getMacAddress(*(null as Array<String?>?)!!)if (!TextUtils.isEmpty(macAddress) || wifiEnabled) return macAddresswifiEnabled = truewifiEnabled = falsereturn getMacAddress(*(null as Array<String?>?)!!)}@set:RequiresPermission(permission.CHANGE_WIFI_STATE)private var wifiEnabled: Booleanget() {@SuppressLint("WifiManagerLeak") val manager = application?.getSystemService(Context.WIFI_SERVICE) as WifiManager?: return falsereturn 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?: returnif (enabled == manager.isWifiEnabled) returnmanager.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 = macAddressByNetworkInterfaceif (isAddressNotInExcepts(macAddress, excepts)) {return macAddress}macAddress = macAddressByInetAddressif (isAddressNotInExcepts(macAddress, excepts)) {return macAddress}macAddress = macAddressByWifiInfoif (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: Stringget() {try {val wifi = application?.getApplicationContext()?.getSystemService(Context.WIFI_SERVICE) as WifiManagerif (wifi != null) {val info = wifi.connectionInfoif (info != null) {@SuppressLint("HardwareIds") val macAddress = info.macAddressif (!TextUtils.isEmpty(macAddress)) {return macAddress}}}} catch (e: Exception) {e.printStackTrace()}return "02:00:00:00:00:00"}private val macAddressByNetworkInterface: Stringget() {try {val nis = NetworkInterface.getNetworkInterfaces()while (nis.hasMoreElements()) {val ni = nis.nextElement()if (ni == null || !ni.name.equals("wlan0", ignoreCase = true)) continueval macBytes = ni.hardwareAddressif (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: Stringget() {try {val inetAddress = inetAddressif (inetAddress != null) {val ni = NetworkInterface.getByInetAddress(inetAddress)if (ni != null) {val macBytes = ni.hardwareAddressif (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) continueval addresses = ni.inetAddresseswhile (addresses.hasMoreElements()) {val inetAddress = addresses.nextElement()if (!inetAddress.isLoopbackAddress) {val hostAddress = inetAddress.hostAddressif (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.successMsgresult = execCmd("cat /sys/class/net/$name/address", false)if (result.result === 0) {val address: String = result.successMsgif (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.MANUFACTURERval model: Stringget() {var model = Build.MODELmodel = 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.screenLayoutand 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.PRODUCTif (checkProperty) return truevar operatorName = ""val tm =application?.getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManagerif (tm != null) {val name = tm.networkOperatorNameif (name != null) {operatorName = name}}val checkOperatorName = operatorName.equals("android", ignoreCase = true)if (checkOperatorName) return trueval url = "tel:" + "123456"val intent = Intent()intent.setData(Uri.parse(url))intent.setAction(Intent.ACTION_DIAL)val checkDial = intent.resolveActivity(application!!.packageManager) == nullif (checkDial) return trueif (isEmulatorByCpu) return truereturn 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) > 0private const val KEY_UDID = "KEY_UDID"@Volatileprivate var udid: String? = nullval 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 = idreturn udid}return getUniqueDeviceIdReal(prefix)}}}return udid}private fun getUniqueDeviceIdReal(prefix: String): String? {try {val androidId = androidIDif (!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 TelephonyManagerreturn 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 TelephonyManagerreturn 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 UsbManagerval usbDevices = usbManager.deviceList// Check if any USB devices are connectedreturn usbDevices.isNotEmpty()}@SuppressLint("DefaultLocale")fun getLatitude(context: Context): BigDecimal? {// 获取位置(经纬度)(需要 LOCATION 权限)val locationManager =context.getSystemService(Context.LOCATION_SERVICE) as LocationManagerval 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?.latitudereturn 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 LocationManagerval 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?.longitudereturn 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 WifiManagerval wifiInfo = wifiManager.connectionInforeturn 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 TelephonyManagerval simState = telephonyManager.simStatereturn 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.displayMetricsreturn "${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 MBreturn totalStorage.toDouble()}//可用磁盘fun getAvailableRomStorage(context: Context): Double {val stat = StatFs(context.filesDir.path)// 设备可用存储val availableStorage = stat.availableBytes / 1024 / 1024 // in MBreturn availableStorage.toDouble()}//路由器地址fun getRouterMacAddress(context: Context): String? {val wifiManager =context.applicationContext.getSystemService(Context.WIFI_SERVICE) as WifiManagerval wifiInfo = wifiManager.connectionInforeturn 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 reasonswifiInfo.bssid} else {// On Android 8.1 and lower, the BSSID (MAC address of the access point) is available directlywifiInfo.bssid}}fun getNetworkType(context: Context): Int {val telephonyManager =context.getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManagerreturn if (ActivityCompat.checkSelfPermission(context,permission.READ_PHONE_STATE) != PackageManager.PERMISSION_GRANTED) {LogUtils.e("permission","permission.READ_PHONE_STATE")return -1} elsetelephonyManager.networkType}suspend fun getDeviceInfo(context: Context): Map<String, Any> {val map: MutableMap<String, Any> = HashMap()map["deviceId"] = getUniqueDeviceId(true) ?: ""map["os"] = Build.VERSION.RELEASEmap["imsi"] = getIMSI(context)map["deviceMac"] = getMacAddress("")map["routerMac"] = getRouterMacAddress(context) ?: ""map["androidId"] = androidIDmap["lng"] = getLongitude(context)?:AppConstant.DECIMAL_DEFAULT_VALUEmap["lat"] = getLatitude(context)?:AppConstant.DECIMAL_DEFAULT_VALUEmap["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()//UUIDmap["simState"] = getSimState(context)//simStatemap["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"] = isDeviceRootedmap["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;}@Overridepublic 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 TelephonyManagerreturn 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.备注
里面还有一些方法因为项目需求没有用到,所以我也没有删。
当然,风控有时候也不止需要这些数据,后面再进行补充吧,上面得方法里得具体数据是啥意思可以看我上面得注释。