题 是否有唯一的Android设备ID?


Android设备是否具有唯一的ID,如果是这样,使用Java访问它的简单方法是什么?


2312
2018-05-07 00:47


起源


如果你正在使用 ANDROID_ID 一定要读 这个答案 和 这个bug。 - Dheeraj V.S.
这是一个内容丰富的答案。 - Eng.Fouad
我觉得很完美: stackoverflow.com/a/16929647/1318946 - Pratik Butani
我发现这非常有用,因为它讨论了所有可用的唯一标识符,并在每个标识符中加权并得出最佳结论 stackoverflow.com/q/27233518/5252270 - sathishkumar_kingmaker


答案:


Settings.Secure#ANDROID_ID 返回Android ID作为 每个用户都是唯一的 64位十六进制字符串。

import android.provider.Settings.Secure;

private String android_id = Secure.getString(getContext().getContentResolver(),
                                                        Secure.ANDROID_ID); 

1699
2018-05-07 00:49



它有时被称为null,它被记录为“可以在出厂重置时更改”。使用风险自负,可以在root手机上轻松更改。 - Seva Alekseyev
groups.google.com/group/android-developers/browse_thread/thread/... - Erdal
我认为我们需要注意在第一个答案中使用哈希中的ANDROID_ID因为它可能在首次运行应用程序时未设置,可能稍后设置,或者甚至可能在理论上更改,因此唯一ID可能会更改
请注意,此解决方案存在巨大限制: android-developers.blogspot.com/2011/03/... - emmby
ANDROID_ID不再唯一标识设备(截至4.2): stackoverflow.com/a/13465373/150016 - Tom


UPDATE:截至最近的Android版本,很多问题都有 ANDROID_ID 已经解决了,我相信这种方法已经不再需要了。请看一下 安东尼的回答

完全披露:我的应用程序最初使用了以下方法,但不再使用此方法,我们现在使用的方法 Android开发者博客 那个 艾姆比的回答 链接(即生成和保存) UUID#randomUUID())。


这个问题有很多答案,其中大部分只会在某些时候起作用,不幸的是,这还不够好。

基于我对设备的测试(所有电话,其中至少有一部分未激活):

  1. 测试的所有设备都返回了一个值 TelephonyManager.getDeviceId()
  2. 所有GSM设备(均使用SIM测试)返回值 TelephonyManager.getSimSerialNumber()
  3. 所有CDMA设备都返回null getSimSerialNumber() (如预期的那样)
  4. 添加了Google帐户的所有设备均返回了值 ANDROID_ID
  5. 所有CDMA设备都返回相同的值(或相同值的推导) ANDROID_ID 和 TelephonyManager.getDeviceId()  - 只要 设置过程中添加了Google帐户。
  6. 我还没有机会测试没有SIM卡的GSM设备,没有添加Google帐户的GSM设备,或飞机模式下的任何设备。

因此,如果您想要设备本身的独特之处, TM.getDeviceId()  应该 足够了。显然有些用户比其他用户更偏执,因此对这些标识符中的一个或多个进行散列可能很有用,这样该字符串对于设备来说实际上仍然是唯一的,但是没有明确标识用户的实际设备。例如,使用 String.hashCode(),结合UUID:

final TelephonyManager tm = (TelephonyManager) getBaseContext().getSystemService(Context.TELEPHONY_SERVICE);

final String tmDevice, tmSerial, androidId;
tmDevice = "" + tm.getDeviceId();
tmSerial = "" + tm.getSimSerialNumber();
androidId = "" + android.provider.Settings.Secure.getString(getContentResolver(), android.provider.Settings.Secure.ANDROID_ID);

UUID deviceUuid = new UUID(androidId.hashCode(), ((long)tmDevice.hashCode() << 32) | tmSerial.hashCode());
String deviceId = deviceUuid.toString();

可能会导致类似于: 00000000-54b3-e7c7-0000-000046bffd97

它对我来说效果很好。

正如理查德在下面提到的那样,不要忘记你需要获得阅读权限 TelephonyManager 属性,所以将此添加到您的清单:

<uses-permission android:name="android.permission.READ_PHONE_STATE" />

导入库

import android.content.Context;
import android.telephony.TelephonyManager;
import android.view.View;

1056
2018-05-17 22:12



