Unity获取手机设备唯一标识-方案探讨

前言

公司开发的游戏需要对用户设备进行标识,获得一个稳定可靠并且唯一的识别码,来作游客登录。并考虑后续玩家从游客换成账户登录数据要同步过来。

虽然Android系统中提供了这样设备识别码,但是由于Android系统版本、厂商定制系统中的Bug等限制,稳定性和唯一性并不理想。而通过其他硬件信息标识也因为系统版本、手机硬件等限制存在不同程度的问题。

下面汇总了一些能作为设备唯一标识的方案。

方案

方案大致分为三个方向,第一个方向就是安卓系统提供的一系列接口,获取具有唯一属性的码,比如imei,MAC,android_id等;第二个方向就是unity自带的API;第三个方向就是自定义计算ID。

一.安卓系统原生

如果不会unity与安卓交互可参考我的上一篇博客:Android与Unity交互及手机震动控制

安卓系统获取串码
参考资料: 获取Android设备唯一标识码
参考资料: 获取Android设备的唯一标识符
参考资料: Android设备唯一标识
参考资料: Android 手机获取Mac地址的方法

主要串码:

IMEI:(国际移动设备识别码(IMEI:International Mobile Equipment Identification Number)是区别移动设备的标志,储存在移动设备中,可用于监控被窃或无效的移动设备。

android系统中通常用下面这段代码获取:

/**
 * 获取手机IMEI号
 * 
 * 需要动态权限: android.permission.READ_PHONE_STATE
 */
public static String getIMEI(Context context) {
        TelephonyManager telephonyManager = (TelephonyManager) context.getSystemService(context.TELEPHONY_SERVICE);
        String imei = telephonyManager.getDeviceId();

        return imei;
    }

MEID:Mobile Equipment IDentifier(MEID)是全球唯一的56bit移动终端标识号。标识号会被烧入终端里,并且不能被修改。
没有统一的获取方法!

MAC ADDRESS:(Media Access Control Address),直译为媒体存取控制位址,也称为局域网地址(LAN Address),MAC位址,以太网地址(Ethernet Address)或物理地址(Physical Address),它是一个用来确认网络设备位置的位址。

android系统中通常用下面这段代码获取:

/**
     * 通过WiFiManager获取mac地址
     * @param context
     * @return
     */
    private static String tryGetWifiMac(Context context) {
        WifiManager wm = (WifiManager) context.getApplicationContext().getSystemService(Context.WIFI_SERVICE);
        WifiInfo wi = wm.getConnectionInfo();
        if (wi == null || wi.getMacAddress() == null) {
            return null;
        }
        if ("02:00:00:00:00:00".equals(wi.getMacAddress().trim())) {
            return null;
        } else {
            return wi.getMacAddress().trim();
        }
    }

ANDROID_ID:在设备首次启动时,系统会随机生成一个64位的数字,并把这个数字以16进制字符串的形式保存下来,这个16进制的字符串就是ANDROID_ID,当设备被wipe后该值会被重置。

android系统中通常用下面这段代码获取:

 String ANDROID_ID = Settings.System.getString(getContentResolver(), Settings.System.ANDROID_ID); 

android.os.Build:根据手机硬件的型号返回串码,所以不同手机具有不同的串码,但是同型号的手机会重码。

android系统中通常用下面这段代码获取:

设备序列号(Serial Number, SN)
String serialNum = android.os.Build.SERIAL;

制造商 (Manufacturer)
String manufacturer = android.os.Build.MANUFACTURER;

型号(Model)
String model = android.os.Build.MODEL;

品牌(Brand)
String brand = android.os.Build.BRAND;

设备名 (Device)
String device = android.os.Build.DEVICE;

二.Unity自带API

参考资料官方API文档
使用Unity自带的API,SystemInfo.deviceUniqueIdentifier获取。

string 设备唯一标识符= SystemInfo.deviceUniqueIdentifier;

三.自定义计算ID

这一套方案就是,服务器端采用流水号算法生成唯一码,然后下推给客户端,客户端将这个唯一码保存,最好设置为初始时自动截屏把唯一码保存在相册里。

方案对比

在这里插入图片描述

踩坑与解决

  • 天坑1:在采用安卓系统原生的方案时,起初使用的是imei码,装上手机发现重号。后来发现这个码在安卓P之后压根不让你获取,会返回空值,所以重号。

  • 天坑2:后来加上设备硬件计算串码,刚开始还好,没什么问题,后来两台同型号的手机鬼使神差般的重号了,原因是当手机型号相同,通过手机硬件获取的串码就会一样,那么重号就不奇怪了。

  • 天坑3:在采用了 imei和硬件设备串码后,还得继续添加新的串码段,经研究android_id的串码是imei后最为合适的,然后就把android_id加上了,这下很欣喜发现不重号了,同型号手机也不同号,好了可以放心了。好景不长,原先打包的同学没在不能打包了,于是用自己的电脑打包,这下好,一安装,全体的ID都成新的了,之前升级了的数据都不在了。研究了好久,发现自Android 8.0(API级别26)起,ANDROID_ID取决于应用程序的签名密钥。这意味着“未签名”构建(默认情况下使用调试密钥库进行签名)的值将不同于已签名构建(使用播放器设置中提供的密钥进行签名)。所以也就有了换一台机器打包就有不同的串码值。

  • 解决:踩了这么多坑怎么解决呢?如上面所说,想要达到不同的机器打包出的串码都是一致的,需要做一个密钥,然后大家的电脑都使用这个密钥,然后结合 ANDROID_ID返回的串码使用。这样 获取手机设备唯一标识算告一段落了。但仍不是完美的方案。

  • 不完美 :为什么上述的不是完美的方案呢?因为各手机厂商不同ANDROID_ID的计算方式有所不同,会可能出现重号的现象,概率很小。除此之外由于Android系统版本、厂商定制系统中的Bug等限制,稳定性和唯一性并不理想。使用的体量一大,说不定也会出现重号和换号的情况。那有没有更好的方案,我想没有,但有可选方案,就是我上面说的自定义ID,这个方案的好处是,可以保证ID的唯一性,缺点就是玩家一旦卸载,再重新安装就会视为新用户,如果想找回账户,得查看手机里自动保存到相册的账号图片,经过一番找回操作才行。万一玩家将这张图片删除或清除了,那想要找回就只能是天方夜谭。

总结

获取设备唯一标识符没有完美的方案,做联网手游应当拒绝这个需求,直接引导玩家进行账号注册。
当然在临时测试阶段使用安卓系统原生的方式,是一个不错的选择。

文中的代码及工程下载:Android2Unity.zip

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值