Câu hỏi Có ID thiết bị Android duy nhất không?


Các thiết bị Android có một ID duy nhất không và nếu có, cách đơn giản để truy cập nó bằng Java là gì?


2312
2018-05-07 00:47


gốc


Nếu bạn đang sử dụng ANDROID_ID hãy nhớ đọc câu trả lời này và lỗi này. - Dheeraj V.S.
Đây là một câu trả lời thông tin. - Eng.Fouad
Tôi thấy hoàn hảo: stackoverflow.com/a/16929647/1318946 - Pratik Butani
Tôi thấy điều này rất hữu ích vì nó thảo luận về tất cả các số nhận dạng duy nhất có sẵn và cân nhắc trong mỗi và kết luận tốt nhất stackoverflow.com/q/27233518/5252270 - sathishkumar_kingmaker


Các câu trả lời:


Settings.Secure#ANDROID_ID trả về ID Android dưới dạng duy nhất cho mỗi người dùng Chuỗi thập lục phân 64 bit.

import android.provider.Settings.Secure;

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

1699
2018-05-07 00:49



Đôi khi nó được biết là vô giá trị, nó được ghi nhận là "có thể thay đổi khi khôi phục cài đặt gốc". Sử dụng có nguy cơ của riêng bạn, và nó có thể dễ dàng thay đổi trên một điện thoại bắt nguồn từ. - Seva Alekseyev
groups.google.com/group/android-developers/browse_thread/thread/… - Erdal
Tôi nghĩ chúng ta cần phải cẩn thận khi sử dụng ANDROID_ID trong hàm băm trong câu trả lời đầu tiên vì nó có thể không được đặt khi ứng dụng lần đầu tiên chạy, có thể được đặt sau hoặc thậm chí có thể thay đổi về lý thuyết, do đó ID duy nhất có thể thay đổi
Hãy nhận biết có những hạn chế rất lớn với giải pháp này: android-developers.blogspot.com/2011/03/… - emmby
ANDROID_ID không còn nhận dạng duy nhất một thiết bị (kể từ 4.2): stackoverflow.com/a/13465373/150016 - Tom


CẬP NHẬT: Kể từ các phiên bản Android gần đây, nhiều vấn đề với ANDROID_ID đã được giải quyết và tôi tin rằng phương pháp này không còn cần thiết nữa. Xin hãy nhìn vào Câu trả lời của Anthony.