平板设备不会出现基于电话的身份证,是吗? - Seva Alekseyev
因此,为什么我说大多数都不会一直工作:)我还没有看到任何对所有设备,所有设备类型和所有硬件配置都可靠的问题的答案。这就是为什么这个问题从这里开始的原因。很明显,没有最终解决方案。单个设备制造商可能具有设备序列号,但这些设备序列号不会公开供我们使用,并且不是必需的。因此,我们留给了我们可用的东西。 - Joe
代码示例效果很好。记得加 <uses-permission android:name="android.permission.READ_PHONE_STATE" /> 到清单文件。如果存储在数据库中,则返回的字符串长度为36个字符。 - Richard
请注意,此解决方案存在巨大限制: android-developers.blogspot.com/2011/03/... - emmby
@softarn:我相信你所指的是emmby已经链接到的Android开发者博客,它解释了你的内容 试 要说,也许你应该简单地赞成他的评论。无论哪种方式,正如emmby在他的回答中提到的那样,即使博客信息也存在问题。这个问题要求一个独特的 设备 标识符(不是安装标识符),所以我不同意你的陈述。博客假设你想要什么 不一定 跟踪设备,而问题只是要求。我同意博客。 - Joe


最后更新时间:2015年6月2日


在阅读关于创建唯一ID,Google开发人员博客和Android文档的每篇Stack Overflow帖子后,我觉得好像'Pseudo ID'是最好的选择。

主要问题:硬件与软件

硬件

  • 用户可以更改他们的硬件,Android平板电脑或手机,因此基于硬件的唯一ID不是好主意 跟踪用户
  • 对于 跟踪硬件, 这是一个好主意

软件

  • 如果root用户可以擦除/更改他们的ROM
  • 您可以跨平台(iOS,Android,Windows和Web)跟踪用户
  • 最好的想要 追踪个人用户 和他们的 同意 只是让他们登录(使用OAuth使其无缝)

Android的总体细分

- 保证API> = 9/10的唯一性(包括root设备)(99.5%的Android设备)

- 没有额外的权限

Psuedo代码:

if API >= 9/10: (99.5% of devices)

return unique ID containing serial id (rooted devices may be different)

else

return unique ID of build information (may overlap data - API < 9)

感谢@stansult的发帖 我们所有的选择 (在此Stack Overflow问题中)。

