diff --git a/uni_modules/uni-getDeviceInfo/changelog.md b/uni_modules/uni-getDeviceInfo/changelog.md new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/uni_modules/uni-getDeviceInfo/package.json b/uni_modules/uni-getDeviceInfo/package.json new file mode 100644 index 0000000000000000000000000000000000000000..829829c4bf57034c620371d08147b8479dd6922d --- /dev/null +++ b/uni_modules/uni-getDeviceInfo/package.json @@ -0,0 +1,93 @@ +{ + "id": "uni-getDeviceInfo", + "displayName": "uni-getDeviceInfo", + "version": "1.0.0", + "description": "uni-getDeviceInfo", + "keywords": [ + "uni-getDeviceInfo" + ], + "repository": "", + "engines": { + "HBuilderX": "^3.6.8" + }, + "dcloudext": { + "type": "uts", + "sale": { + "regular": { + "price": "0.00" + }, + "sourcecode": { + "price": "0.00" + } + }, + "contact": { + "qq": "" + }, + "declaration": { + "ads": "", + "data": "", + "permissions": "" + }, + "npmurl": "" + }, + "uni_modules": { + "dependencies": [], + "uni-ext-api": { + "uni": { + "getDeviceInfo": { + "name": "getDeviceInfo", + "app": { + "js": false, + "kotlin": true, + "swift": true + } + } + } + }, + "encrypt": [], + "platforms": { + "cloud": { + "tcb": "u", + "aliyun": "u" + }, + "client": { + "Vue": { + "vue2": "u", + "vue3": "u" + }, + "App": { + "app-android": "u", + "app-ios": "u" + }, + "H5-mobile": { + "Safari": "u", + "Android Browser": "u", + "微信浏览器(Android)": "u", + "QQ浏览器(Android)": "u" + }, + "H5-pc": { + "Chrome": "u", + "IE": "u", + "Edge": "u", + "Firefox": "u", + "Safari": "u" + }, + "小程序": { + "微信": "u", + "阿里": "u", + "百度": "u", + "字节跳动": "u", + "QQ": "u", + "钉钉": "u", + "快手": "u", + "飞书": "u", + "京东": "u" + }, + "快应用": { + "华为": "u", + "联盟": "u" + } + } + } + } +} \ No newline at end of file diff --git a/uni_modules/uni-getDeviceInfo/readme.md b/uni_modules/uni-getDeviceInfo/readme.md new file mode 100644 index 0000000000000000000000000000000000000000..3e334985e6adf19dc6d31c1586f09e8e18b807bf --- /dev/null +++ b/uni_modules/uni-getDeviceInfo/readme.md @@ -0,0 +1,5 @@ +# uni-getDeviceInfo +### 开发文档 +[UTS 语法](https://uniapp.dcloud.net.cn/tutorial/syntax-uts.html) +[UTS 原生插件](https://uniapp.dcloud.net.cn/plugin/uts-plugin.html) +[Hello UTS](https://gitcode.net/dcloud/hello-uts/-/tree/dev) \ No newline at end of file diff --git a/uni_modules/uni-getDeviceInfo/utssdk/app-android/device/DeviceUtil.uts b/uni_modules/uni-getDeviceInfo/utssdk/app-android/device/DeviceUtil.uts new file mode 100644 index 0000000000000000000000000000000000000000..47bf8b49fa207eba8fbb63506fa294467b317b43 --- /dev/null +++ b/uni_modules/uni-getDeviceInfo/utssdk/app-android/device/DeviceUtil.uts @@ -0,0 +1,382 @@ +import Activity from 'android.app.Activity'; +import Configuration from 'android.content.res.Configuration'; +import Context from 'android.content.Context'; +import UiModeManager from 'android.app.UiModeManager'; +import WindowManager from 'android.view.WindowManager'; +import DisplayMetrics from 'android.util.DisplayMetrics'; +import Build from 'android.os.Build'; +import File from 'java.io.File'; + +import { EmulatorCheckUtil } from './EmulatorCheckUtil.uts' +import TextUtils from 'android.text.TextUtils'; + +import { UTSAndroid as Device } from "io.dcloud.uts"; +import BufferedReader from 'java.io.BufferedReader'; +import InputStreamReader from 'java.io.InputStreamReader'; +import Exception from 'java.lang.Exception'; +import KotlinArray from 'kotlin.Array' + + +export class DeviceUtil { + + private static customOS: string | null = null + private static customOSVersion: string | null = null + + private static readonly rootRelatedDirs = [ + "/su", "/su/bin/su", "/sbin/su", + "/data/local/xbin/su", "/data/local/bin/su", "/data/local/su", + "/system/xbin/su", + "/system/bin/su", "/system/sd/xbin/su", "/system/bin/failsafe/su", + "/system/bin/cufsdosck", "/system/xbin/cufsdosck", "/system/bin/cufsmgr", + "/system/xbin/cufsmgr", "/system/bin/cufaevdd", "/system/xbin/cufaevdd", + "/system/bin/conbb", "/system/xbin/conbb"]; + + + /** + * HarmonyOS 系统输出的 + * 格式:2.0.0 + */ + private static KEY_HARMONYOS_VERSION_NAME = "hw_sc.build.platform.version"; + + /** + * EMUI系统输出的 + * 格式:EmotionUI_8.0.0 + */ + private static KEY_EMUI_VERSION_NAME = "ro.build.version.emui"; + + /** + * MagicUI系统输出的 + * 格式:3.1.0 + */ + private static KEY_MAGICUI_VERSION = "ro.build.version.magic"; + + /** + * MIUI系统输出的 + * 格式:V12 + */ + private static KEY_MIUI_VERSION_NAME = "ro.miui.ui.version.name"; + + /** + * OPPO手机ColorOS系统输出的 + * 格式:9 + */ + private static KEY_COLOROS_VERSION_NAME = "ro.build.version.opporom"; + + /** + * VIVO手机系统输出的 + * name格式:funtouch + * version格式: 9 + */ + private static KEY_VIVO_VERSION_NAME = "ro.vivo.os.name"; + private static KEY_VIVO_VERSION = "ro.vivo.os.version"; + + /** + * OonPlus手机系统输出的 + * 格式:Hydrogen OS 11.0.7.10.KB05 + */ + private static KEY_ONEPLUS_VERSION_NAME = "ro.rom.version"; + + /** + * 魅族手机系统输出的 + */ + private static KEY_FLYME_VERSION_NAME = "ro.build.display.id"; + + /** + * nubia手机系统输出的 + */ + private static KEY_NUBIA_VERSION_NAME = "ro.build.nubia.rom.name"; + private static KEY_NUBIA_VERSION_CODE = "ro.build.nubia.rom.code"; + + + + public static getOrientation(activity: Activity): string { + const activityOrientation = activity.getResources().getConfiguration().orientation; + let outOrientation = "portrait"; + if (activityOrientation == Configuration.ORIENTATION_LANDSCAPE) { + outOrientation = "landscape"; + } + return outOrientation; + } + + /** + * 获取屏幕像素比 + */ + public static getScaledDensity(activity: Activity): number { + const windowManager = activity.getSystemService(Context.WINDOW_SERVICE) as WindowManager; + const displayMetrics = new DisplayMetrics(); + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { + windowManager.getDefaultDisplay().getRealMetrics(displayMetrics); + } else { + windowManager.getDefaultDisplay().getMetrics(displayMetrics); + } + return displayMetrics.scaledDensity; + } + + public static getSystemUIModeType(activity: Activity): string { + + let uiModeManager = activity.getSystemService(Context.UI_MODE_SERVICE) as UiModeManager; + let modeType = "unknown"; + + switch (uiModeManager.getCurrentModeType()) { + case Configuration.UI_MODE_TYPE_TELEVISION: + modeType = "tv"; + break; + case Configuration.UI_MODE_TYPE_WATCH: + modeType = "watch"; + break; + case Configuration.UI_MODE_TYPE_NORMAL: + if (DeviceUtil.isTablet(activity)) { + modeType = "pad"; + } else { + modeType = "phone"; + } + break; + case Configuration.UI_MODE_TYPE_DESK: + modeType = "pc"; + break; + case Configuration.UI_MODE_TYPE_UNDEFINED: + modeType = "undefined"; + break; + case Configuration.UI_MODE_TYPE_CAR: + modeType = "car"; + break; + case Configuration.UI_MODE_TYPE_VR_HEADSET: + modeType = "vr"; + break; + case Configuration.UI_MODE_TYPE_APPLIANCE: + modeType = "appliance"; + break; + } + + return modeType; + } + + + /** + * 是否root + */ + public static hasRootPrivilege(): boolean { + let hasRootDir = false; + let rootDirs = DeviceUtil.rootRelatedDirs; + let dirCount = rootDirs.length; + let i = 0; + while (i < dirCount) { + let dir = rootDirs[i]; + if ((new File(dir)).exists()) { + hasRootDir = true; + break; + } + i++; + } + + + return Build.TAGS != null && Build.TAGS.includes("test-keys") || hasRootDir; + } + + public static isSimulator(context: Context): boolean { + return EmulatorCheckUtil.getSingleInstance().emulatorCheck(context); + } + + + public static getDeviceID(context: Context): string { + return Device.getDeviceID(context); + } + + + public static getOsLanguage(context: Context): string { + return Device.getLanguageInfo(context)["osLanguage"].toString(); + } + + public static getOsLanguageNormal(context: Context): string { + const LOCALE_ZH_HANS = 'zh-Hans' + const LOCALE_ZH_HANT = 'zh-Hant' + let locale = Device.getLanguageInfo(context)["appLanguage"].toString(); + if (locale.indexOf('zh') === 0) { + if (locale.indexOf('-hans') > -1) { + return LOCALE_ZH_HANS; + } + if (locale.indexOf('-hant') > -1) { + return LOCALE_ZH_HANT; + } + if (locale.includes("-tw") || locale.includes("-hk") || locale.includes("-mo") || locale.includes("-cht")) { + return LOCALE_ZH_HANT; + } + + return LOCALE_ZH_HANS; + } else { + return locale; + } + } + + public static getAppInnerVersion(): string { + return Device.getInnerVersion(); + } + + public static getOaid(): string { + return Device.getOAID(); + } + + + /** + * 是否为平板 不是太准确 + */ + public static isTablet(activity: Activity): boolean { + return (activity.getResources().getConfiguration().screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) >= Configuration.SCREENLAYOUT_SIZE_LARGE; + } + + + + private static setCustomInfo(phoneBrand: string) { + try { + switch (DeviceUtil.deleteSpaceAndToUpperCase(phoneBrand)) { + case "HUAWEI": + if (DeviceUtil.isHarmonyOS()) { + DeviceUtil.customOSVersion = DeviceUtil.getSystemPropertyValue(DeviceUtil.KEY_HARMONYOS_VERSION_NAME); + DeviceUtil.customOS = "HarmonyOS"; + } else { + DeviceUtil.customOS = "EMUI"; + DeviceUtil.customOSVersion = DeviceUtil.getSystemPropertyValue(DeviceUtil.KEY_EMUI_VERSION_NAME);; + } + break; + case "HONOR": + if (DeviceUtil.isHarmonyOS()) { + DeviceUtil.customOS = "HarmonyOS"; + if (!TextUtils.isEmpty(DeviceUtil.getSystemPropertyValue(DeviceUtil.KEY_HARMONYOS_VERSION_NAME))) { + DeviceUtil.customOSVersion = DeviceUtil.getSystemPropertyValue(DeviceUtil.KEY_HARMONYOS_VERSION_NAME);; + } else { + DeviceUtil.customOSVersion = ""; + } + } else if (!TextUtils.isEmpty(DeviceUtil.getSystemPropertyValue(DeviceUtil.KEY_MAGICUI_VERSION))) { + DeviceUtil.customOS = "MagicUI"; + DeviceUtil.customOSVersion = DeviceUtil.getSystemPropertyValue(DeviceUtil.KEY_MAGICUI_VERSION); + } else { + //格式:EmotionUI_8.0.0 + DeviceUtil.customOS = "EMUI"; + DeviceUtil.customOSVersion = DeviceUtil.getSystemPropertyValue(DeviceUtil.KEY_EMUI_VERSION_NAME); + } + break; + case "XIAOMI": + case "REDMI": + //格式:MIUIV12 + DeviceUtil.customOS = "MIUI"; + DeviceUtil.customOSVersion = DeviceUtil.getSystemPropertyValue(DeviceUtil.KEY_MIUI_VERSION_NAME); + break; + case "REALME": + case "OPPO": + //格式:ColorOSV2.1 + DeviceUtil.customOS = "ColorOS"; + DeviceUtil.customOSVersion = DeviceUtil.getSystemPropertyValue(DeviceUtil.KEY_COLOROS_VERSION_NAME); + break; + case "VIVO": + //格式:Funtouch9 + DeviceUtil.customOS = "Funtouch"; + DeviceUtil.customOSVersion = DeviceUtil.getSystemPropertyValue(DeviceUtil.KEY_VIVO_VERSION); + break; + case "ONEPLUS": + //格式:Hydrogen OS 11.0.7.10.KB05 + DeviceUtil.customOS = "HydrogenOS"; + DeviceUtil.customOSVersion = DeviceUtil.getSystemPropertyValue(DeviceUtil.KEY_ONEPLUS_VERSION_NAME); + break; + case "MEIZU": + //格式:Flyme 6.3.5.1G + DeviceUtil.customOS = "Flyme"; + DeviceUtil.customOSVersion = DeviceUtil.getSystemPropertyValue(DeviceUtil.KEY_FLYME_VERSION_NAME); + break; + case "NUBIA": + //格式:nubiaUIV3.0 + DeviceUtil.customOS = DeviceUtil.getSystemPropertyValue(DeviceUtil.KEY_NUBIA_VERSION_NAME); + DeviceUtil.customOSVersion = DeviceUtil.getSystemPropertyValue(DeviceUtil.KEY_NUBIA_VERSION_CODE); + break; + default: + DeviceUtil.customOS = "Android"; + DeviceUtil.customOSVersion = Build.VERSION.RELEASE; + break; + } + } catch (e: Exception) { + } + } + + + + /** + * 判断是否是华为鸿蒙系统,能否识别荣耀鸿蒙未知 + * + * @return + */ + private static isHarmonyOS(): boolean { + try { + let classType = Class.forName("com.huawei.system.BuildEx"); + let getMethod = classType.getMethod("getOsBrand"); + let value = getMethod.invoke(classType) as string; + return !TextUtils.isEmpty(value); + } catch (e: Exception) { + return false; + } + } + + + + + + + /** + * 删除字符串中的空格并全部转成大写 + * @param str + * @return + */ + public static deleteSpaceAndToUpperCase(str: string | null): string { + if (TextUtils.isEmpty(str)) { + return ""; + } + return str!.replace(" ", "").toUpperCase(); + } + + private static getSystemPropertyValue(propName: string): string | null { + let value: string | null = null; + let roSecureObj: any | null; + try { + // Class.forName("java.lang.String") + const method = Class.forName("android.os.SystemProperties").getMethod("get", Class.forName("java.lang.String")); + roSecureObj = method.invoke(null, propName); + if (roSecureObj != null) { + value = roSecureObj as string; + } + } catch (e: Exception) { + } + return value; + } + + public static listeningForADB(): boolean { + let cmd : KotlinArray = arrayOf("/bin/sh", "-c", "getprop | grep init.svc.adbd"); + try{ + Runtime.getRuntime().exec(cmd); + }catch(e:Exception){ + cmd = arrayOf("/system/bin/sh", "-c", "getprop | grep init.svc.adbd"); + try{ + Runtime.getRuntime().exec(cmd); + }catch(e:Exception){ + return false + } + } + let exec = Runtime.getRuntime().exec(cmd); + let bufferedReader = new BufferedReader(new InputStreamReader(exec.getInputStream(), "utf-8")); + let tmp = new CharArray(1024); + + let result = false; + + do { + let len = bufferedReader.read(tmp); + if (len == -1) { + break; + } + let res = new String(tmp, 0, len); + result = res.includes("running"); + } while (true) + + exec.getInputStream().close(); + bufferedReader.close(); + return result; + } +} + diff --git a/uni_modules/uni-getDeviceInfo/utssdk/app-android/device/EmulatorCheckUtil.uts b/uni_modules/uni-getDeviceInfo/utssdk/app-android/device/EmulatorCheckUtil.uts new file mode 100644 index 0000000000000000000000000000000000000000..537a19b2aa4b1f8d359263ba554afb7faacaea5a --- /dev/null +++ b/uni_modules/uni-getDeviceInfo/utssdk/app-android/device/EmulatorCheckUtil.uts @@ -0,0 +1,393 @@ +import Context from "android.content.Context"; +import Locale from "java.util.Locale"; +import File from "java.io.File"; +import SensorManager from "android.hardware.SensorManager"; +import Sensor from "android.hardware.Sensor"; +import PackageManager from 'android.content.pm.PackageManager'; +class CheckResult { + public result: Int; + public value: string | null; + + constructor(result: Int, value: string | null) { + this.result = result; + this.value = value; + } +} + +export class EmulatorCheckUtil { + private static INSTANCE: EmulatorCheckUtil | null = null; + + public static readonly RESULT_MAYBE_EMULATOR:Int = 0; //可能是模拟器 + public static readonly RESULT_EMULATOR:Int = 1; //模拟器 + public static readonly RESULT_UNKNOWN:Int = 2; //可能是真机 + + private static known_pkgNames =[ + "sdcard/Android/data/com.bluestacks.home", //蓝叠 + "sdcard/Android/data/com.bluestacks.settings", //蓝叠 + "sdcard/Android/data/com.microvirt.guide", //逍遥 + "sdcard/Android/data/com.microvirt.launcher2" //逍遥 + ]; + + public static getSingleInstance(): EmulatorCheckUtil { + if (EmulatorCheckUtil.INSTANCE == null) { + EmulatorCheckUtil.INSTANCE = new EmulatorCheckUtil(); + } + return EmulatorCheckUtil.INSTANCE!; + } + + public emulatorCheck(context: Context): boolean { + if (context == null) { + throw new IllegalArgumentException("context must not be null"); + } + + let suspectCount = 0; + + //检测硬件名称 + let hardwareResult = this.checkFeaturesByHardware(); + switch (hardwareResult.result) { + case EmulatorCheckUtil.RESULT_MAYBE_EMULATOR: + ++suspectCount; + break; + case EmulatorCheckUtil.RESULT_EMULATOR: + return true; + } + + //通过pkgName检测 + let blueStacksResult = this.checkPkgNameForEmulator(); + switch (blueStacksResult.result) { + case EmulatorCheckUtil.RESULT_MAYBE_EMULATOR: + ++suspectCount; + break; + case EmulatorCheckUtil.RESULT_EMULATOR: + return true; + } + + //检测渠道 + let flavorResult = this.checkFeaturesByFlavor(); + switch (flavorResult.result) { + case EmulatorCheckUtil.RESULT_MAYBE_EMULATOR: + ++suspectCount; + break; + case EmulatorCheckUtil.RESULT_EMULATOR: + return true; + } + + //检测设备型号 + let modelResult = this.checkFeaturesByModel(); + switch (modelResult.result) { + case EmulatorCheckUtil.RESULT_MAYBE_EMULATOR: + ++suspectCount; + break; + case EmulatorCheckUtil.RESULT_EMULATOR: + return true; + } + + //检测硬件制造商 + let manufacturerResult = this.checkFeaturesByManufacturer(); + switch (manufacturerResult.result) { + case EmulatorCheckUtil.RESULT_MAYBE_EMULATOR: + ++suspectCount; + break; + case EmulatorCheckUtil.RESULT_EMULATOR: + return true; + } + + //检测主板名称 + let boardResult = this.checkFeaturesByBoard(); + switch (boardResult.result) { + case EmulatorCheckUtil.RESULT_MAYBE_EMULATOR: + ++suspectCount; + break; + case EmulatorCheckUtil.RESULT_EMULATOR: + return true; + } + + //检测主板平台 + let platformResult = this.checkFeaturesByPlatform(); + switch (platformResult.result) { + case EmulatorCheckUtil.RESULT_MAYBE_EMULATOR: + ++suspectCount; + break; + case EmulatorCheckUtil.RESULT_EMULATOR: + return true; + } + + //检测基带信息 + let baseBandResult = this.checkFeaturesByBaseBand(); + switch (baseBandResult.result) { + case EmulatorCheckUtil.RESULT_MAYBE_EMULATOR: + suspectCount += 2; //模拟器基带信息为null的情况概率相当大 + break; + case EmulatorCheckUtil.RESULT_EMULATOR: + return true; + } + + //检测传感器数量 + let sensorNumber = this.getSensorNumber(context); + if (sensorNumber <= 7) ++suspectCount; + + //检测已安装第三方应用数量 + /*int userAppNumber = getUserAppNumber(); + if (userAppNumber <= 5) ++suspectCount;*/ + + //检测是否支持闪光灯 + let supportCameraFlash = this.supportCameraFlash(context); + if (!supportCameraFlash) ++suspectCount; + + //检测是否支持蓝牙 + let supportBluetooth = this.supportBluetooth(context); + if (!supportBluetooth) ++suspectCount; + + //检测光线传感器 + let hasLightSensor = this.hasLightSensor(context); + if (!hasLightSensor) ++suspectCount; + + //检测进程组信息 + /*CheckResult cgroupResult = checkFeaturesByCgroup(); + if (cgroupResult.result == RESULT_MAYBE_EMULATOR) ++suspectCount;*/ + + //嫌疑值大于3,认为是模拟器 + return suspectCount > 3; + } + + private getProperty(propName: string): string | null { + let value: string | null = null; + let roSecureObj: any | null = null; + try { + const method = Class.forName("android.os.SystemProperties").getMethod( + "get", + Class.forName("java.lang.String") + ); + roSecureObj = method.invoke(null, propName); + if (roSecureObj != null) { + value = roSecureObj as string; + } + } catch (e: Exception) { + } + return value; + } + + /** + * 特征参数-硬件名称 + * + * @return 0表示可能是模拟器,1表示模拟器,2表示可能是真机 + */ + private checkFeaturesByHardware(): CheckResult { + let hardware = this.getProperty("ro.hardware"); + if (null == hardware) { + return new CheckResult(EmulatorCheckUtil.RESULT_MAYBE_EMULATOR, null); + } + let result: Int | null; + let tempValue = hardware.toLowerCase(Locale.ENGLISH); + switch (tempValue) { + case "ttvm": //天天模拟器 + case "nox": //夜神模拟器 + case "cancro": //网易MUMU模拟器 + case "intel": //逍遥模拟器 + case "vbox": + case "vbox86": //腾讯手游助手 + case "android_x86": //雷电模拟器 + result = EmulatorCheckUtil.RESULT_EMULATOR; + break; + default: + result = EmulatorCheckUtil.RESULT_UNKNOWN; + break; + } + return new CheckResult(result, hardware); + } + + /** + * 特征参数-渠道 + * + * @return 0表示可能是模拟器,1表示模拟器,2表示可能是真机 + */ + private checkFeaturesByFlavor(): CheckResult { + let flavor = this.getProperty("ro.build.flavor"); + if (null == flavor) { + return new CheckResult(EmulatorCheckUtil.RESULT_MAYBE_EMULATOR, null); + } + let result: Int | null; + let tempValue = flavor.toLowerCase(Locale.ENGLISH); + if (tempValue.includes("vbox")) { + result = EmulatorCheckUtil.RESULT_EMULATOR; + } else if (tempValue.includes("sdk_gphone")) { + result = EmulatorCheckUtil.RESULT_EMULATOR; + } else { + result = EmulatorCheckUtil.RESULT_UNKNOWN; + } + return new CheckResult(result, flavor); + } + + private checkPkgNameForEmulator(): CheckResult { + let result = EmulatorCheckUtil.RESULT_UNKNOWN; + let accordSize = 0; + for (let i = 0; i < EmulatorCheckUtil.known_pkgNames.length; i++) { + let file_name = EmulatorCheckUtil.known_pkgNames[i]; + let qemu_file = new File(file_name); + if (qemu_file.exists()) { + accordSize++; + } else { + result = EmulatorCheckUtil.RESULT_MAYBE_EMULATOR; + } + if (accordSize > 2) { + break; + } + } + switch (accordSize) { + case 1: { + result = EmulatorCheckUtil.RESULT_MAYBE_EMULATOR; + break; + } + case 2: { + result = EmulatorCheckUtil.RESULT_EMULATOR; + break; + } + } + return new CheckResult(result, "PkgName"); + } + + /** + * 特征参数-设备型号 + * + * @return 0表示可能是模拟器,1表示模拟器,2表示可能是真机 + */ + private checkFeaturesByModel(): CheckResult { + let model = this.getProperty("ro.product.model"); + if (null == model) { + return new CheckResult(EmulatorCheckUtil.RESULT_MAYBE_EMULATOR, null); + } + let result: Int | null; + let tempValue = model.toLowerCase(Locale.ENGLISH); + if (tempValue.includes("google_sdk")) { + result = EmulatorCheckUtil.RESULT_EMULATOR; + } else if (tempValue.includes("emulator")) { + result = EmulatorCheckUtil.RESULT_EMULATOR; + } else if (tempValue.includes("android sdk built for x86")) { + result = EmulatorCheckUtil.RESULT_EMULATOR; + } else { + result = EmulatorCheckUtil.RESULT_UNKNOWN; + } + return new CheckResult(result, model); + } + + /** + * 特征参数-硬件制造商 + * + * @return 0表示可能是模拟器,1表示模拟器,2表示可能是真机 + */ + private checkFeaturesByManufacturer(): CheckResult { + let manufacturer = this.getProperty("ro.product.manufacturer"); + if (null == manufacturer) + return new CheckResult(EmulatorCheckUtil.RESULT_MAYBE_EMULATOR, null); + let result: Int | null; + let tempValue = manufacturer.toLowerCase(Locale.ENGLISH); + if (tempValue.includes("genymotion")) { + result = EmulatorCheckUtil.RESULT_EMULATOR; + } else if (tempValue.includes("netease")) { + result = EmulatorCheckUtil.RESULT_EMULATOR; //网易MUMU模拟器 + } else { + result = EmulatorCheckUtil.RESULT_UNKNOWN; + } + return new CheckResult(result, manufacturer); + } + + /** + * 特征参数-主板名称 + * + * @return 0表示可能是模拟器,1表示模拟器,2表示可能是真机 + */ + private checkFeaturesByBoard(): CheckResult { + let board = this.getProperty("ro.product.board"); + if (null == board) { + return new CheckResult(EmulatorCheckUtil.RESULT_MAYBE_EMULATOR, null); + } + let result: Int | null; + let tempValue = board.toLowerCase(Locale.ENGLISH); + if (tempValue.includes("android")) { + result = EmulatorCheckUtil.RESULT_EMULATOR; + } else if (tempValue.includes("goldfish")) { + result = EmulatorCheckUtil.RESULT_EMULATOR; + } else { + result = EmulatorCheckUtil.RESULT_UNKNOWN; + } + return new CheckResult(result, board); + } + + /** + * 特征参数-主板平台 + * + * @return 0表示可能是模拟器,1表示模拟器,2表示可能是真机 + */ + private checkFeaturesByPlatform(): CheckResult { + let platform = this.getProperty("ro.board.platform"); + if (null == platform) + return new CheckResult(EmulatorCheckUtil.RESULT_MAYBE_EMULATOR, null); + let result: Int | null; + let tempValue = platform.toLowerCase(Locale.ENGLISH); + if (tempValue.includes("android")) { + result = EmulatorCheckUtil.RESULT_EMULATOR; + } else { + result = EmulatorCheckUtil.RESULT_UNKNOWN; + } + return new CheckResult(result, platform); + } + + /** + * 特征参数-基带信息 + * + * @return 0表示可能是模拟器,1表示模拟器,2表示可能是真机 + */ + private checkFeaturesByBaseBand(): CheckResult { + let baseBandVersion = this.getProperty("gsm.version.baseband"); + if (null == baseBandVersion) { + return new CheckResult(EmulatorCheckUtil.RESULT_MAYBE_EMULATOR, null); + } + let result: Int | null; + if (baseBandVersion.includes("1.0.0.0")) { + result = EmulatorCheckUtil.RESULT_EMULATOR; + } else { + result = EmulatorCheckUtil.RESULT_UNKNOWN; + } + return new CheckResult(result, baseBandVersion); + } + + /** + * 获取传感器数量 + */ + private getSensorNumber(context: Context): Int { + let sm = context.getSystemService(Context.SENSOR_SERVICE) as SensorManager; + return sm.getSensorList(Sensor.TYPE_ALL).size; + } + + /** + * 是否支持闪光灯 + */ + private supportCameraFlash(context: Context): boolean { + return context + .getPackageManager() + .hasSystemFeature(PackageManager.FEATURE_CAMERA_FLASH); + } + + /** + * 是否支持蓝牙 + */ + private supportBluetooth(context: Context): boolean { + return context + .getPackageManager() + .hasSystemFeature(PackageManager.FEATURE_BLUETOOTH); + } + + /** + * 判断是否存在光传感器来判断是否为模拟器 + * 部分真机也不存在温度和压力传感器。其余传感器模拟器也存在。 + * + * @return false为模拟器 + */ + private hasLightSensor(context: Context): boolean { + let sensorManager = context.getSystemService( + Context.SENSOR_SERVICE + ) as SensorManager; + let sensor = sensorManager.getDefaultSensor(Sensor.TYPE_LIGHT); //光线传感器 + return null != sensor; + } +} diff --git a/uni_modules/uni-getDeviceInfo/utssdk/app-android/index.uts b/uni_modules/uni-getDeviceInfo/utssdk/app-android/index.uts new file mode 100644 index 0000000000000000000000000000000000000000..89659c9915f27ff23a00e93c1d9be5d27b314bd0 --- /dev/null +++ b/uni_modules/uni-getDeviceInfo/utssdk/app-android/index.uts @@ -0,0 +1,82 @@ +import Build from 'android.os.Build'; +import { UTSAndroid } from "io.dcloud.uts"; +import { DeviceUtil } from './device/DeviceUtil.uts'; + +import { GetDeviceInfo, GetDeviceInfoOptions, GetDeviceInfoResult } from '../interface.uts' + + +export const getDeviceInfo : GetDeviceInfo = (config : GetDeviceInfoOptions | null) : GetDeviceInfoResult => { + let filter : Array = []; + if (config != null && config.filter != null) { + filter = config.filter; + } + + if (config == null || filter.length == 0) { + const defaultFilter = [ + "brand", + "deviceBrand", + "deviceId", + "model", + "deviceModel", + "deviceType", + "deviceOrientation", + "devicePixelRatio", + "system", + "platform", + "oaid", + "isRoot", + "isSimulator", + "isUSBDebugging" + ]; + filter = defaultFilter; + } + return getBaseInfo(filter); +} + +function getBaseInfo(filterArray : Array) : GetDeviceInfoResult { + const activity = UTSAndroid.getUniActivity()!; + let result : GetDeviceInfoResult = {}; + if (filterArray.indexOf("brand") != -1) { + result.brand = Build.MANUFACTURER; + } + if (filterArray.indexOf("deviceBrand") != -1) { + result.deviceBrand = Build.MANUFACTURER; + } + if (filterArray.indexOf("model") != -1) { + result.model = Build.MODEL; + } + if (filterArray.indexOf("deviceModel") != -1) { + result.deviceModel = Build.MODEL; + } + if (filterArray.indexOf("deviceType") != -1) { + result.deviceType = DeviceUtil.getSystemUIModeType(activity); + } + if (filterArray.indexOf("deviceOrientation") != -1) { + result.deviceOrientation = DeviceUtil.getOrientation(activity); + } + if (filterArray.indexOf("deviceId") != -1) { + result.deviceId = DeviceUtil.getDeviceID(activity); + } + if (filterArray.indexOf("devicePixelRatio") != -1) { + result.devicePixelRatio = DeviceUtil.getScaledDensity(activity) + ""; + } + if (filterArray.indexOf("system") != -1) { + result.system = "Android " + Build.VERSION.RELEASE; + } + if (filterArray.indexOf("platform") != -1) { + result.platform = "android"; + } + if (filterArray.indexOf("oaid") != -1) { + result.oaid = DeviceUtil.getOaid(); + } + if (filterArray.indexOf("isRoot") != -1) { + result.isRoot = DeviceUtil.hasRootPrivilege(); + } + if (filterArray.indexOf("isSimulator") != -1) { + result.isSimulator = DeviceUtil.isSimulator(activity); + } + if (filterArray.indexOf("isUSBDebugging") != -1) { + result.isUSBDebugging = DeviceUtil.listeningForADB(); + } + return result; +} \ No newline at end of file diff --git a/uni_modules/uni-getDeviceInfo/utssdk/app-ios/device/DeviceUtil.uts b/uni_modules/uni-getDeviceInfo/utssdk/app-ios/device/DeviceUtil.uts new file mode 100644 index 0000000000000000000000000000000000000000..2d39d8c9ad70e9ada324e09450df6edd353e1790 --- /dev/null +++ b/uni_modules/uni-getDeviceInfo/utssdk/app-ios/device/DeviceUtil.uts @@ -0,0 +1,82 @@ +import { UIDevice, UIApplication, UIInterfaceOrientation, UIScreen } from 'UIKit'; +import { NSLocale, URL, FileManager } from 'Foundation'; +import { ATTrackingManager } from 'AppTrackingTransparency'; +import { ASIdentifierManager } from 'AdSupport'; +import { DispatchSemaphore, DispatchQueue } from 'Dispatch'; + + + +export class DeviceUtil { + + public static isPad(): boolean { + return UIDevice.current.userInterfaceIdiom == UIUserInterfaceIdiom.pad + } + + public static getOSVersion(): string { + return UIDevice.current.systemVersion; + } + + public static getLan(): string { + let currentLanguage = NSLocale.preferredLanguages[0]; + return currentLanguage == null ? "" : currentLanguage + } + + public static getOrientation(): string { + let orientation = "portrait"; + DispatchQueue.main.sync(execute = () => { + const orient = UIApplication.shared.statusBarOrientation; + if (orient == UIInterfaceOrientation.landscapeLeft || orient == UIInterfaceOrientation.landscapeRight) { + orientation = "landscape"; + } + }) + return orientation; + } + + public static getScreenScale(): string { + return UIScreen.main.scale.description; + } + + + public static getIdfa(): string { + if (UTSiOS.available("iOS 14, *")) { + if (ATTrackingManager.trackingAuthorizationStatus == ATTrackingManager.AuthorizationStatus.notDetermined) { + ATTrackingManager.requestTrackingAuthorization(completionHandler = (status) => { }); + } else if (ATTrackingManager.trackingAuthorizationStatus == ATTrackingManager.AuthorizationStatus.authorized) { + return ASIdentifierManager.shared().advertisingIdentifier.uuidString; + } + return ""; + } + + return ASIdentifierManager.shared().advertisingIdentifier.uuidString; + } + + public static hasRootPrivilege(): boolean { + let url = new URL(string = "cydia://"); + let canOpenUrl = false; + DispatchQueue.main.sync(execute = () => { + canOpenUrl = UIApplication.shared.canOpenURL(url!) + }) + if (canOpenUrl) { + return true; + } + + let jailbreakToolPaths = [ + "/Applications/Cydia.app", + "/Library/MobileSubstrate/MobileSubstrate.dylib", + "/bin/bash", + "/usr/sbin/sshd", + "/etc/apt" + ]; + + let i = 0; + while (i < jailbreakToolPaths.length) { + if (FileManager.default.fileExists(atPath = jailbreakToolPaths[i])) { + return true; + } + i++; + } + + + return false; + } +} \ No newline at end of file diff --git a/uni_modules/uni-getDeviceInfo/utssdk/app-ios/index.uts b/uni_modules/uni-getDeviceInfo/utssdk/app-ios/index.uts new file mode 100644 index 0000000000000000000000000000000000000000..bf6d6b31c2fb90b09ed968f2a814cbc4899e54ed --- /dev/null +++ b/uni_modules/uni-getDeviceInfo/utssdk/app-ios/index.uts @@ -0,0 +1,80 @@ + +import { UTSiOS } from "DCloudUTSFoundation"; +import { DeviceUtil } from './device/DeviceUtil.uts'; + +import { GetDeviceInfo, GetDeviceInfoOptions, GetDeviceInfoResult } from '../interface.uts' + +export const getDeviceInfo : GetDeviceInfo = (config : GetDeviceInfoOptions | null) : GetDeviceInfoResult => { + let filter : Array = []; + if (config != null && config?.filter != null) { + let temp = config?.filter; + filter = temp!; + } + + if (config == null || filter.length == 0) { + const defaultFilter = [ + "brand", + "deviceBrand", + "deviceId", + "model", + "deviceModel", + "deviceType", + "deviceOrientation", + "devicePixelRatio", + "system", + "platform", + "idfa", + "isRoot", + "isSimulator" + ]; + filter = defaultFilter; + } + return getBaseInfo(filter); +} + + +function getBaseInfo(filterArray : Array) : GetDeviceInfoResult { + const osVersion = DeviceUtil.getOSVersion(); + let result : GetDeviceInfoResult = {}; + if (filterArray.indexOf("brand") != -1) { + result.brand = "apple"; + } + if (filterArray.indexOf("deviceBrand") != -1) { + result.deviceBrand = "apple"; + } + if (filterArray.indexOf("deviceId") != -1) { + result.deviceId = UTSiOS.getDeviceId(); + } + if (filterArray.indexOf("model") != -1) { + result.model = UTSiOS.getModel(); + } + if (filterArray.indexOf("deviceModel") != -1) { + result.deviceModel = UTSiOS.getModel(); + } + if (filterArray.indexOf("deviceType") != -1) { + result.deviceType = DeviceUtil.isPad() ? "pad" : "phone"; + } + if (filterArray.indexOf("deviceOrientation") != -1) { + result.deviceOrientation = DeviceUtil.getOrientation(); + } + if (filterArray.indexOf("devicePixelRatio") != -1) { + result.devicePixelRatio = DeviceUtil.getScreenScale(); + } + if (filterArray.indexOf("system") != -1) { + result.system = String(format = "iOS %@", osVersion); + } + if (filterArray.indexOf("platform") != -1) { + result.platform = "ios"; + } + if (filterArray.indexOf("idfa") != -1) { + result.idfa = DeviceUtil.getIdfa(); + } + if (filterArray.indexOf("isRoot") != -1) { + result.isRoot = DeviceUtil.hasRootPrivilege(); + } + if (filterArray.indexOf("isSimulator") != -1) { + result.isSimulator = UTSiOS.isSimulator(); + } + + return result; +} \ No newline at end of file diff --git a/uni_modules/uni-getDeviceInfo/utssdk/interface.uts b/uni_modules/uni-getDeviceInfo/utssdk/interface.uts new file mode 100644 index 0000000000000000000000000000000000000000..10f846a857d9b241cac3642a8d3a7d082128f07a --- /dev/null +++ b/uni_modules/uni-getDeviceInfo/utssdk/interface.uts @@ -0,0 +1,156 @@ +export type GetDeviceInfoOptions = { + /** + * @description 过滤字段的字符串数组,假如要获取指定字段,传入此数组。 + */ + filter: Array +} + +export type GetDeviceInfoResult = { + /** + * 设备品牌 + */ + brand?: string + /** + * 设备品牌 + */ + deviceBrand?: string, + /** + * 设备 id 。由 uni-app 框架生成并存储,清空 Storage 会导致改变 + */ + deviceId?: string, + /** + * 设备型号 + */ + model?: string, + /** + * 设备型号 + */ + deviceModel?: string, + /** + * 设备类型phone、pad、pc + */ + deviceType?: string, + /** + * 设备方向 竖屏 portrait、横屏 landscape + */ + deviceOrientation?: string, + /** + * 设备像素比 + */ + devicePixelRatio?: string, + /** + * 操作系统及版本 + */ + system?: string, + /** + * 客户端平台 + */ + platform?: string, + /** + * oaid标识 Android专有 + * + * @uniPlatform { + * "app": { + * "android": { + * "osVer": "5.0", + * "uniVer": "√", + * "unixVer": "√" + * }, + * "ios": { + * "osVer": "9.0", + * "uniVer": "x", + * "unixVer": "x" + * } + * } + * } + */ + oaid?: string, + /** + * 是否root + */ + isRoot?: boolean, + /** + * 是否是模拟器 + */ + isSimulator?: boolean, + /** + * adb是否开启 + * + * @uniPlatform { + * "app": { + * "android": { + * "osVer": "5.0", + * "uniVer": "√", + * "unixVer": "√" + * }, + * "ios": { + * "osVer": "9.0", + * "uniVer": "x", + * "unixVer": "x" + * } + * } + * } + */ + isUSBDebugging?: boolean, + /** + * idfa标识 iOS专有 + * + * @uniPlatform { + * "app": { + * "android": { + * "osVer": "5.0", + * "uniVer": "x", + * "unixVer": "x" + * }, + * "ios": { + * "osVer": "9.0", + * "uniVer": "√", + * "unixVer": "√" + * } + * } + * } + */ + idfa?: string, + /** + * 应用平台 + */ +} + + +/** + * @param [options=包含所有字段的过滤对象] 过滤的字段对象, 不传参数默认为获取全部字段。 + */ +export type GetDeviceInfo = (options?: GetDeviceInfoOptions | null) => GetDeviceInfoResult; + + +export interface Uni { + /** + * GetDeviceInfo(Object object) + * @description + * 获取设备信息 + * @param {GetDeviceInfoOptions} options [options=包含所有字段的过滤对象] 过滤的字段对象, 不传参数默认为获取全部字段。 + * @return {object} + * @tutorial https://uniapp.dcloud.net.cn/api/system/getDeviceInfo.html + * @uniPlatform { + * "app": { + * "android": { + * "osVer": "4.4", + * "uniVer": "√", + * "unixVer": "3.9+" + * }, + * "ios": { + * "osVer": "9.0", + * "uniVer": "√", + * "unixVer": "3.9+" + * } + * } + * } + * @example + ```typescript + uni.getDeviceInfo({ + filter:[] + }) + ``` + */ + getDeviceInfo(options?: GetDeviceInfoOptions | null): GetDeviceInfoResult; +}