Tiết lộ đầy đủ: ứng dụng của tôi đã sử dụng phương pháp tiếp cận bên dưới ban đầu nhưng không còn sử dụng cách tiếp cận này nữa và giờ đây chúng tôi sử dụng cách tiếp cận được nêu trong Blog nhà phát triển Android nhập cảnh câu trả lời của emmby liên kết đến (cụ thể là tạo và lưu UUID#randomUUID()).


Có rất nhiều câu trả lời cho câu hỏi này, hầu hết trong số đó sẽ chỉ làm việc "một số" thời gian, và tiếc là điều đó không đủ tốt.

Dựa trên các thử nghiệm của tôi về các thiết bị (tất cả các điện thoại, ít nhất một trong số đó không được kích hoạt):

  1. Tất cả các thiết bị được thử nghiệm đã trả về một giá trị cho TelephonyManager.getDeviceId()
  2. Tất cả các thiết bị GSM (tất cả được thử nghiệm với một SIM) trả lại một giá trị cho TelephonyManager.getSimSerialNumber()
  3. Tất cả các thiết bị CDMA trả về null cho getSimSerialNumber() (như mong đợi)
  4. Tất cả các thiết bị có tài khoản Google được thêm trả về một giá trị cho ANDROID_ID
  5. Tất cả các thiết bị CDMA trả lại cùng một giá trị (hoặc dẫn xuất của cùng một giá trị) cho cả hai ANDROID_ID và TelephonyManager.getDeviceId() - - miễn là tài khoản Google đã được thêm trong khi thiết lập.
  6. Tôi chưa có cơ hội thử nghiệm các thiết bị GSM không có SIM, thiết bị GSM không có tài khoản Google được thêm vào hoặc bất kỳ thiết bị nào trong chế độ trên máy bay.

Vì vậy, nếu bạn muốn một cái gì đó độc đáo cho chính thiết bị đó, TM.getDeviceId()  Nên đầy đủ. Rõ ràng một số người dùng hoang tưởng hơn những người khác, vì vậy có thể hữu ích khi băm 1 hoặc nhiều số nhận dạng này, để chuỗi vẫn hầu như duy nhất cho thiết bị nhưng không xác định rõ ràng thiết bị thực của người dùng. Ví dụ: sử dụng String.hashCode(), kết hợp với 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();

có thể dẫn đến một cái gì đó như: 00000000-54b3-e7c7-0000-000046bffd97

Nó hoạt động tốt cho tôi.

Như Richard đề cập bên dưới, đừng quên rằng bạn cần sự cho phép để đọc TelephonyManager các thuộc tính, vì vậy hãy thêm thuộc tính này vào tệp kê khai của bạn:

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

nhập libs

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

1056
2018-05-17 22:12



ID dựa trên điện thoại sẽ không có trên các thiết bị máy tính bảng, neh? - Seva Alekseyev
Do đó tại sao tôi nói hầu hết sẽ không làm việc tất cả các thời gian :) Tôi chưa thấy bất kỳ câu trả lời cho câu hỏi này là đáng tin cậy cho tất cả các thiết bị, tất cả các loại thiết bị, và tất cả các cấu hình phần cứng. Đó là lý do tại sao câu hỏi này là ở đây để bắt đầu. Nó khá rõ ràng rằng không có giải pháp cuối cùng tất cả cho tất cả. Các nhà sản xuất thiết bị cá nhân có thể có số sê-ri của thiết bị, nhưng những thiết bị đó không được tiếp xúc để chúng tôi sử dụng và không phải là yêu cầu. Vì vậy, chúng tôi còn lại với những gì có sẵn cho chúng tôi. - Joe
Mẫu mã hoạt động tốt. Nhớ thêm <uses-permission android:name="android.permission.READ_PHONE_STATE" /> vào tệp kê khai. Nếu lưu trữ trong cơ sở dữ liệu, chuỗi trả về dài 36 ký tự. - Richard
Hãy nhận biết có những hạn chế rất lớn với giải pháp này: android-developers.blogspot.com/2011/03/… - emmby
@softarn: Tôi tin rằng những gì bạn đang đề cập đến là Blog nhà phát triển Android mà emmby đã liên kết đến, điều này giải thích bạn là ai cố gắng để nói, vì vậy có lẽ bạn nên chỉ đơn giản là upvoted bình luận của mình để thay thế. Dù bằng cách nào, như emmby đề cập đến trong câu trả lời của mình, vẫn có vấn đề ngay cả với thông tin blog. Câu hỏi đặt ra một câu hỏi duy nhất THIẾT BỊ số nhận dạng (không phải mã định danh cài đặt), vì vậy tôi không đồng ý với tuyên bố của bạn. Blog đang đưa ra giả định rằng những gì bạn muốn không cần thiết để theo dõi thiết bị, trong khi câu hỏi yêu cầu điều đó. Tôi đồng ý với blog khác. - Joe


Cập nhật lần cuối: 6/2/15


Sau khi đọc tất cả bài đăng Tràn ngăn xếp về cách tạo ID duy nhất, blog nhà phát triển Google và tài liệu Android, tôi cảm thấy như thể 'ID giả' là tùy chọn tốt nhất có thể.

Vấn đề chính: Phần cứng so với phần mềm

Phần cứng

  • Người dùng có thể thay đổi phần cứng, máy tính bảng hoặc điện thoại Android của mình, để các ID duy nhất dựa trên phần cứng không phải là ý tưởng hay cho THEO D USI NGƯỜI DÙNG
  • Dành cho THEO D HI PHẦN CỨNG, đây là một ý tưởng hay

Phần mềm

  • Người dùng có thể xóa / thay đổi ROM của họ nếu chúng được root
  • Bạn có thể theo dõi người dùng trên các nền tảng (iOS, Android, Windows và Web)
  • Điều tốt nhất muốn TRACK AN NGƯỜI DÙNG RIÊNG với họ bằng lòng chỉ đơn giản là để họ đăng nhập (tạo điều này liền mạch bằng OAuth)

Phân tích tổng thể với Android

