android APP 唯一鉴别,Android6.0以上获取APP设备唯一标识的正确姿势

问题

在用户没有登录的情况下必须确保设备的唯一性,于是惯性思维想到的肯定是使用DevicesId 来作为设备的唯一标识。

但Android6.0后google对权限加以限制和国内rom的不同等原因导致无法一个稳定的唯一标示

常见唯一标示

imei

Android_id

mac地址

Installtion ID : UUID

Pseudo-Unique ID

IMEI

获取权限

获取方法

TelephonyManager telephonyManager =(TelephonyManager)context.getSystemService(context.TELEPHONY_SERVICE);

String imei = telephonyManager.getDeviceId();

问题:

Android6.0后当无法获取到该权限后,方法直接报错,imei作为唯一标示可靠性太差。

Android_id

获取

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

问题:

Android_id是不需要权限,但它跟手机rom和手机厂商有关(Android_id是设备首次运行随机生成的64位数字)有点手机是获取不到,恢复出厂设置时也会改变,可靠性也较差

Mac地址

获取方法

/**

* Android 6.0 之前(不包括6.0)获取mac地址

* 必须的权限

* @param context * @return

*/

public static String getMacDefault(Context context) {

String mac = "";

if (context == null) {

return mac;

}

WifiManager wifi = (WifiManager)context.getApplicationContext().getSystemService(Context.WIFI_SERVICE);

WifiInfo info = null;

try {

info = wifi.getConnectionInfo();

} catch (Exception e) {

e.printStackTrace();

}

if (info == null) {

return null;

}

mac = info.getMacAddress();

if (!TextUtils.isEmpty(mac)) {

mac = mac.toUpperCase(Locale.ENGLISH);

}

return mac;

}

/**

* Android 6.0-Android 7.0 获取mac地址

*/

public static String getMacAddress() {

String macSerial = null;

String str = "";

try {

Process pp = Runtime.getRuntime().exec("cat/sys/class/net/wlan0/address");

InputStreamReader ir = new InputStreamReader(pp.getInputStream());

LineNumberReader input = new LineNumberReader(ir);

while (null != str) {

str = input.readLine();

if (str != null) {

macSerial = str.trim();//去空格

break;

}

}

} catch (IOException ex) {

// 赋予默认值

ex.printStackTrace();

}

return macSerial;

}

/**

* 通过网络接口取

* @return

*/

private static String getNewMac() {

try {

Listall = Collections.list(NetworkInterface.getNetworkInterfaces());

for (NetworkInterface nif : all) {

if (!nif.getName().equalsIgnoreCase("wlan0")) continue;

byte[] macBytes = nif.getHardwareAddress();

if (macBytes == null) {

return null;

}

StringBuilder res1 = new StringBuilder();

for (byte b : macBytes) {

res1.append(String.format("%02X:", b));

}

if (res1.length() > 0) {

res1.deleteCharAt(res1.length() - 1);

}

return res1.toString();

}

} catch (Exception ex) {

ex.printStackTrace();

}

return null;

}

/**

* 获取mac地址(适配所有Android版本)

* @return

*/

public static String getMac( Context context) {

String mac = "";

if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {

mac = getMacDefault(context);

} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {

mac = getMacAddress();

} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {

mac = getNewMac();

}

return mac;

}

问题:

手机必须具有上网功能,使用场景有局限性

Installtion ID : UUID

这种方式的原理是在程序安装后第一次运行时生成一个ID,该方式和设备唯一标识不一样,不同的应用程序会产生不同的ID,同一个程序重新安装也会不同。所以这不是设备的唯一ID,但是可以保证每个用户的ID是不同的。可以说是用来标识每一份应用程序的唯一ID(即Installtion ID),可以用来跟踪应用的安装数量等。

获取方法

public class Installation {

private static String sID = null;

private static final String INSTALLATION = "INSTALLATION";

public synchronized static String id(Context context) {

if (sID == null) {

File installation = new File(context.getFilesDir(), INSTALLATION);

try {

if (!installation.exists())

writeInstallationFile(installation);

sID = readInstallationFile(installation);

} catch (Exception e) {

throw new RuntimeException(e);

}

}

return sID;

}

private static String readInstallationFile(File installation) throws IOException {

RandomAccessFile f = new RandomAccessFile(installation, "r");

byte[] bytes = new byte[(int) f.length()];

f.readFully(bytes);

f.close();

return new String(bytes);

}

private static void writeInstallationFile(File installation) throws IOException {

FileOutputStream out = new FileOutputStream(installation);

String id = UUID.randomUUID().toString();

out.write(id.getBytes());

out.close();

}

}

问题:

无法唯一的标示,多次安装多次不同

Pseudo-Unique ID

/**

* Return pseudo unique ID

*

* @return ID

*/

public static String getUniquePsuedoDeviceID() {

// If all else fails, if the user does have lower than API 9 (lower

// than Gingerbread), has reset their device or 'Secure.ANDROID_ID'

// returns 'null', then simply the ID returned will be solely based

// off their Android device information. This is where the collisions

// can happen.

// Thanks http://www.pocketmagic.net/?p=1662!

// Try not to use DISPLAY, HOST or ID - these items could change.

// If there are collisions, there will be overlapping data

String m_szDevIDShort = "35" +

(Build.BOARD.length() % 10) +

(Build.BRAND.length() % 10) +

(Build.CPU_ABI.length() % 10) +

(Build.DEVICE.length() % 10) +

(Build.MANUFACTURER.length() % 10) +

(Build.MODEL.length() % 10) +

(Build.PRODUCT.length() % 10);

// Log.i("", "getUniquePsuedoDeviceID: "+m_szDevIDShort);

// Only devices with API >= 9 have android.os.Build.SERIAL

String serial = null;

try {

serial = Build.class.getField("SERIAL").get(null).toString();

// Go ahead and return the serial for api => 9

return new UUID(m_szDevIDShort.hashCode(), serial.hashCode()).toString();

} catch (Exception exception) {

// String needs to be initialized

serial = "serial"; // some value

}

// Thanks @Joe!

// http://stackoverflow.com/a/2853253/950427

// Finally, combine the values we have found by using the UUID class to create a unique identifier

return new UUID(m_szDevIDShort.hashCode(), serial.hashCode()).toString();

}

问题:

模拟器和刷机带来的一样的id,但能保证99.5%的成功率

总结

到现在发现没有一个是完全靠谱的方式,那就呵呵。

那就其他人是咋解决的呢?发现无外乎这些方法,那大厂是如何解决的呢?

解决

utdid4all-1.1.5.3_proguard.jar

借助上面阿里的jar

UTDevice.getUtdid(AppApplication.in())

获取一个稳定的id

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值