做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获取设备唯一码终极方案》。



还没有评论,来说两句吧...