- Tính bảo đảm độc đáo (bao gồm các thiết bị gốc) cho API> = 9/10 (99,5% thiết bị Android)

- Không có quyền bổ sung

Mã 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)

Cảm ơn @stansult vì đã đăng tất cả các tùy chọn của chúng tôi (trong câu hỏi tràn ngăn xếp này).

Danh sách các tùy chọn - lý do tại sao / tại sao không sử dụng chúng:

  • Email người dùng - Phần mềm

    • Người dùng có thể thay đổi email - KHÔNG chắc chắn lắm
    • API 5+ <uses-permission android:name="android.permission.GET_ACCOUNTS" /> hoặc là
    • API 14+ <uses-permission android:name="android.permission.READ_PROFILE" />  <uses-permission android:name="android.permission.READ_CONTACTS" /> (Cách nhận địa chỉ e-mail chính của thiết bị Android)
  • Số điện thoại của người dùng - Phần mềm

    • Người dùng có thể thay đổi số điện thoại - Rất ít khả năng
    • <uses-permission android:name="android.permission.READ_PHONE_STATE" />
  • IMEI - Phần cứng (chỉ điện thoại, nhu cầu android.permission.READ_PHONE_STATE)

    • Hầu hết người dùng ghét thực tế là nó nói "Cuộc gọi điện thoại" trong sự cho phép. Một số người dùng đưa ra xếp hạng kém, bởi vì họ tin rằng bạn chỉ đơn giản là ăn cắp thông tin cá nhân của họ, khi tất cả những gì bạn thực sự muốn làm là theo dõi lượt cài đặt thiết bị. Rõ ràng là bạn đang thu thập dữ liệu.
    • <uses-permission android:name="android.permission.READ_PHONE_STATE" />
  • ID Android - Phần cứng (có thể là null, có thể thay đổi khi khôi phục cài đặt gốc, có thể được thay đổi trên thiết bị gốc)

    • Vì nó có thể là 'null', chúng ta có thể kiểm tra 'null' và thay đổi giá trị của nó, nhưng điều này có nghĩa là nó sẽ không còn là duy nhất nữa.
    • Nếu bạn có người dùng có thiết bị khôi phục cài đặt gốc, giá trị có thể đã thay đổi hoặc thay đổi trên thiết bị gốc để có thể có mục trùng lặp nếu bạn đang theo dõi lượt cài đặt của người dùng.
  • Địa chỉ MAC WLAN - Phần cứng (nhu cầu android.permission.ACCESS_WIFI_STATE)

    • Đây có thể là tùy chọn tốt thứ hai, nhưng bạn vẫn đang thu thập và lưu trữ một số nhận dạng duy nhất đến trực tiếp từ người dùng. Điều này rõ ràng là bạn đang thu thập dữ liệu.
    • <uses-permission android:name="android.permission.ACCESS_WIFI_STATE "/>
  • Địa chỉ MAC Bluetooth - Phần cứng (thiết bị có Bluetooth, nhu cầu android.permission.BLUETOOTH)

    • Hầu hết các ứng dụng trên thị trường đều không sử dụng Bluetooth, và vì vậy nếu ứng dụng của bạn không sử dụng Bluetooth và bạn đang bao gồm điều này, người dùng có thể trở nên đáng ngờ.
    • <uses-permission android:name="android.permission.BLUETOOTH "/>
  • ID giả duy nhất - Phần mềm (cho tất cả các thiết bị Android)

    • Rất có thể, có thể chứa va chạm - Xem phương pháp của tôi được đăng bên dưới!
    • Điều này cho phép bạn có ID 'gần như duy nhất' từ người dùng mà không lấy bất kỳ thứ gì riêng tư. Bạn có thể tạo ID riêng của bạn từ thông tin thiết bị.

Tôi biết không có cách nào 'hoàn hảo' để nhận được một ID duy nhất mà không sử dụng quyền; tuy nhiên, đôi khi chúng tôi chỉ thực sự cần theo dõi cài đặt thiết bị. Khi tạo ID duy nhất, chúng tôi có thể tạo 'id duy nhất giả' chỉ dựa trên thông tin mà API Android cung cấp cho chúng tôi mà không cần sử dụng quyền bổ sung. Bằng cách này, chúng tôi có thể thể hiện sự tôn trọng của người dùng và cố gắng cung cấp trải nghiệm người dùng tốt.