选项列表 - 原因/为何不使用它们:

  • 用户电子邮件 - 软件

    • 用户可以更改电子邮件 - 极不可能
    • API 5+ <uses-permission android:name="android.permission.GET_ACCOUNTS" /> 要么
    • API 14+ <uses-permission android:name="android.permission.READ_PROFILE" />  <uses-permission android:name="android.permission.READ_CONTACTS" /> (如何获取Android设备的主要电子邮件地址
  • 用户电话号码 - 软件

    • 用户可以更改电话号码 - 极不可能
    • <uses-permission android:name="android.permission.READ_PHONE_STATE" />
  • IMEI - 硬件 (只有手机,需要 android.permission.READ_PHONE_STATE

    • 大多数用户讨厌在许可中说“电话”的事实。一些用户给出了不好的评级,因为他们认为你只是窃取他们的个人信息,当你真正想做的就是跟踪设备安装。很明显,您正在收集数据。
    • <uses-permission android:name="android.permission.READ_PHONE_STATE" />
  • Android ID - 硬件 (可以为null,可以在恢复出厂设置时更改,可以在有根设备上更改)

    • 由于它可以为'null',我们可以检查'null'并更改其值,但这意味着它将不再是唯一的。
    • 如果您的用户具有出厂重置设备,则该设备上的值可能已更改或更改,因此如果您正在跟踪用户安装,则可能存在重复条目。
  • WLAN MAC地址 - 硬件 (需要 android.permission.ACCESS_WIFI_STATE

    • 这可能是第二个最佳选择,但您仍在收集和存储直接来自用户的唯一标识符。很明显,您正在收集数据。
    • <uses-permission android:name="android.permission.ACCESS_WIFI_STATE "/>
  • 蓝牙MAC地址 - 硬件 (带蓝牙的设备,需要 android.permission.BLUETOOTH

    • 市场上的大多数应用程序都不使用蓝牙,因此如果您的应用程序不使用蓝牙而您包含此功能,则用户可能会产生怀疑。
    • <uses-permission android:name="android.permission.BLUETOOTH "/>
  • 伪唯一ID - 软件 (适用于所有Android设备)

    • 很可能,可能包含碰撞 - 请参阅下面发布的方法!
    • 这使您可以从用户那里获得“几乎唯一”的ID,而无需使用任何私有ID。您可以从设备信息创建自己的匿名ID。

我知道没有任何“完美”的方法可以在不使用权限的情况下获取唯一ID;但是,有时我们只需要跟踪设备安装。在创建唯一ID时,我们可以根据Android API提供的信息创建“伪唯一ID”,而无需使用额外的权限。通过这种方式,我们可以向用户展示尊重并尝试提供良好的用户体验。

使用伪唯一ID,您实际上只会遇到基于类似设备这一事实可能存在重复的事实。您可以调整组合方法,使其更加独特;但是,一些开发人员需要跟踪设备安装,这将基于类似设备执行技巧或性能。

API> = 9:

如果他们的Android设备是API 9或更高版本,由于“Build.SERIAL”字段,这保证是唯一的。

记得从技术上讲,你只有大约0.5%的用户错过了 谁有API <9。所以你可以专注于其余的:这是99.5%的用户!

API <9:

如果用户的Android设备低于API 9;希望他们没有完成工厂重置,他们的'Secure.ANDROID_ID'将被保留或不是'null'。 (看到 http://developer.android.com/about/dashboards/index.html

如果一切都失败了:

如果所有其他方法都失败了,如果用户确实低于API 9(低于Gingerbread),重置了他们的设备或'Secure.ANDROID_ID'返回'null',那么返回的ID将完全基于他们的Android设备信息。这是碰撞可能发生的地方。

变化:

  • 由于工厂重置而删除'Android.SECURE_ID'可能会导致值发生变化
  • 编辑代码以更改API
  • 改变了伪

请看下面的方法:

/**
 * Return pseudo unique ID
 * @return ID
 */
public static String getUniquePsuedoID() {
    // 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);

    // Thanks to @Roman SL!
    // https://stackoverflow.com/a/4789483/950427
    // Only devices with API >= 9 have android.os.Build.SERIAL
    // http://developer.android.com/reference/android/os/Build.html#SERIAL
    // If a user upgrades software or roots their device, there will be a duplicate entry
    String serial = null;
    try {
        serial = android.os.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!
    // https://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();
}

新功能(适用于包含广告和Google Play服务的应用):

来自Google Play Developer的控制台:

从2014年8月1日开始,Google Play开发者计划政策   要求所有新的应用上传和更新都使用广告ID   为任何广告目的代替任何其他持久性标识符。   学到更多

履行

允许:

<uses-permission android:name="android.permission.INTERNET" />

码:

import com.google.android.gms.ads.identifier.AdvertisingIdClient;
import com.google.android.gms.ads.identifier.AdvertisingIdClient.Info;
import com.google.android.gms.common.GooglePlayServicesAvailabilityException;
import com.google.android.gms.common.GooglePlayServicesNotAvailableException;
import java.io.IOException;
...

// Do not call this function from the main thread. Otherwise, 
// an IllegalStateException will be thrown.
public void getIdThread() {

  Info adInfo = null;
  try {
    adInfo = AdvertisingIdClient.getAdvertisingIdInfo(mContext);

  } catch (IOException exception) {
    // Unrecoverable error connecting to Google Play services (e.g.,
    // the old version of the service doesn't support getting AdvertisingId).

  } catch (GooglePlayServicesAvailabilityException exception) {
    // Encountered a recoverable error connecting to Google Play services. 

  } catch (GooglePlayServicesNotAvailableException exception) {
    // Google Play services is not available entirely.
  }
  final String id = adInfo.getId();
  final boolean isLAT = adInfo.isLimitAdTrackingEnabled();
}

来源/文档:

http://developer.android.com/google/play-services/id.html http://developer.android.com/reference/com/google/android/gms/ads/identifier/AdvertisingIdClient.html

重要:

广告ID旨在完全取代现有的广告ID   出于广告目的使用其他标识符(例如使用ANDROID_ID   在“设置。安全”中,当Google Play服务可用时。案例   Google Play服务不可用的地方由a表示   引发的GooglePlayServicesNotAvailableException   getAdvertisingIdInfo()。

警告,用户可以重置:

http://en.kioskea.net/faq/34732-android-reset-your-advertising-id

我试图引用我从中获取信息的每个链接。如果您遗失并需要加入,请发表评论!

Google Player服务实例ID

https://developers.google.com/instance-id/


365
2017-07-12 23:58



但不会 Build OS更新时的类更改?特别是如果API得到更新?如果是这样,你如何保证这是独一无二的? (谈到你写的方法) - LuckyMe
我在我的应用程序中使用您的方法发送评论。我有坏消息。不幸的是,PsuedoID并不是完全独一无二的。我的服务器为5个ID记录了超过100个,对于近30个ID记录了超过30个。最重复的ID是'ffffffff-fc8f-6093-ffff-ffffd8'(159记录)和'ffffffff-fe99-b334-ffff-ffffef'(154次)。也基于时间和评论,显然有不同的人。到目前为止的总记录是10,000。请让我知道为什么会这样。坦克。 - hojjat reyhane
我在1.5多年前写过这篇文章。我不确定为什么它不是你独一无二的。您可以尝试广告ID。如果没有,您可以提出自己的解决方案。 - Jared Burrows
sorta ..如果你仔细阅读并提出自己的想法,我真的很感激 - Durai Amuthan.H
@ user1587329谢谢。我试图让每个人保持最新状态。在涉及硬件与软件和跨平台时,这个问题很棘手。 - Jared Burrows


正如Dave Webb所提到的那样 Android开发者博客有一篇文章 这涵盖了这个。他们首选的解决方案是跟踪应用安装而不是设备,这对大多数用例都有效。博客文章将向您展示完成这项工作所需的代码,我建议您查看它。

但是,如果您需要设备标识符而不是应用程序安装标识符,则博客文章会继续讨论解决方案。我与Google的某位人士进行了交谈,以便在您需要的情况下对一些项目进行一些额外的澄清。以下是我在上述博客文章中未提及的设备标识符的发现:

  • ANDROID_ID是首选的设备标识符。 ANDROID_ID在Android <= 2.1或> = 2.3的版本上非常可靠。只有2.2有帖子中提到的问题。
  • 几个制造商的几个设备受2.2中的ANDROID_ID错误的影响。
  • 据我所知,所有受影响的设备都有 相同的ANDROID_ID,是的 9774d56d682e549c。这也是模拟器报告的相同设备ID,顺便说一下。
  • 谷歌相信原始设备制造商已经为他们的许多或大多数设备修补了这个问题,但我能够验证到2011年4月初,至少,找到那些破坏了ANDROID_ID的设备仍然很容易。

根据Google的建议,我实现了一个类,它将为每个设备生成一个唯一的UUID,在适当的情况下使用ANDROID_ID作为种子,必要时返回TelephonyManager.getDeviceId(),如果失败,则使用随机生成的唯一UUID这是在应用程序重新启动时保留的(但不是应用程序重新安装)。

请注意,对于必须回退设备ID的设备,唯一ID  坚持工厂重置。这是需要注意的事情。如果您需要确保恢复出厂设置将重置您的唯一ID,您可能需要考虑直接回退到随机UUID而不是设备ID。

同样,此代码用于设备ID,而不是应用程序安装ID。在大多数情况下,应用程序安装ID可能就是您要查找的内容。但是,如果您确实需要设备ID,那么以下代码可能适合您。

import android.content.Context;
import android.content.SharedPreferences;
import android.provider.Settings.Secure;
import android.telephony.TelephonyManager;

import java.io.UnsupportedEncodingException;
import java.util.UUID;

public class DeviceUuidFactory {

    protected static final String PREFS_FILE = "device_id.xml";
    protected static final String PREFS_DEVICE_ID = "device_id";
    protected volatile static UUID uuid;

    public DeviceUuidFactory(Context context) {
        if (uuid == null) {
            synchronized (DeviceUuidFactory.class) {
                if (uuid == null) {
                    final SharedPreferences prefs = context
                            .getSharedPreferences(PREFS_FILE, 0);
                    final String id = prefs.getString(PREFS_DEVICE_ID, null);
                    if (id != null) {
                        // Use the ids previously computed and stored in the
                        // prefs file
                        uuid = UUID.fromString(id);
                    } else {
                        final String androidId = Secure.getString(
                            context.getContentResolver(), Secure.ANDROID_ID);
                        // Use the Android ID unless it's broken, in which case
                        // fallback on deviceId,
                        // unless it's not available, then fallback on a random
                        // number which we store to a prefs file
                        try {
                            if (!"9774d56d682e549c".equals(androidId)) {
                                uuid = UUID.nameUUIDFromBytes(androidId
                                        .getBytes("utf8"));
                            } else {
                                final String deviceId = (
                                    (TelephonyManager) context
                                    .getSystemService(Context.TELEPHONY_SERVICE))
                                    .getDeviceId();
                                uuid = deviceId != null ? UUID
                                    .nameUUIDFromBytes(deviceId
                                            .getBytes("utf8")) : UUID
                                    .randomUUID();
                            }
                        } catch (UnsupportedEncodingException e) {
                            throw new RuntimeException(e);
                        }
                        // Write the value out to the prefs file
                        prefs.edit()
                                .putString(PREFS_DEVICE_ID, uuid.toString())
                                .commit();
                    }
                }
            }
        }
    }

    /**
     * Returns a unique UUID for the current android device. As with all UUIDs,
     * this unique ID is "very highly likely" to be unique across all Android
     * devices. Much more so than ANDROID_ID is.
     * 
     * The UUID is generated by using ANDROID_ID as the base key if appropriate,
     * falling back on TelephonyManager.getDeviceID() if ANDROID_ID is known to
     * be incorrect, and finally falling back on a random UUID that's persisted
     * to SharedPreferences if getDeviceID() does not return a usable value.
     * 
     * In some rare circumstances, this ID may change. In particular, if the
     * device is factory reset a new device ID may be generated. In addition, if
     * a user upgrades their phone from certain buggy implementations of Android
     * 2.2 to a newer, non-buggy version of Android, the device ID may change.
     * Or, if a user uninstalls your app on a device that has neither a proper
     * Android ID nor a Device ID, this ID may change on reinstallation.
     * 
     * Note that if the code falls back on using TelephonyManager.getDeviceId(),
     * the resulting ID will NOT change after a factory reset. Something to be
     * aware of.
     * 
     * Works around a bug in Android 2.2 for many devices when using ANDROID_ID
     * directly.
     * 
     * @see http://code.google.com/p/android/issues/detail?id=10603
     * 
     * @return a UUID that may be used to uniquely identify your device for most
     *         purposes.
     */
    public UUID getDeviceUuid() {
        return uuid;
    }
}

314
2018-04-11 19:06



你不应该散列各种ID,以便它们的大小相同吗?此外,您应该对设备ID进行哈希处理,以免意外泄露私人信息。 - Steve Pomeroy
好的,史蒂夫。我更新了代码以始终返回UUID。这确保了a)生成的ID总是相同的大小,并且b)在返回之前对android和设备ID进行哈希处理以避免意外地暴露个人信息。我还更新了描述,注意设备ID将在出厂重置时保持不变,并且这可能不适合某些用户。 - emmby
我相信你是不正确的;首选解决方案是跟踪安装,而不是设备标识符。您的代码比博客文章中的代码更长,更复杂,对我而言,它增加任何价值并不明显。 - Tim Bray
好点,我更新了评论,强烈建议用户使用应用程序安装ID而不是设备ID。但是,我认为这种解决方案对于需要设备而非安装ID的人来说仍然很有价值。 - emmby
ANDROID_ID可以在出厂重置时更改,因此它也无法识别设备 - Samuel


以下是Reto Meier使用的代码 Google I / O. 今年的演示文稿为用户获取一个唯一的ID:

private static String uniqueID = null;
private static final String PREF_UNIQUE_ID = "PREF_UNIQUE_ID";

public synchronized static String id(Context context) {
    if (uniqueID == null) {
        SharedPreferences sharedPrefs = context.getSharedPreferences(
                PREF_UNIQUE_ID, Context.MODE_PRIVATE);
        uniqueID = sharedPrefs.getString(PREF_UNIQUE_ID, null);
        if (uniqueID == null) {
            uniqueID = UUID.randomUUID().toString();
            Editor editor = sharedPrefs.edit();
            editor.putString(PREF_UNIQUE_ID, uniqueID);
            editor.commit();
        }
    }
    return uniqueID;
}

如果您将此与备份策略相结合,以将首选项发送到云(也在Reto中描述) 谈论,你应该有一个与用户联系的id,并在擦除或甚至更换设备后留下来。我打算在未来的分析中使用它(换句话说,我还没有完成那一点:)。


165
2017-10-28 13:19



我正在使用@Lenn Dolling的方法,附加了当前时间的唯一ID。但这似乎更简单可靠。感谢Reto Meier和Antony Nolan - Gökhan Barış Aker
这很好但是根设备呢?他们可以访问它并轻松地将uid更改为另一个。 - tasomaniac
如果您在卸载并重新安装后不需要唯一ID(例如,您有三次获胜机会的促销活动/游戏,期间),那么这是一个很好的选择。 - Kyle Clegg
Meier演示依赖于使用Android备份管理器,而后者依赖于用户选择打开该功能。对于应用程序用户首选项(Meier的使用)来说这很好,因为如果用户没有选择该选项,她就不会获得那些备份。但是,最初的问题是关于生成一个唯一的ID 设备并且,每个应用程序生成此ID,甚至不是每个安装,更不用说每个设备,并且由于它依赖于用户选择备份选项,因此超出用户偏好(例如,用于限时试用)的用途是有限的。 - Carl
这不适用于卸载或清除数据。 - John Shelley


您也可以考虑Wi-Fi适配器的MAC地址。如此检索:

WifiManager wm = (WifiManager)Ctxt.getSystemService(Context.WIFI_SERVICE);
return wm.getConnectionInfo().getMacAddress();

需要许可 android.permission.ACCESS_WIFI_STATE 在清单中。

报告即使未连接Wi-Fi也可用。如果上面的答案中的Joe在他的许多设备上尝试了这个,那就太好了。

在某些设备上,当Wi-Fi关闭时,它不可用。

注意: 从Android 6.x开始,它返回一致的虚假mac地址: 02:00:00:00:00:00


98
2018-06-23 14:27



这需要 android.permission.ACCESS_WIFI_STATE - ohhorob
他们存在吗?我宁愿设想一个无电话设备(AKA平板电脑)...... - Seva Alekseyev
我知道这个问题很老 - 但这是个好主意。我在我的应用程序中使用了BT mac ID,但仅仅因为它需要BT才能运行。给我看一个值得开发的Android设备没有WiFi。 - Jack
我认为你会发现它在WiFi关闭时无法使用,几乎所有Android设备上都有。关闭WiFi会在内核级别删除设备。 - chrisdowney
@Sanandrea - 让我们面对它,在一个有根的设备上,一切都可以被欺骗。 - ocodo


有相当有用的信息 这里

它涵盖了五种不同的ID类型:

  1. IMEI (仅适用于使用电话的Android设备;需要 android.permission.READ_PHONE_STATE
  2. 伪唯一ID (适用于所有Android设备)
  3. Android ID (可以为null,可以在出厂重置时更改,可以在root电话上更改)
  4. WLAN MAC地址 字符串(需要 android.permission.ACCESS_WIFI_STATE
  5. BT MAC地址 字符串(带蓝牙的设备,需要 android.permission.BLUETOOTH

78
2018-02-08 02:16



遗漏的重点(此处和文章中):除非打开它们,否则无法获得WLAN或BT MAC!否则我认为WLAN MAC将是完美的标识符。你不能保证用户会打开他们的Wi-Fi,我真的不认为自己打开它是“合适的”。 - Tom
@Tom你错了。即使关闭WLAN或BT MAC,您仍然可以读取它们。但是,无法保证设备具有可用的WLAN或BT模块。 - Marqs
最值得注意的是,本地WiFi和蓝牙MAC地址不再可用.aWifiInfo对象的getMacAddress()方法和BluetoothAdapter.getDefaultAdapter()。getAddress()方法将从现在开始返回02:00:00:00:00:00 - sarika kate
@sarikakate仅在6.0棉花糖及以上的情况下才真实......它仍然在6.0棉花糖的下方工作。 - Smeet
@Smeet是的你是对的。我忘了提到它的工作低于6.0 - sarika kate