做APP的设备注册是,一般会获取设备的唯一码,以唯一码做依据进行设备信息注册。针对这种小成本的app,一般是采用uni-app做开发,而我们这个app还只是做了app的外壳,内部使用的html5,所以一般使用H5+的方式获取设备唯一码。依据官方文档介绍,可以使用getInfo的方法。
获取到的设备信息,其中有一个UUID,就是设备的唯一标识号
这种方式原本是通用的,只是在某些厂商定制的系统中就出问题了,比如海信的设备,他们的设备做了很多定制化的改动,电视机系统连APK都拦截掉了。实在没想到的是连UUID的值也做了处理,现场的同批次设备,返回的UUID竟然都是一样的。
只能另外寻找出路,参考了网上的资料。
1、使用mac地址,不过是安卓的方式,需要写java代码才能兼容各种安卓版本,原生安卓比较合适。《Android获取Mac地址-适配所有版本》
2、使用h5+调用原生安卓的方法(native.js),获取机器id。经测试,与getInfo获取的uuid一样的,同批次设备都一样。
var mainActivity = plus.android.runtimeMainActivity(); var Settings = plus.android.importClass("android.provider.Settings"); var machineNo = Settings.Secure.getString(mainActivity.getContentResolver(), Settings.Secure.ANDROID_ID);
3、使用h5+调用原生安卓的方法(native.js),获取serialNo。这是需要READ_PHONE_STATE权限的。做了安卓版本的兼容处理。
经过测试,安卓6的海信电视机和皓丽的安卓8触控屏都能正常获取serialNo,但是安卓8的设备返回的是123456789,估计也是厂商做的处理。并且现场的设备(安卓9),以及自己的手机(安卓11)都是返回的Unknown。
查找资料《解决Android 11 获取不到Serial number方法》,应该是源码层面做了某些处理。只是这种处理方式,在我这里不适用。
function getSerialNo() { const Build = window.plus.android.importClass('android.os.Build') const Manifest = window.plus.android.importClass('android.Manifest') const SystemProperties = window.plus.android.importClass('android.os.SystemProperties') const MainActivity = window.plus.android.runtimeMainActivity() const ArrPermissions = [ Manifest.permission.READ_PHONE_STATE ] const PermissionCheck = (permission) => { if (Build.VERSION.SDK_INT >= 23) { if (MainActivity.checkSelfPermission(permission) === -1) { return false } } return true } const PermissionChecks = (Arr) => { let HasPermission = true for (var index in Arr) { const permission = Arr[index] // 如果此处没有权限,则是用户拒绝了 if (!PermissionCheck(permission)) { HasPermission = false break } } return HasPermission } const PermissionRequest = (Arr) => { const REQUEST_CODE_CONTACT = 101 if (Build.VERSION.SDK_INT >= 23) { mui.toast('申请权限') MainActivity.requestPermissions(Arr, REQUEST_CODE_CONTACT) } } if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { // 9.0+ // 如果没有权限,则申请 if (!PermissionChecks(ArrPermissions)) { PermissionRequest(ArrPermissions) } else { // 如果拥有权限,那么干点啥吧^_^ return Build.getSerial() } } else if (Build.VERSION.SDK_INT > Build.VERSION_CODES.N) { // 8.0+ if (Build.SERIAL) { return Build.SERIAL } } else { if (SystemProperties.get('ro.serialno')) { return SystemProperties.get('ro.serialno') } } }
4、参考资料《ANDROID设备唯一识别码的获取》自己生成UUID储存到设备中,如果已有信息就读取。这种方式在本场景下稍微有些麻烦,需要h5端与app端交互,由app读写文件,所以也没有采用。
5、参考以上方案,通过设备参数信息生成唯一id。其中使用了Fingerprint2组件用作生成uuid。
function getSerialNo() { const info = {} const Build = window.plus.android.importClass('android.os.Build') info.board = Build.BOARD// 主板 info.brand = Build.BRAND// 系统定制商 info.supportedAbis = Build.SUPPORTED_ABIS// CPU指令集 info.device = Build.DEVICE// 设备参数 info.display = Build.DISPLAY// 显示屏参数 info.fingerprint = Build.FINGERPRINT// 唯一编号 info.serial = Build.SERIAL// 硬件序列号 info.id = Build.ID// 修订版本列表 info.manufacturer = Build.MANUFACTURER// 硬件制造商 info.model = Build.MODEL// 版本 info.hardware = Build.HARDWARE// 硬件名 info.product = Build.PRODUCT// 手机产品名 info.tags = Build.TAGS// 描述Build的标签 info.type = Build.TYPE// Builder类型 info.codename = Build.VERSION.CODENAME// 当前开发代码 info.incremental = Build.VERSION.INCREMENTAL// 源码控制版本号 info.release = Build.VERSION.RELEASE// 版本字符串 info.sdkInt = Build.VERSION.SDK_INT// 版本号 info.host = Build.HOST// Host值 info.user = Build.USER// User名 // info.time = Build.TIME// 编译时间 const murmur = Fingerprint2.x64hash128(JSON.stringify(info), 20) return murmur }
最终采用了方案5,可行性还需要验证,提供了公共方法,兼容app模式(常规设备和特殊厂商设备)和浏览器模式,获取设备唯一号
import Fingerprint2 from 'fingerprintjs2' /** * 获取设备号 并存放到db中 */ function getDeviceUUID(callback) { // 显示模式 const showModel = matchUrlParam('', 'showModel') || window.localStorage.getItem('showModel') || 'windows' // app 环境 使用html5Plus获取设备号 if (showModel === 'app') { // 根据h5Plus获取信息 const getInfoByPlus = () => { const vendor = window.plus.device.vendor if (vendor && vendor.toLowerCase().indexOf('hisense') !== -1) { const uuid = getSerialNo() window.localStorage.setItem('deviceUUID', uuid) // 设备号 if (callback) { callback() } } else { window.plus.device.getInfo({ success: (e) => { window.localStorage.setItem('deviceUUID', e.uuid) // 设备号 if (callback) { callback() } } }) } } if (window.plus) { getInfoByPlus() } else { // 监听H5Plus准备事件 window.document.addEventListener('plusready', getInfoByPlus, false) } // windows 环境 使用Fingerprint2获取唯一编号 } else { Fingerprint2.get(function(components) { const values = components.filter(item => ['platform', 'canvas', 'webgl', 'webglVendorAndRenderer'].includes(item.key)).map(function(component) { return component.value }) const murmur = Fingerprint2.x64hash128(values.join(''), 31) window.localStorage.setItem('deviceUUID', murmur) // 设备号 if (callback) { callback() } }) } } function getSerialNo() { const info = {} const Build = window.plus.android.importClass('android.os.Build') info.board = Build.BOARD// 主板 info.brand = Build.BRAND// 系统定制商 info.supportedAbis = Build.SUPPORTED_ABIS// CPU指令集 info.device = Build.DEVICE// 设备参数 info.display = Build.DISPLAY// 显示屏参数 info.fingerprint = Build.FINGERPRINT// 唯一编号 info.serial = Build.SERIAL// 硬件序列号 info.id = Build.ID// 修订版本列表 info.manufacturer = Build.MANUFACTURER// 硬件制造商 info.model = Build.MODEL// 版本 info.hardware = Build.HARDWARE// 硬件名 info.product = Build.PRODUCT// 手机产品名 info.tags = Build.TAGS// 描述Build的标签 info.type = Build.TYPE// Builder类型 info.codename = Build.VERSION.CODENAME// 当前开发代码 info.incremental = Build.VERSION.INCREMENTAL// 源码控制版本号 info.release = Build.VERSION.RELEASE// 版本字符串 info.sdkInt = Build.VERSION.SDK_INT// 版本号 info.host = Build.HOST// Host值 info.user = Build.USER// User名 // info.time = Build.TIME// 编译时间 const murmur = Fingerprint2.x64hash128(JSON.stringify(info), 20) return murmur }
后续
经过测试,发现并未成功解决问题,同批次设备获取的唯一码还是相同的,因为设备参数信息都一样。所以基于上文方案四,衍生出来了终极解决方案《踩坑系列之h5plus获取设备唯一码终极方案》。
还没有评论,来说两句吧...