Với một id giả duy nhất, bạn thực sự chỉ chạy vào thực tế là có thể có các bản sao dựa trên thực tế là có các thiết bị tương tự. Bạn có thể tinh chỉnh phương pháp kết hợp để làm cho nó độc đáo hơn; tuy nhiên, một số nhà phát triển cần theo dõi lượt cài đặt thiết bị và điều này sẽ thực hiện thủ thuật hoặc hiệu suất dựa trên các thiết bị tương tự.

API> = 9:

Nếu thiết bị Android của họ là API 9 trở lên, điều này được đảm bảo là duy nhất vì trường 'Build.SERIAL'.

NHỚ LẠI, về mặt kỹ thuật, bạn chỉ bỏ lỡ khoảng 0,5% người dùng ai có API <9. Vì vậy, bạn có thể tập trung vào phần còn lại: Đây là 99,5% người dùng!

API <9:

Nếu thiết bị Android của người dùng thấp hơn API 9; hy vọng, họ đã không thực hiện khôi phục cài đặt gốc và 'Secure.ANDROID_ID' của họ sẽ được giữ nguyên hoặc không 'rỗng'. (xem http://developer.android.com/about/dashboards/index.html)

Nếu mọi thứ khác không thành công:

Nếu mọi thứ khác thất bại, nếu người dùng có thấp hơn API 9 (thấp hơn Gingerbread), đã đặt lại thiết bị của họ hoặc 'Secure.ANDROID_ID' trả về 'null', thì chỉ đơn giản là ID được trả lại sẽ chỉ dựa trên thông tin thiết bị Android của họ. Đây là nơi mà các va chạm có thể xảy ra.

Thay đổi:

  • Đã xóa 'Android.SECURE_ID' do đặt lại nhà máy có thể khiến giá trị thay đổi
  • Đã chỉnh sửa mã để thay đổi trên API
  • Đã thay đổi Pseudo

Vui lòng xem phương thức bên dưới:

/**
 * 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();
}

Mới (đối với ứng dụng có quảng cáo VÀ Dịch vụ của Google Play):

Từ bảng điều khiển dành cho nhà phát triển trên Google Play:

Bắt đầu từ ngày 1 tháng 8 năm 2014, Chính sách chương trình dành cho nhà phát triển trên Google Play   yêu cầu tất cả các bản tải lên và cập nhật ứng dụng mới để sử dụng ID quảng cáo trong   thay cho bất kỳ số nhận dạng liên tục nào khác cho bất kỳ mục đích quảng cáo nào.   Tìm hiểu thêm

Thực hiện:

Quyền:

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

Mã số:

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();
}

Nguồn / Tài liệu:

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

Quan trọng:

Dự định rằng ID quảng cáo thay thế hoàn toàn hiện tại   việc sử dụng các số nhận dạng khác cho mục đích quảng cáo (chẳng hạn như sử dụng ANDROID_ID   trong Cài đặt.Secure) khi Google Play Services khả dụng. Các trường hợp   nơi Dịch vụ của Google Play không khả dụng được biểu thị bằng   GooglePlayServicesNotAvailableException bị ném bởi   getAdvertisingIdInfo ().

Cảnh báo, người dùng có thể đặt lại:

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

Tôi đã cố gắng tham khảo mọi liên kết mà tôi lấy thông tin từ đó. Nếu bạn đang thiếu và cần phải được bao gồm, xin vui lòng bình luận!

Dịch vụ Google Player InstanceID

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


365
2017-07-12 23:58



Nhưng không phải Build thay đổi lớp học khi cập nhật hệ điều hành? Đặc biệt nếu API đã được cập nhật? Nếu vậy, làm thế nào để bạn đảm bảo điều này là duy nhất? (Nói về phương pháp bạn viết) - LuckyMe
tôi đã sử dụng phương pháp của bạn trong ứng dụng của tôi để gửi nhận xét. tôi có tin xấu. tiếc là PsuedoID không hoàn toàn độc đáo. máy chủ của tôi đã ghi hơn 100 cho 5 ID và hơn 30 cho gần 30 ID. ID lặp lại nhiều nhất là 'ffffffff-fc8f-6093-ffff-ffffd8' (bản ghi 159) và 'ffffffff-fe99-b334-ffff-ffffef' (154 lần). cũng dựa trên thời gian và ý kiến ​​rõ ràng là có những người khác nhau. tổng số hồ sơ cho đến bây giờ là 10.000. xin vui lòng cho tôi biết lý do tại sao điều này xảy ra. xe tăng. - hojjat reyhane
Tôi đã viết cách đây 1,5 năm. Tôi không chắc tại sao nó không phải là duy nhất cho bạn. Bạn có thể thử ID quảng cáo. Nếu không, bạn có thể đưa ra giải pháp của riêng bạn. - Jared Burrows
sorta..Tôi thực sự đánh giá cao nếu bạn đi qua câu hỏi và đưa ra suy nghĩ của bạn về điều này - Durai Amuthan.H
@ user1587329 Cảm ơn bạn. Tôi đang cố gắng cập nhật cho mọi người. Câu hỏi này là khó khăn khi nói đến phần cứng so với phần mềm và nền tảng chéo. - Jared Burrows


Như Dave Webb đề cập, Blog nhà phát triển Android có bài viết bao gồm điều này. Giải pháp ưa thích của họ là theo dõi lượt cài đặt ứng dụng thay vì thiết bị và điều đó sẽ hoạt động tốt cho hầu hết các trường hợp sử dụng. Bài đăng trên blog sẽ hiển thị cho bạn mã cần thiết để thực hiện công việc đó và tôi khuyên bạn nên kiểm tra.

Tuy nhiên, bài đăng trên blog tiếp tục thảo luận các giải pháp nếu bạn cần số nhận dạng thiết bị thay vì số nhận dạng cài đặt ứng dụng. Tôi đã nói chuyện với một người nào đó tại Google để được giải thích thêm về một số mặt hàng trong trường hợp bạn cần làm như vậy. Dưới đây là những gì tôi đã khám phá về số nhận dạng thiết bị KHÔNG được đề cập trong bài đăng trên blog nói trên:

  • ANDROID_ID là số nhận dạng thiết bị được ưu tiên. ANDROID_ID hoàn toàn đáng tin cậy trên các phiên bản Android <= 2.1 hoặc> = 2.3. Chỉ có 2,2 vấn đề được đề cập trong bài viết.
  • Một số thiết bị của một số nhà sản xuất bị ảnh hưởng bởi lỗi ANDROID_ID trong phiên bản 2.2.
  • Theo như tôi đã có thể xác định, tất cả các thiết bị bị ảnh hưởng đều có cùng ANDROID_ID, đó là 9774d56d682e549c. Đó cũng là id thiết bị tương tự được báo cáo bởi trình mô phỏng, btw.
  • Google tin rằng các OEM đã vá vấn đề cho nhiều hoặc hầu hết các thiết bị của họ, nhưng tôi đã có thể xác minh rằng vào đầu tháng 4 năm 2011, ít nhất, vẫn còn khá dễ dàng để tìm các thiết bị có ANDROID_ID bị hỏng.

Dựa trên các khuyến nghị của Google, tôi đã triển khai một lớp sẽ tạo UUID duy nhất cho từng thiết bị, sử dụng ANDROID_ID làm hạt giống khi thích hợp, quay lại trên TelephonyManager.getDeviceId () nếu cần và nếu không thành công, hãy sử dụng UUID duy nhất được tạo ngẫu nhiên được duy trì trong quá trình khởi động lại ứng dụng (nhưng không được cài đặt lại ứng dụng).

Lưu ý rằng đối với các thiết bị có dự phòng trên ID thiết bị, ID duy nhất SẼ tồn tại trên toàn bộ cài đặt gốc của nhà máy. Đây là điều cần biết. Nếu bạn cần đảm bảo khôi phục cài đặt gốc sẽ đặt lại ID duy nhất của mình, bạn có thể muốn xem xét giảm trực tiếp về UUID ngẫu nhiên thay vì ID thiết bị.

Một lần nữa, mã này dành cho ID thiết bị chứ không phải ID cài đặt ứng dụng. Đối với hầu hết các trường hợp, ID cài đặt ứng dụng có thể là thứ bạn đang tìm kiếm. Nhưng nếu bạn cần một ID thiết bị, sau đó mã sau đây có thể sẽ làm việc cho bạn.

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



Bạn không nên băm nhỏ các ID khác nhau sao cho chúng có cùng kích cỡ? Ngoài ra, bạn nên băm ID thiết bị để không vô tình để lộ thông tin cá nhân. - Steve Pomeroy
Điểm tốt, Steve. Tôi đã cập nhật mã để luôn trả lại UUID. Điều này đảm bảo rằng a) các ID được tạo luôn có cùng kích thước và b) ID android và thiết bị được băm trước khi được trả lại để tránh vô tình tiết lộ thông tin cá nhân. Tôi cũng đã cập nhật mô tả để lưu ý rằng ID thiết bị sẽ vẫn tồn tại trên các lần đặt lại nhà máy và điều này có thể không được mong muốn đối với một số người dùng. - emmby
Tôi tin rằng bạn không chính xác; giải pháp ưa thích là theo dõi cài đặt, không phải là số nhận dạng thiết bị. Mã của bạn dài hơn và phức tạp hơn nhiều so với mã trong bài đăng trên blog và điều đó không rõ ràng với tôi rằng nó thêm bất kỳ giá trị nào. - Tim Bray
Điểm tốt, tôi đã cập nhật bình luận để đề xuất người dùng sử dụng id cài đặt ứng dụng thay vì id thiết bị. Tuy nhiên, tôi nghĩ rằng giải pháp này vẫn có giá trị đối với những người cần một thiết bị thay vì ID cài đặt. - emmby
ANDROID_ID có thể thay đổi khi khôi phục cài đặt gốc nên không thể xác định thiết bị - Samuel


Đây là mã mà Reto Meier sử dụng trong Google I / O trình bày năm nay để có được một id duy nhất cho người dùng:

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;
}

Nếu bạn kết hợp với chiến lược sao lưu để gửi tùy chọn lên đám mây (cũng được mô tả trong Reto nói chuyện, bạn nên có một id liên kết với người dùng và di chuyển xung quanh sau khi thiết bị đã bị xóa hoặc thậm chí thay thế. Tôi dự định sử dụng điều này trong phân tích về phía trước (nói cách khác, tôi chưa làm điều đó chút nào :).


165
2017-10-28 13:19



Tôi đã sử dụng phương pháp @Lenn Dolling với thời gian hiện tại được nối thêm vào id duy nhất. Nhưng điều này có vẻ như cách đơn giản và đáng tin cậy hơn. Cảm ơn Reto Meier và Antony Nolan - Gökhan Barış Aker
Nó là tuyệt vời nhưng những gì về các thiết bị bắt nguồn từ? Họ có thể truy cập này và thay đổi uid đến một khác nhau một cách dễ dàng. - tasomaniac
Tùy chọn tuyệt vời nếu bạn không cần ID duy nhất tồn tại sau khi gỡ cài đặt và cài đặt lại (ví dụ: sự kiện / trò chơi khuyến mại nơi bạn có ba cơ hội để giành chiến thắng, thời gian). - Kyle Clegg
Trình bày Meier dựa trên việc sử dụng Trình quản lý sao lưu của Android, điều này phụ thuộc vào người dùng chọn bật tính năng đó. Điều đó là tốt cho các tùy chọn người dùng ứng dụng (sử dụng của Meier), bởi vì nếu người dùng không chọn tùy chọn đó, cô ấy sẽ không nhận được những bản sao lưu đó. Tuy nhiên, câu hỏi ban đầu là tạo một ID duy nhất cho thiết bịvà ID này được tạo cho mỗi ứng dụng, thậm chí không cho mỗi lần cài đặt, cho phép trên mỗi thiết bị và vì nó dựa trên người dùng chọn tùy chọn sao lưu, việc sử dụng nó vượt quá sở thích của người dùng (ví dụ: trong thời gian dùng thử giới hạn) bị giới hạn. - Carl
Điều này sẽ không hoạt động khi gỡ cài đặt hoặc xóa dữ liệu. - John Shelley


Ngoài ra, bạn có thể xem xét địa chỉ MAC của adapter Wi-Fi. Lấy như sau:

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

Yêu cầu quyền android.permission.ACCESS_WIFI_STATE trong tệp kê khai.

Được báo cáo khả dụng ngay cả khi Wi-Fi không được kết nối. Nếu Joe từ câu trả lời ở trên cho phép người này thử trên nhiều thiết bị của mình, điều đó thật tuyệt.

Trên một số thiết bị, nó không khả dụng khi Wi-Fi bị tắt.

CHÚ THÍCH: Từ Android 6.x, nó trả về địa chỉ mac giả phù hợp: 02:00:00:00:00:00


98
2018-06-23 14:27



Yêu cầu này android.permission.ACCESS_WIFI_STATE - ohhorob
Chúng tồn tại? Tôi thà hình dung ra một thiết bị ít điện thoại hơn (máy tính bảng AKA) ... - Seva Alekseyev
Tôi biết câu hỏi này là cũ - nhưng đây là một ý tưởng tuyệt vời. Tôi đã sử dụng ID MAC BT trong ứng dụng của mình, nhưng chỉ vì nó yêu cầu BT hoạt động. Chỉ cho tôi một thiết bị Android có giá trị phát triển cho điều đó KHÔNG có WiFi. - Jack
Tôi nghĩ rằng bạn sẽ thấy rằng nó không có sẵn khi WiFi tắt, trên khá nhiều tất cả các thiết bị Android. Tắt Wi-Fi sẽ xóa thiết bị ở cấp hạt nhân. - chrisdowney
@Sanandrea - hãy đối mặt với nó, trên một thiết bị bắt nguồn từ mọi thứ có thể được giả mạo. - ocodo


Có thông tin khá hữu ích đây.

Nó bao gồm năm loại ID khác nhau:

  1. IMEI (chỉ dành cho các thiết bị Android có sử dụng Điện thoại; nhu cầu android.permission.READ_PHONE_STATE)
  2. ID giả duy nhất (cho tất cả các thiết bị Android)
  3. ID Android (có thể là null, có thể thay đổi khi khôi phục cài đặt gốc, có thể được thay đổi trên điện thoại gốc)
  4. Địa chỉ MAC WLAN chuỗi (nhu cầu android.permission.ACCESS_WIFI_STATE)
  5. Địa chỉ MAC BT chuỗi (thiết bị có Bluetooth, nhu cầu android.permission.BLUETOOTH)

78
2018-02-08 02:16



Điểm quan trọng còn lại (ở đây và trong bài viết): bạn không thể nhận được WLAN hoặc BT MAC trừ khi chúng được bật! Nếu không, tôi nghĩ rằng MAC MAC sẽ là định danh hoàn hảo. Bạn không đảm bảo rằng người dùng sẽ bật Wi-Fi của họ và tôi thực sự không nghĩ rằng đó là 'thích hợp' để tự bật tính năng này. - Tom
@ Anh đã sai rồi. Bạn vẫn có thể đọc WLAN hoặc BT MAC ngay cả khi chúng bị tắt. Tuy nhiên, không có gì đảm bảo rằng thiết bị có sẵn các mô-đun WLAN hoặc BT. - Marqs
Đáng chú ý nhất, địa chỉ WiFi cục bộ và địa chỉ MAC không còn khả dụng. Phương thức getMacAddress () của đối tượng aWifiInfo và phương thức getAddress () sẽ trả về 02: 00: 00: 00: 00: 00 từ giờ trở đi - sarika kate
@sarikakate Đó là sự thật chỉ trong 6.0 Marshmallow và ở trên ... Nó vẫn hoạt động như mong đợi ở dưới 6.0 Marshmallow. - Smeet
@ Smeet Yeah bạn là right.I quên đề cập đến rằng nó làm việc dưới 6.0 - sarika kate


Blog nhà phát triển Android chính thức hiện có một bài viết đầy đủ về chủ đề này, Xác định cài đặt ứng dụng.


43
2018-04-06 07:36



Và điểm mấu chốt của lập luận đó là nếu bạn đang cố gắng lấy một ID duy nhất ra khỏi phần cứng, có lẽ bạn đang mắc lỗi. - Tim Bray
Và nếu bạn cho phép thiết bị khóa của mình được đặt lại bằng cài đặt gốc, mô hình phần mềm dùng thử của bạn cũng tốt như đã chết. - Seva Alekseyev