import{_ as l,c as o,b as e,a as t,d as a,e as p,w as c,r,o as d}from"./app-Dgsdh8A6.js";const i={};function D(y,s){const n=r("RouteLink");return d(),o("div",null,[s[3]||(s[3]=e("h1",{id:"设备各类标识算法-app-端",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#设备各类标识算法-app-端"},[e("span",null,"设备各类标识算法(APP 端)")])],-1)),s[4]||(s[4]=e("h2",{id:"设备唯一标识-buvid",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#设备唯一标识-buvid"},[e("span",null,"设备唯一标识 BUVID")])],-1)),e("p",null,[s[1]||(s[1]=a("注意区分于 Web 端的 ")),p(n,{to:"/docs/misc/buvid3_4.html"},{default:c(()=>s[0]||(s[0]=[a("buvid3, buvid4")])),_:1,__:[0]}),s[2]||(s[2]=a("."))]),s[5]||(s[5]=t(`
BUVID 在 APP 首次安装于某设备, 且首次启动时生成.
APP 首次(即每次安装后)启动, 会向云端发送本机各类设备特征, 含 AndroidId, DrmId 等, 请求是否有匹配的 BUVID, 有就使用云端的, 否则使用本地生成的.
APP 请求是否有匹配的 BUVID 发送的本机各类设备特征包括(但不限于):
AndroidIDDrmIdIMEIOAIDMAC选定设备特征码, 可以是 AndroidID, DrmId, 手机网卡 MAC 等. 记为 ID. 特别地, MAC 应当去掉 :, GUID(即 UUID) 应当去掉 -.
计算 ID 的 MD5. 记为 ID_MD5.
从 ID_MD5 抽取第 3, 13, 23 位, 失败就默认为 000, 记为 ID_E.
根据选定的设备特征码类型确定 BUVID Prefix, 见附录. 记为 BUVID_Prefix.
按 {BUVID_Prefix}{ID_E}{ID_MD5} 的顺序连接起来, 共37位(2+3+32). 结果应当为大写.
代码及测试样例见 Rust Playground.
用于请求账户相关 REST API, 及 gRPC Metadata 生成.
在请求头中, fp_local 和 fp_remote 设置为同一值即可, 暂不清楚区别.
获取 BUVID. 此处一般使用 XU Prefix 的 BUVID.
获取设备 Model(Build.MODEL), 如 NOH-AN01.
获取手机无线电固件版本号(Build.getRadioVersion()), 失败则留空. 如 21C20B686S000C000,21C20B686S000C000.
按前述顺序拼接字符串, 计算得 MD5.
获取年月日, 格式 yyyyMMddhhmmss, 拼接到 4 得到的字符串后.
生成 16 位随机字符串, CharSet 为 0123456789abcdef, 拼接到 5 得到的字符串后, 记为 fp_raw.
计算得到一个特殊字符串, 拼接到 fp_raw 后, 即得到最终的 fp, 特殊字符串算法见下:
let mut veri_code = 0;
// 有点像 HEX 的操作
let fp_raw_sub_str = fp_raw
.as_bytes() // 将字符串 fp_raw 转换为字节数组
.chunks(2) // 按每两个字节一组进行切分
.map(|s| unsafe { ::std::str::from_utf8_unchecked(s) }) // 对每一组解析作为 UTF-8 字符串
.collect::<Vec<_>>(); // 将结果收集到 Vec 中
// 如果 fp_raw 的长度小于 62, 则向下取偶数减半作为循环终止条件, 否则终止条件为31
for i in 0..({
if fp_raw.len() < 62 {
fp_raw.len() - fp_raw.len() % 2 // 取偶数
} else {
62
}
} / 2)
{
// 将每组字符串转换为对应的 16 进制整数, 将转换得到的整数加到 veri_code 上.
veri_code += i32::from_str_radix(fp_raw_sub_str[i], 16).unwrap_or(0);
}
// 最后将 veri_code 对 256 取余, 格式化为两位的 16 进制字符串
let veri_code = format!("{:0>2x}", veri_code % 256);代码及测试样例见 Rust Playground.
| 设备特征码 | BUVID Prefix | 备注 |
|---|---|---|
AndroidID | XX | |
DrmId | XU | |
IMEI | XZ | 已弃用 |
GUID | XW | 已弃用 |
MAC | XY | |
GoogleId | XG | 东南亚版本 |
FacebookId | XF | 东南亚版本 |