Có ID thiết bị Android duy nhất không?


Câu trả lời:


2025

Settings.Secure#ANDROID_IDtrả về ID Android dưới dạng duy nhất cho mỗi chuỗi hex 64 bit của người dùng .

import android.provider.Settings.Secure;

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

476
Đôi khi nó được gọi là null, nó được ghi 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 điện thoại đã root.
Seva Alekseyev


18
Tôi nghĩ rằng chúng ta cần cẩn thận về việc 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 được chạy lần đầu, có thể được đặt sau hoặc thậm chí có thể thay đổi về mặt lý thuyết, do đó ID duy nhất có thể thay đổi

46
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

35
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

1146

CẬP NHẬT : Kể từ các phiên bản gần đây của Android, nhiều vấn đề 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 xem câu trả lời của Anthony .

Tiết lộ đầy đủ: ứng dụng của tôi ban đầu sử dụng cách tiếp cận bên dưới nhưng không còn sử dụng cách tiếp cận này nữa và hiện chúng tôi sử dụng cách tiếp cận được nêu trong mục Blog của Nhà phát triển Android có liên kết câu trả lời của emmby với (cụ thể là tạo và lưu a 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ỉ hoạt động "một số" thời gian, và thật không may, điều đó không đủ tốt.

Dựa trên các thử nghiệm thiết bị của tôi (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 đều trả về giá trị cho TelephonyManager.getDeviceId()
  2. Tất cả các thiết bị GSM (tất cả được thử nghiệm với SIM) đã trả về 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ề giá trị cho ANDROID_ID
  5. Tất cả các thiết bị CDMA đều trả về cùng một giá trị (hoặc dẫn xuất của cùng một giá trị) cho cả hai ANDROID_IDTelephonyManager.getDeviceId()- miễn là tài khoản Google đã được thêm trong quá trình 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 hoặc bất kỳ thiết bị nào ở chế độ 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 là đủ. 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, do đó, chuỗi vẫn gần như duy nhất cho thiết bị, nhưng không xác định rõ ràng thiết bị thực tế của người dùng. Ví dụ: bằng cách 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 dưới đây, đừng quên rằng bạn cần có quyền đọc các TelephonyManagerthuộc tính, vì vậy hãy thêm điều này vào bảng 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;

151
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, phải không?
Seva Alekseyev

22
Do đó, tại sao tôi nói hầu hết sẽ không hoạt động mọi lúc :) Tôi chưa thấy câu trả lời nào cho câu hỏi này đá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 ở đây để bắt đầu. Rõ ràng là không có giải pháp cuối cùng cho tất cả. Các nhà sản xuất thiết bị cá nhân có thể có số sê-ri thiết bị, nhưng chúng không được hiển thị để chúng tôi sử dụng và đó không phải là một 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

31
Các mẫu mã hoạt động tuyệt vời. 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ề có độ dài 36 ký tự.
Richard

10
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

18
@softarn: Tôi tin rằng những gì bạn đang đề cập đến là Blog dành cho nhà phát triển Android mà emmby đã liên kết đến, điều này giải thích những gì bạn đang cố gắng nói, vì vậy có lẽ bạn nên đơn giản nêu lên nhận xét của anh ấy. Dù bằng cách nào, như emmby đề cập 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 yêu cầu một định danh DEVICE duy nhất (không phải đị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 một giả định rằng những gì bạn muốn không nhất thiết phải 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

439

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


Sau khi đọc mọi bài đăng Stack Overflow về việc tạo một ID duy nhất, blog của 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 và 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 Android hoặc điện thoại của họ, vì vậy ID duy nhất dựa trên phần cứng không phải là ý tưởng hay để THEO D USI NGƯỜI DÙNG
  • Đối với PHẦN MỀM THEO DACKI , đây là một ý tưởng tuyệt vời

Phần mềm

  • Người dùng có thể xóa / thay đổi ROM nếu họ đã 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 THEO D USERI NGƯỜI DÙNG CÁ NHÂN với sự đồng ý của họ là chỉ cần đăng nhập cho họ (làm cho nó liền mạch bằng OAuth)

Sự cố chung với Android

- Đảm bảo tính duy nhất (bao gồm các thiết bị đã root) 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 the unique ID of build information (may overlap data - API < 9)

Cảm ơn @stansult đã đăng tất cả các tùy chọn của chúng tôi (trong câu hỏi Stack Overflow 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 - Rất khó xảy ra
    • API 5+ <uses-permission android:name="android.permission.GET_ACCOUNTS" />trở lên
    • API 14+ <uses-permission android:name="android.permission.READ_PROFILE" /> <uses-permission android:name="android.permission.READ_CONTACTS" />( Cách nhận địa chỉ email chính của thiết bị Android )
  • Số điện thoại người dùng - Phần mềm

    • Người dùng có thể thay đổi số điện thoại - Rất khó xảy ra
    • <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 sự thật rằng 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 xấu, vì họ tin rằng bạn chỉ đang đánh 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 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ị đã root)

    • Vì nó có thể là 'null', chúng tôi 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ếu bạn có người dùng với 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ị đã root để có thể có các mục trùng lặp nếu bạn đang theo dõi 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 mã định danh duy nhất đến trực tiếp từ người dùng. Điều này là rõ ràng rằng 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, có nhu cầu android.permission.BLUETOOTH)

    • Hầu hết các ứng dụng trên thị trường 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 bao gồm điều này, người dùng có thể nghi ngờ.
    • <uses-permission android:name="android.permission.BLUETOOTH "/>
  • ID giả duy nhất - Phần mềm (dành cho tất cả các thiết bị Android)

    • Rất có thể, có thể chứa các va chạm - Xem phương pháp của tôi được đăng dưới đây!
    • Đ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 cần lấy bất cứ thứ gì riêng tư. Bạn có thể tạo ID ẩn danh của riêng bạn từ thông tin thiết bị.

Tôi biết không có cách 'hoàn hảo' nào để có được một ID duy nhất mà không cần sử dụng quyền; tuy nhiên, đôi khi chúng ta chỉ thực sự cần theo dõi quá trình cài đặt thiết bị. Khi nói đến việc tạo một ID duy nhất, chúng ta có thể tạo một 'id duy nhất giả' chỉ dựa trên thông tin mà API Android cung cấp cho chúng ta mà không cần sử dụng thêm quyền. 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ỉ gặp phải sự thật rằng 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ể điều chỉnh phương thức 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 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'.

HÃY NHỚ , về mặt kỹ thuật, bạn chỉ bỏ lỡ khoảng 0,5% người dùng 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 'null'. (xem http://developer.android.com/about/dashboards/index.html )

Nếu vẫn thất bại:

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

Thay đổi:

  • Đã xóa 'Android.SECURE_ID' vì đặ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 giả

Xin hãy xem phương pháp dưới đây:

/**
 * 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ụ Google Play):

Từ bảng điều khiển của Nhà phát triể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 của 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 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-service/id.html http://developer.android.com/reference/com/google/android/gms/ads/identifier/Ad Quảng cáoIdClient.html

Quan trọng:

Dự kiến ​​ID quảng cáo sẽ thay thế hoàn toàn việc sử dụng các số nhận dạng khác hiện có cho mục đích quảng cáo (chẳng hạn như việc sử dụng ANDROID_ID trong Cài đặt. Bảo mật) khi Dịch vụ Google Play khả dụng. Các trường hợp Dịch vụ Google Play không khả dụng được chỉ định bởi GooglePlayServiceNotAv AvailableException bị ném bởi getAd Quảng cáoIdInfo ().

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

http://en.kioskea.net/faq/34732-android-reset-your-ad Quảng cáo-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 được đưa vào, xin vui lòng bình luận!

Dịch vụ Google Player InstanceID

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


Nhưng Buildlớp học sẽ thay đổi khi cập nhật hệ điều hành? Đặc biệt là 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

2
tôi đã sử dụng phương pháp của bạn trong ứng dụng của tôi để gửi bình luận. tôi có tin xấu Thật không may, PsuedoID không phải là duy nhất hoàn toàn. máy chủ của tôi đã ghi lại 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 có nhiều người khác nhau. tổng số hồ sơ cho đến nay là 10.000. xin vui lòng cho tôi biết tại sao điều này xảy ra. xe tăng.
hojjat reyhane 17/03/2015

1
Tôi đã viết điều này hơn 1,5 năm trước. 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

2
sorta..tôi thực sự đánh giá cao nếu bạn lướt qua câu hỏi và đưa ra suy nghĩ của bạn về điều này
Durai Amuthan.

1
@ user1587329 Cảm ơn bạn. Tôi đang cố gắng để cập nhật điều này cho mọi người. Câu hỏi này rất khó khi nói về phần cứng so với phần mềm và đa nền tảng.
Jared Burrows

340

Như Dave Webb đã đề cập, Blog Nhà phát triển Android có một bài viết đề cập đến vấn đề này. Giải pháp ưa thích của họ là theo dõi cài đặt ứng dụng thay vì thiết bị và điều đó sẽ hoạt động tốt trong hầu hết các trường hợp sử dụng. Bài đăng trên blog sẽ cho bạn thấy 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 nó.

Tuy nhiên, bài đăng trên blog tiếp tục thảo luận về 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 ai đó tại Google để có thêm một số giải thích rõ ràng về một vài mục trong trường hợp bạn cần phải làm như vậy. Đâ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à định danh thiết bị ưa thích. 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 có vấn đề được đề cập trong bài.
  • 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 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 giả lập, btw.
  • Google tin rằng các OEM đã vá lỗi 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 từ đầu tháng 4 năm 2011, ít nhất, vẫn dễ dàng tìm thấy các thiết bị bị hỏng ANDROID_ID.

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

Lưu ý rằng đối với các thiết bị phải dự phòng ID thiết bị, ID duy nhất SILL tồn tại trên các thiết lập lại của nhà máy. Đây là một cái gì đó để nhận thức được. Nếu bạn cần đảm bảo rằng 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 việc quay lại trực tiếp vào 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ị, không phải ID cài đặt ứng dụng. Trong hầu hết các tình huống, 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 ID thiết bị, thì đoạn mã sau có thể sẽ phù hợp với 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;
    }
}

6
Bạn có nên băm các ID khác nhau để chúng có cùng kích thước không? Ngoài ra, bạn nên băm ID thiết bị để không vô tình làm lộ thông tin cá nhân.
Steve Pomeroy

2
Điểm tốt, Steve. Tôi đã cập nhật mã để luôn trả về UUID. Điều này đảm bảo rằng a) ID được tạo luôn có cùng kích thước và b) ID của Android và thiết bị được băm trước khi được trả về để tránh vô tình làm 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ẽ tồn tại trên các thiết lập lại của 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

1
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 định danh thiết bị. Mã của bạn dài hơn và phức tạp hơn trong bài viết trên blog và đối với tôi nó không rõ ràng rằng nó có thêm bất kỳ giá trị nào.
Tim Bray

7
Điểm hay, tôi đã cập nhật bình luận để đề nghị 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ĩ giải pháp này vẫn có giá trị cho những người cần một thiết bị hơn là ID cài đặt.
emmby

8
ANDROID_ID có thể thay đổi khi khôi phục cài đặt gốc, do đó, nó cũng không thể nhận dạng thiết bị
Samuel

180

Dưới đây là mã mà Reto Meier đã sử dụng trong bản trình bày Google I / O 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 chiến lược sao lưu này để gửi tùy chọn lên đám mây (cũng được mô tả trong cuộc nói chuyện của Reto , bạn nên có một id liên kết với người dùng và dính xung quanh sau khi thiết bị bị xóa hoặc thậm chí thay thế. Tôi dự định sử dụng trong phân tích sắp tới (nói cách khác, tôi chưa làm được điều đó :).


Tôi đã sử dụng phương pháp của @Lenn Dolling với thời gian hiện tại được 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ề thiết bị root? Họ có thể truy cập cái này và thay đổi uid sang một cái khác một cách dễ dàng.
tasomaniac

3
Tùy chọn tuyệt vời nếu bạn không cần ID duy nhất để duy trì sau khi gỡ cài đặt và cài đặt lại (ví dụ: sự kiện / trò chơi quảng cáo mà bạn có ba cơ hội để giành chiến thắng, giai đoạn).
Kyle Clegg

2
Bản trình bày Meier phụ thuộc vào việc sử dụng Trình quản lý sao lưu Android, điều này phụ thuộc vào người dùng chọn bật tính năng đó. Điều đó tốt cho các tùy chọn của người dùng ứng dụng (sử dụng 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à về việc 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 và thậm chí không phải mỗi lần cài đặt, chứ không phải mỗi thiết bị và vì nó phụ thuộc vào người dùng chọn tùy chọn sao lưu, nên nó sử dụng ngoài người dùng tùy chọn (ví dụ: đối với bản dùng thử giới hạn thời gian) bị giới hạn.
Carl

12
Điều này sẽ không hoạt động khi gỡ cài đặt hoặc xóa dữ liệu.
John Shelley

106

Ngoài ra, bạn có thể xem xét địa chỉ MAC của bộ điều hợp Wi-Fi. Lấy như vậy:

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

Yêu cầu sự cho phép android.permission.ACCESS_WIFI_STATEtrong bảng kê khai.

Báo cáo là có sẵn ngay cả khi Wi-Fi không được kết nối. Nếu Joe từ câu trả lời ở trên thử cái này trên nhiều thiết bị của anh ta, điều đó thật tuyệt.

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

LƯU Ý: Từ Android 6.x, nó trả về địa chỉ mac giả nhất quán:02:00:00:00:00:00


8
Điều này là bắt buộcandroid.permission.ACCESS_WIFI_STATE
ohhorob

5
Tôi nghĩ bạn sẽ thấy rằng nó không khả dụng khi WiFi bị tắt, trên hầu hết các thiết bị Android. Tắt WiFi sẽ loại bỏ thiết bị ở cấp kernel.
chrisdowney

12
@Sanandrea - Hãy đối mặt với nó, trên một thiết bị đã root, MỌI THỨ có thể bị giả mạo.
ocodo

5
Truy cập địa chỉ MAC WiFi đã bị chặn trên Android M: stackoverflow.com/questions/31329733/ cấp
breez

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

87

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 thiết bị Android có sử dụng Điện thoại; cầnandroid.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ể thay đổi trên điện thoại đã root)
  4. Chuỗi địa chỉ MAC MAC (cầnandroid.permission.ACCESS_WIFI_STATE )
  5. Chuỗi địa chỉ MAC MAC (thiết bị có Bluetooth, có nhu cầu android.permission.BLUETOOTH)

2
Điểm quan trọng còn sót lại (ở đây và trong bài viết): bạn không thể nhận được mạng 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 có gì đả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 nó là 'phù hợp' để tự bật nó.
Tom

1
@Tom bạn 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

2
Đáng chú ý nhất là các địa chỉ MAC WiFi và Bluetooth cục bộ không còn khả dụng. Phương thức getMacAddress () của đối tượng aWifiInfo và phương thức BluetoothAd Module.getDefaultAd Module (). GetAddress () sẽ trả về cả02: 00: 00: 00: 00
sarika kate

4
@sarikakate Điều đó chỉ đúng trong 6.0 Marshmallow trở lên ... Nó vẫn hoạt động như mong đợi trong 6.0 Marshmallow.
Smeet

@Smeet Vâng, bạn đã đúng. Tôi quên đề cập rằng nó hoạt động dưới 6.0
sarika kate

51

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 .


4
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 đã mắc lỗi.
Tim Bray

3
Và nếu bạn cho phép khóa thiết bị 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 sẽ tốt như chết.
Seva Alekseyev

43

Tại Google I / O Reto Meier đã đưa ra một câu trả lời mạnh mẽ về cách tiếp cận điều này sẽ đáp ứng hầu hết các nhu cầu của nhà phát triển để theo dõi người dùng qua các cài đặt. Anthony Nolan cho thấy hướng đi trong câu trả lời của anh ấy, nhưng tôi nghĩ tôi đã viết ra cách tiếp cận đầy đủ để những người khác có thể dễ dàng thấy cách thực hiện (tôi phải mất một thời gian để tìm hiểu chi tiết).

Cách tiếp cận này sẽ cung cấp cho bạn ID người dùng an toàn, ẩn danh, sẽ tồn tại lâu dài cho người dùng trên các thiết bị khác nhau (dựa trên tài khoản Google chính) và trên các cài đặt. Cách tiếp cận cơ bản là tạo ID người dùng ngẫu nhiên và lưu trữ tệp này trong tùy chọn chia sẻ của ứng dụng. Sau đó, bạn sử dụng tác nhân sao lưu của Google để lưu trữ các tùy chọn được chia sẻ được liên kết với tài khoản Google trên đám mây.

Chúng ta hãy đi qua cách tiếp cận đầy đủ. Trước tiên, chúng tôi cần tạo bản sao lưu cho SharedPreferences bằng Dịch vụ sao lưu Android. Bắt đầu bằng cách đăng ký ứng dụng của bạn thông qua http://developer.android.com/google/backup/signup.html.

Google sẽ cung cấp cho bạn khóa dịch vụ sao lưu mà bạn cần thêm vào bảng kê khai. Bạn cũng cần yêu cầu ứng dụng sử dụng BackupAgent như sau:

<application android:label="MyApplication"
         android:backupAgent="MyBackupAgent">
    ...
    <meta-data android:name="com.google.android.backup.api_key"
        android:value="your_backup_service_key" />
</application>

Sau đó, bạn cần tạo tác nhân sao lưu và bảo nó sử dụng tác nhân trợ giúp cho các cuộc họp chung:

public class MyBackupAgent extends BackupAgentHelper {
    // The name of the SharedPreferences file
    static final String PREFS = "user_preferences";

    // A key to uniquely identify the set of backup data
    static final String PREFS_BACKUP_KEY = "prefs";

    // Allocate a helper and add it to the backup agent
    @Override
    public void onCreate() {
        SharedPreferencesBackupHelper helper = new SharedPreferencesBackupHelper(this,          PREFS);
        addHelper(PREFS_BACKUP_KEY, helper);
    }
}

Để hoàn thành bản sao lưu, bạn cần tạo một phiên bản của BackupManager trong Hoạt động chính của mình:

BackupManager backupManager = new BackupManager(context);

Cuối cùng tạo ID người dùng, nếu nó chưa tồn tại và lưu nó trong SharedPreferences:

  public static String getUserID(Context context) {
            private static String uniqueID = null;
        private static final String PREF_UNIQUE_ID = "PREF_UNIQUE_ID";
    if (uniqueID == null) {
        SharedPreferences sharedPrefs = context.getSharedPreferences(
                MyBackupAgent.PREFS, 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();

            //backup the changes
            BackupManager mBackupManager = new BackupManager(context);
            mBackupManager.dataChanged();
        }
    }

    return uniqueID;
}

User_ID này bây giờ sẽ liên tục trong các cài đặt, ngay cả khi người dùng di chuyển thiết bị.

Để biết thêm thông tin về phương pháp này, hãy xem bài nói chuyện của Reto .

Và để biết chi tiết đầy đủ về cách triển khai tác nhân sao lưu, hãy xem Sao lưu dữ liệu . Tôi đặc biệt khuyên bạn nên kiểm tra phần dưới cùng vì việc sao lưu không xảy ra tức thời và vì vậy để kiểm tra bạn phải buộc sao lưu.


5
Điều này không dẫn đến nhiều thiết bị có cùng id khi người dùng có nhiều thiết bị? Một máy tính bảng và điện thoại chẳng hạn.
Tosa

Mục tiêu tối thiểu 8 là cần thiết cho việc này.
chia đôi

Đây có phải là cách ưa thích để tạo tải trọng xác minh khi thực hiện mua hàng trong ứng dụng không? Từ nhận xét mã ví dụ thanh toán trong ứng dụng: "Vì vậy, tải trọng của nhà phát triển tốt có các đặc điểm sau: 1. Nếu hai người dùng khác nhau mua một mặt hàng, tải trọng khác nhau giữa họ, do đó, một lần mua của người dùng không thể được phát lại cho người dùng khác. 2. Tải trọng phải sao cho bạn có thể xác minh ngay cả khi ứng dụng không phải là người khởi tạo luồng mua hàng (để các mặt hàng được người dùng mua trên một thiết bị hoạt động trên các thiết bị khác do người dùng sở hữu). "
TouchBoarder

@Tosa Tôi chỉ có cùng một câu hỏi. Nhưng chúng ta không thể sử dụng kỹ thuật này một lần nữa để tạo id thiết bị ảo và chỉ không sao lưu theo cùng một cách? Id thiết bị sẽ không tồn tại trong quá trình xóa hoặc cài đặt lại nhưng nếu chúng ta có id người dùng liên tục, chúng ta có thể không cần nhiều từ id thiết bị.
jwehrle

39

Tôi nghĩ rằng đây là cách chắc chắn để xây dựng bộ xương cho một ID duy nhất ... hãy kiểm tra nó.

ID giả duy nhất, hoạt động trên tất cả các thiết bị Android Một số thiết bị không có điện thoại (ví dụ: Máy tính bảng) hoặc vì một số lý do, bạn không muốn bao gồm quyền READ_PHONE_STATE. Bạn vẫn có thể đọc các chi tiết như Phiên bản ROM, tên nhà sản xuất, loại CPU và các chi tiết phần cứng khác, sẽ rất phù hợp nếu bạn muốn sử dụng ID để kiểm tra khóa nối tiếp hoặc các mục đích chung khác. ID được tính theo cách này sẽ không phải là duy nhất: có thể tìm thấy hai thiết bị có cùng ID (dựa trên cùng một phần cứng và hình ảnh ROM) nhưng những thay đổi trong các ứng dụng trong thế giới thực là không đáng kể. Với mục đích này, bạn có thể sử dụng lớp Build:

String m_szDevIDShort = "35" + //we make this look like a valid IMEI
            Build.BOARD.length()%10+ Build.BRAND.length()%10 +
            Build.CPU_ABI.length()%10 + Build.DEVICE.length()%10 +
            Build.DISPLAY.length()%10 + Build.HOST.length()%10 +
            Build.ID.length()%10 + Build.MANUFACTURER.length()%10 +
            Build.MODEL.length()%10 + Build.PRODUCT.length()%10 +
            Build.TAGS.length()%10 + Build.TYPE.length()%10 +
            Build.USER.length()%10 ; //13 digits

Hầu hết các thành viên Build là các chuỗi, những gì chúng tôi đang làm ở đây là lấy độ dài của chúng và biến đổi nó thông qua modulo trong một chữ số. Chúng tôi có 13 chữ số như vậy và chúng tôi sẽ thêm hai chữ số nữa ở phía trước (35) để có cùng kích thước ID với IMEI (15 chữ số). Có những khả năng khác ở đây là tốt, chỉ cần nhìn vào các chuỗi này. Trả về một cái gì đó như 355715565309247. Không có sự cho phép đặc biệt là cần thiết, làm cho phương pháp này rất thuận tiện.


(Thông tin thêm: Kỹ thuật được nêu ở trên được sao chép từ một bài viết trên Pocket Magic .)


7
Giải pháp thú vị. Có vẻ như đây là một tình huống mà bạn thực sự nên băm tất cả dữ liệu được nối với nhau thay vì cố gắng đưa ra chức năng "băm" của riêng bạn. Có nhiều trường hợp bạn bị va chạm ngay cả khi có dữ liệu quan trọng khác nhau cho từng giá trị. Đề nghị của tôi: sử dụng hàm băm và sau đó chuyển đổi kết quả nhị phân thành số thập phân và cắt bớt nó khi cần thiết. Để làm điều đó đúng, mặc dù bạn thực sự nên sử dụng UUID hoặc chuỗi băm đầy đủ.
Steve Pomeroy

21
Bạn nên cung cấp tín dụng cho các nguồn của mình ... Điều này đã được gỡ bỏ ngay trong bài viết sau: Pocketmagic.net/?p=1662
Steve Haley

8
ID này được mở cho các va chạm như bạn không biết gì. Nó thực tế được đảm bảo giống nhau trên các thiết bị giống hệt nhau từ cùng một nhà mạng.
Seva Alekseyev

7
Điều này cũng có thể thay đổi nếu thiết bị được nâng cấp.
David đưa ra

8
Giải pháp rất, rất tệ. Đã thử nghiệm trên hai Nexus 5 ... Trả về cùng một số.
Sinan Dizdarević

38

Đoạn mã sau trả về số sê-ri của thiết bị bằng API Android ẩn. Nhưng, mã này không hoạt động trên Samsung Galaxy Tab vì "ro.serialno" không được đặt trên thiết bị này.

String serial = null;

try {
    Class<?> c = Class.forName("android.os.SystemProperties");
    Method get = c.getMethod("get", String.class);
    serial = (String) get.invoke(c, "ro.serialno");
}
catch (Exception ignored) {

}

Tôi chỉ đọc trên nhà phát triển xda rằng cái ro.serialnođược sử dụng để tạo Settings.Secure.ANDROID_ID. Vì vậy, về cơ bản chúng là các đại diện khác nhau của cùng một giá trị.
Martin

@Martin: nhưng có lẽ số sê-ri không thay đổi khi đặt lại thiết bị. Phải không? Chỉ cần một giá trị mới ANDROID_IDđược bắt nguồn từ nó.
Ronnie

Trên thực tế trên tất cả các thiết bị tôi đã thử nghiệm chúng giống hệt nhau. Hoặc ít nhất là các giá trị băm giống nhau (vì lý do riêng tư tôi không ghi giá trị thực vào tệp nhật ký).
Martin

Giá trị này giống nhưandroid.os.Build.SERIAL
eugeneek

android.os.Build.SERIALsẽ hết hạn vào Android O, xem android-developers.googleblog.com/2017/04/...
EpicPandaForce

32

Đó là một câu hỏi đơn giản, không có câu trả lời đơn giản.

Hơn nữa, tất cả các câu trả lời hiện có ở đây là dù đã lỗi thời hay không đáng tin cậy.

Vì vậy, nếu bạn đang tìm kiếm một giải pháp vào năm 2020 .

Dưới đây là một số điều cần lưu ý:

Tất cả các số nhận dạng dựa trên phần cứng (SSAID, IMEI, MAC, v.v.) đều không đáng tin cậy cho các thiết bị không phải của google (Mọi thứ trừ Pixels và Nexuses), hơn 50% thiết bị hoạt động trên toàn thế giới. Do đó, các định danh Android chính thức thực hành tốt nhất nêu rõ:

Tránh sử dụng số nhận dạng phần cứng , chẳng hạn như SSAID (ID Android), IMEI, địa chỉ MAC, v.v ...

Điều đó làm cho hầu hết các câu trả lời ở trên không hợp lệ. Ngoài ra do các bản cập nhật bảo mật Android khác nhau, một số trong số chúng yêu cầu các quyền thời gian chạy mới hơn và chặt chẽ hơn, có thể bị người dùng từ chối.

Ví dụ như CVE-2018-9489 ảnh hưởng đến tất cả các kỹ thuật dựa trên WIFI được đề cập ở trên.

Điều đó làm cho những định danh không chỉ không đáng tin cậy, mà còn không thể truy cập được trong nhiều trường hợp.

Vì vậy, nói một cách đơn giản hơn: đừng sử dụng những kỹ thuật đó .

Nhiều câu trả lời khác ở đây đang đề xuất sử dụng AdvertisingIdClient, cũng không tương thích, vì thiết kế của nó chỉ nên được sử dụng cho hồ sơ quảng cáo. Nó cũng được nêu trong tài liệu tham khảo chính thức

Chỉ sử dụng ID quảng cáo cho trường hợp sử dụng hồ sơ người dùng hoặc quảng cáo

Không chỉ không đáng tin cậy để nhận dạng thiết bị, mà bạn còn phải tuân theo quyền riêng tư của người dùng về theo dõi quảng cáo chính sách , trong đó nêu rõ rằng người dùng có thể đặt lại hoặc chặn nó bất cứ lúc nào.

Vì vậy, đừng sử dụng nó .

Vì bạn không thể có định danh thiết bị đáng tin cậy và độc nhất trên toàn cầu. Tài liệu tham khảo chính thức của Android đề xuất:

Sử dụng FirebaseInstanceId hoặc GUID được lưu trữ riêng tư bất cứ khi nào có thể cho tất cả các trường hợp sử dụng khác, ngoại trừ phòng chống gian lận thanh toán và điện thoại.

Nó là duy nhất cho cài đặt ứng dụng trên thiết bị, vì vậy khi người dùng gỡ cài đặt ứng dụng - nó đã bị xóa, vì vậy nó không đáng tin cậy 100%, nhưng đó là điều tốt nhất tiếp theo.

Để sử dụng FirebaseInstanceIdthêm phụ thuộc nhắn tin firebase mới nhất vào lớp của bạn

implementation 'com.google.firebase:firebase-messaging:20.2.0'

Và sử dụng mã dưới đây trong một chủ đề nền:

String reliableIdentifier = FirebaseInstanceId.getInstance().getId();

Nếu bạn cần lưu trữ nhận dạng thiết bị trên máy chủ từ xa của mình, thì đừng lưu nó dưới dạng (văn bản thuần túy), mà là một hàm băm với muối .

Ngày nay, nó không chỉ là một thực tiễn tốt nhất, bạn thực sự phải thực hiện nó theo luật theo GDPR - định danh và các quy định tương tự.


3
Hiện tại, đây là câu trả lời hay nhất và câu đầu tiên là tóm tắt hay nhất: "Đó là một câu hỏi đơn giản, không có câu trả lời đơn giản - chỉ cần yêu nó.
b2mob

Bạn phải đánh giá cao nhận xét "ngoại trừ phòng chống gian lận thanh toán và điện thoại" mà không có câu trả lời nào được cung cấp về cách giải quyết trường hợp sử dụng đó.
Eran Boudjnah

@EranBoudjnah Câu nói đó từ tài liệu tham khảo chính thức, được liên kết trong câu trả lời. Tôi có thể cố gắng giải quyết trường hợp sử dụng đó, nhưng vì nó không cụ thể đối với câu hỏi OP, Theo chính sách của stackoverflow - nó nên được thực hiện trong một câu hỏi dành riêng.
Nikita Kurtin

Tôi chỉ nói rằng câu trả lời là không đầy đủ. Nhưng tôi biết đó không phải là lỗi của bạn vì đó là một trích dẫn.
Eran Boudjnah

1
@ M.UsmanKhan, câu trả lời được viết ngay sau đó: " Hôm nay, nó không chỉ là một cách thực hành tốt nhất, mà bạn thực sự phải làm theo luật theo GDPR - định danh và các quy định tương tự. "
Nikita Kurtin

27

Sử dụng mã bên dưới, bạn có thể lấy ID thiết bị duy nhất của thiết bị HĐH Android dưới dạng chuỗi.

deviceId = Secure.getString(getApplicationContext().getContentResolver(), Secure.ANDROID_ID); 

21

Một trường nối tiếp đã được thêm vàoBuild lớp trong API cấp 9 (Android 2.3 - Gingerbread). Tài liệu nói rằng nó đại diện cho số sê-ri phần cứng. Do đó, nó phải là duy nhất, nếu nó tồn tại trên thiết bị.

Tôi không biết liệu nó có thực sự được hỗ trợ (= không null) bởi tất cả các thiết bị có cấp API> = 9 hay không.


2
Thật không may, nó "không rõ".
m0skit0

18

Một điều tôi sẽ thêm - tôi có một trong những tình huống độc đáo đó.

Sử dụng:

deviceId = Secure.getString(this.getContext().getContentResolver(), Secure.ANDROID_ID);

Hóa ra, mặc dù Viewsonic G Tablet của tôi báo cáo DeviceID không phải là Null, nhưng mỗi G Tablet đều báo cáo cùng một số.

Làm cho nó thú vị khi chơi "Pocket Empires" cho phép bạn truy cập ngay vào tài khoản của ai đó dựa trên DeviceID "duy nhất".

Thiết bị của tôi không có radio di động.


Id là gì? có phải là nguy hiểm không 9774d56d682e549c?
Mr_and_Mrs_D

Wow, đã rất lâu rồi tôi mới ném chiếc máy tính bảng đó từ lâu. Không thể nói.
Tony Maro

Làm. Ngoài ra, nhỏ gọn hơn rất nhiều so với ID mà tôi nhận được từ UUID ngẫu nhiên.
Treewallie

1
@Treewallie có hoạt động không? Bạn có thể nhận cùng một ID thiết bị từ các Ứng dụng khác nhau không?
Arnold Brown

@ArnoldBrown Có. Hãy chắc chắn để kiểm tra nó kỹ lưỡng. Chúc một ngày tốt lành: D
Treewallie

16

Để biết hướng dẫn chi tiết về cách nhận số nhận dạng duy nhất cho mỗi thiết bị Android mà ứng dụng của bạn được cài đặt từ đó, hãy xem Blog chính thức của Nhà phát triển Android đăng bài Nhận dạng cài đặt ứng dụng .

Có vẻ như cách tốt nhất là bạn tự tạo một cái khi cài đặt và sau đó đọc nó khi ứng dụng được khởi chạy lại.

Cá nhân tôi thấy điều này chấp nhận được nhưng không lý tưởng. Không một định danh nào được cung cấp bởi Android hoạt động trong mọi trường hợp vì hầu hết đều phụ thuộc vào trạng thái radio của điện thoại (bật / tắt Wi-Fi, bật / tắt di động, bật / tắt Bluetooth). Những người khác, nhưSettings.Secure.ANDROID_ID phải được thực hiện bởi nhà sản xuất và không được đảm bảo là duy nhất.

Sau đây là một ví dụ về việc ghi dữ liệu vào tệp cài đặt sẽ được lưu trữ cùng với bất kỳ dữ liệu nào khác mà ứng dụng lưu cục bộ.

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

Nếu bạn muốn theo dõi cài đặt ứng dụng này là hoàn hảo. Các thiết bị theo dõi mặc dù phức tạp hơn rất nhiều và dường như không phải là một giải pháp hoàn toàn kín gió.
Luca Spiller

Những thiết bị đã root thì sao? Họ có thể thay đổi id cài đặt này một cách dễ dàng, phải không?
tasomaniac

Chắc chắn rồi. Root có thể thay đổi ID cài đặt. Bạn có thể kiểm tra root bằng cách sử dụng khối mã này: stackoverflow.com/questions/1101380/ trộm
Kevin Parker

Nếu chúng ta thiết lập lại nhà máy, tập tin sẽ xóa?
Jamshid

Nếu bạn khôi phục cài đặt gốc và xóa hoặc định dạng phân vùng / dữ liệu thì UUID sẽ khác.
Kevin Parker

12

Thêm mã dưới đây trong tệp lớp:

final TelephonyManager tm = (TelephonyManager) getBaseContext()
            .getSystemService(SplashActivity.TELEPHONY_SERVICE);
    final String tmDevice, tmSerial, androidId;
    tmDevice = "" + tm.getDeviceId();
    Log.v("DeviceIMEI", "" + tmDevice);
    tmSerial = "" + tm.getSimSerialNumber();
    Log.v("GSM devices Serial Number[simcard] ", "" + tmSerial);
    androidId = "" + android.provider.Settings.Secure.getString(getContentResolver(),
            android.provider.Settings.Secure.ANDROID_ID);
    Log.v("androidId CDMA devices", "" + androidId);
    UUID deviceUuid = new UUID(androidId.hashCode(),
            ((long) tmDevice.hashCode() << 32) | tmSerial.hashCode());
    String deviceId = deviceUuid.toString();
    Log.v("deviceIdUUID universally unique identifier", "" + deviceId);
    String deviceModelName = android.os.Build.MODEL;
    Log.v("Model Name", "" + deviceModelName);
    String deviceUSER = android.os.Build.USER;
    Log.v("Name USER", "" + deviceUSER);
    String devicePRODUCT = android.os.Build.PRODUCT;
    Log.v("PRODUCT", "" + devicePRODUCT);
    String deviceHARDWARE = android.os.Build.HARDWARE;
    Log.v("HARDWARE", "" + deviceHARDWARE);
    String deviceBRAND = android.os.Build.BRAND;
    Log.v("BRAND", "" + deviceBRAND);
    String myVersion = android.os.Build.VERSION.RELEASE;
    Log.v("VERSION.RELEASE", "" + myVersion);
    int sdkVersion = android.os.Build.VERSION.SDK_INT;
    Log.v("VERSION.SDK_INT", "" + sdkVersion);

Thêm vào AndroidManifest.xml:

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

10

ID thiết bị duy nhất của thiết bị HĐH Android dưới dạng Chuỗi, sử dụng TelephonyManagerANDROID_ID, được lấy bởi:

String deviceId;
final TelephonyManager mTelephony = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
if (mTelephony.getDeviceId() != null) {
    deviceId = mTelephony.getDeviceId();
}
else {
    deviceId = Secure.getString(
                   getApplicationContext().getContentResolver(),
                   Secure.ANDROID_ID);
}

Nhưng tôi thực sự khuyên bạn nên sử dụng một phương pháp được đề xuất bởi Google, xem Xác định cài đặt ứng dụng .


9

Có rất nhiều cách tiếp cận khác nhau để giải quyết các ANDROID_IDvấn đề đó ( nullđôi khi hoặc các thiết bị của một kiểu máy cụ thể luôn trả về cùng một ID) với những ưu và nhược điểm:

  • Thực hiện thuật toán tạo ID tùy chỉnh (dựa trên các thuộc tính của thiết bị được coi là tĩnh và sẽ không thay đổi -> ai biết)
  • Lạm dụng các ID khác như IMEI , số sê-ri, địa chỉ Wi-Fi / Bluetooth-MAC (chúng sẽ không tồn tại trên tất cả các thiết bị hoặc các quyền bổ sung trở nên cần thiết)

Bản thân tôi thích sử dụng triển khai OpenUDID hiện có (xem https://github.com/ylechelle/OpenUDID ) cho Android (xem https://github.com/vieux/OpenUDID ). Nó dễ dàng tích hợp và sử dụng các ANDROID_IDdự phòng cho những vấn đề được đề cập ở trên.


8

Làm thế nào về IMEI . Đó là duy nhất cho Android hoặc các thiết bị di động khác.


9
Không dành cho máy tính bảng của tôi, không có IMEI vì chúng không kết nối với nhà cung cấp dịch vụ di động của tôi.
Brill Pappin

2
Chưa kể các thiết bị CDMA có ESN thay vì IMEI.
David đưa ra

@David Cho có CDMA nào với Android không?
Elzo Valugi

1
Nó sẽ chỉ làm điều đó một điện thoại :) Một máy tính bảng có thể không.
Brill Pappin

3
@ElzoValugi Đã "ngày này" và vẫn chưa phải tất cả máy tính bảng đều có thẻ SIM.
Matthew Quiros

8

Đây là cách tôi tạo id duy nhất:

public static String getDeviceId(Context ctx)
{
    TelephonyManager tm = (TelephonyManager) ctx.getSystemService(Context.TELEPHONY_SERVICE);

    String tmDevice = tm.getDeviceId();
    String androidId = Secure.getString(ctx.getContentResolver(), Secure.ANDROID_ID);
    String serial = null;
    if(Build.VERSION.SDK_INT > Build.VERSION_CODES.FROYO) serial = Build.SERIAL;

    if(tmDevice != null) return "01" + tmDevice;
    if(androidId != null) return "02" + androidId;
    if(serial != null) return "03" + serial;
    // other alternatives (i.e. Wi-Fi MAC, Bluetooth MAC, etc.)

    return null;
}

nếu chúng tôi sử dụng ReadPhoneState trong phiên bản 6.0 yêu cầu cấp phép thời gian chạy
Harsha

8

Hai xu của tôi - NB đây là dành cho một ID duy nhất (err) của thiết bị - không phải ID cài đặt như được thảo luận trong blog của nhà phát triển Android .

Lưu ý rằng giải pháp được cung cấp bởi @emmby rơi vào ID mỗi ứng dụng vì SharedPreferences không được đồng bộ hóa qua các quy trình (xem tại đâytại đây ). Vì vậy, tôi đã tránh điều này hoàn toàn.

Thay vào đó, tôi đã gói gọn các chiến lược khác nhau để nhận ID (thiết bị) trong enum - thay đổi thứ tự của hằng số enum ảnh hưởng đến mức độ ưu tiên của các cách khác nhau để nhận ID. ID không null đầu tiên được trả về hoặc một ngoại lệ được đưa ra (theo thông lệ Java tốt không mang lại ý nghĩa null). Vì vậy, ví dụ trước tiên tôi có ĐIỆN THOẠI - nhưng một lựa chọn mặc định tốt sẽ là ANDROID_ID beta:

import android.Manifest.permission;
import android.bluetooth.BluetoothAdapter;
import android.content.Context;
import android.content.pm.PackageManager;
import android.net.wifi.WifiManager;
import android.provider.Settings.Secure;
import android.telephony.TelephonyManager;
import android.util.Log;

// TODO : hash
public final class DeviceIdentifier {

    private DeviceIdentifier() {}

    /** @see http://code.google.com/p/android/issues/detail?id=10603 */
    private static final String ANDROID_ID_BUG_MSG = "The device suffers from "
        + "the Android ID bug - its ID is the emulator ID : "
        + IDs.BUGGY_ANDROID_ID;
    private static volatile String uuid; // volatile needed - see EJ item 71
    // need lazy initialization to get a context

    /**
     * Returns a unique identifier for this device. The first (in the order the
     * enums constants as defined in the IDs enum) non null identifier is
     * returned or a DeviceIDException is thrown. A DeviceIDException is also
     * thrown if ignoreBuggyAndroidID is false and the device has the Android ID
     * bug
     *
     * @param ctx
     *            an Android constant (to retrieve system services)
     * @param ignoreBuggyAndroidID
     *            if false, on a device with the android ID bug, the buggy
     *            android ID is not returned instead a DeviceIDException is
     *            thrown
     * @return a *device* ID - null is never returned, instead a
     *         DeviceIDException is thrown
     * @throws DeviceIDException
     *             if none of the enum methods manages to return a device ID
     */
    public static String getDeviceIdentifier(Context ctx,
            boolean ignoreBuggyAndroidID) throws DeviceIDException {
        String result = uuid;
        if (result == null) {
            synchronized (DeviceIdentifier.class) {
                result = uuid;
                if (result == null) {
                    for (IDs id : IDs.values()) {
                        try {
                            result = uuid = id.getId(ctx);
                        } catch (DeviceIDNotUniqueException e) {
                            if (!ignoreBuggyAndroidID)
                                throw new DeviceIDException(e);
                        }
                        if (result != null) return result;
                    }
                    throw new DeviceIDException();
                }
            }
        }
        return result;
    }

    private static enum IDs {
        TELEPHONY_ID {

            @Override
            String getId(Context ctx) {
                // TODO : add a SIM based mechanism ? tm.getSimSerialNumber();
                final TelephonyManager tm = (TelephonyManager) ctx
                        .getSystemService(Context.TELEPHONY_SERVICE);
                if (tm == null) {
                    w("Telephony Manager not available");
                    return null;
                }
                assertPermission(ctx, permission.READ_PHONE_STATE);
                return tm.getDeviceId();
            }
        },
        ANDROID_ID {

            @Override
            String getId(Context ctx) throws DeviceIDException {
                // no permission needed !
                final String andoidId = Secure.getString(
                    ctx.getContentResolver(),
                    android.provider.Settings.Secure.ANDROID_ID);
                if (BUGGY_ANDROID_ID.equals(andoidId)) {
                    e(ANDROID_ID_BUG_MSG);
                    throw new DeviceIDNotUniqueException();
                }
                return andoidId;
            }
        },
        WIFI_MAC {

            @Override
            String getId(Context ctx) {
                WifiManager wm = (WifiManager) ctx
                        .getSystemService(Context.WIFI_SERVICE);
                if (wm == null) {
                    w("Wifi Manager not available");
                    return null;
                }
                assertPermission(ctx, permission.ACCESS_WIFI_STATE); // I guess
                // getMacAddress() has no java doc !!!
                return wm.getConnectionInfo().getMacAddress();
            }
        },
        BLUETOOTH_MAC {

            @Override
            String getId(Context ctx) {
                BluetoothAdapter ba = BluetoothAdapter.getDefaultAdapter();
                if (ba == null) {
                    w("Bluetooth Adapter not available");
                    return null;
                }
                assertPermission(ctx, permission.BLUETOOTH);
                return ba.getAddress();
            }
        }
        // TODO PSEUDO_ID
        // http://www.pocketmagic.net/2011/02/android-unique-device-id/
        ;

        static final String BUGGY_ANDROID_ID = "9774d56d682e549c";
        private final static String TAG = IDs.class.getSimpleName();

        abstract String getId(Context ctx) throws DeviceIDException;

        private static void w(String msg) {
            Log.w(TAG, msg);
        }

        private static void e(String msg) {
            Log.e(TAG, msg);
        }
    }

    private static void assertPermission(Context ctx, String perm) {
        final int checkPermission = ctx.getPackageManager().checkPermission(
            perm, ctx.getPackageName());
        if (checkPermission != PackageManager.PERMISSION_GRANTED) {
            throw new SecurityException("Permission " + perm + " is required");
        }
    }

    // =========================================================================
    // Exceptions
    // =========================================================================
    public static class DeviceIDException extends Exception {

        private static final long serialVersionUID = -8083699995384519417L;
        private static final String NO_ANDROID_ID = "Could not retrieve a "
            + "device ID";

        public DeviceIDException(Throwable throwable) {
            super(NO_ANDROID_ID, throwable);
        }

        public DeviceIDException(String detailMessage) {
            super(detailMessage);
        }

        public DeviceIDException() {
            super(NO_ANDROID_ID);
        }
    }

    public static final class DeviceIDNotUniqueException extends
            DeviceIDException {

        private static final long serialVersionUID = -8940090896069484955L;

        public DeviceIDNotUniqueException() {
            super(ANDROID_ID_BUG_MSG);
        }
    }
}

8

Có hơn 30 câu trả lời ở đây và một số là giống nhau và một số là duy nhất. Câu trả lời này dựa trên một vài trong số những câu trả lời đó. Một trong số đó là câu trả lời của @Lenn Dolling.

Nó kết hợp 3 ID và tạo ra một chuỗi hex 32 chữ số. Nó đã làm việc rất tốt cho tôi.

3 ID là:
Pseudo-ID - Nó được tạo dựa trên thông số kỹ thuật của thiết bị vật lý
ANDROID_ID - Settings.Secure.ANDROID_ID
Địa chỉ Bluetooth Bluetooth - bộ điều hợp Bluetooth

Nó sẽ trả về một cái gì đó như thế này: 551F27C060712A72730B0A0F734064B1

Lưu ý: Bạn luôn có thể thêm nhiều ID vào longIdchuỗi. Ví dụ: Số sê-ri. địa chỉ bộ chuyển đổi wifi. IMEI. Bằng cách này, bạn đang làm cho nó độc đáo hơn trên mỗi thiết bị.

@SuppressWarnings("deprecation")
@SuppressLint("HardwareIds")
public static String generateDeviceIdentifier(Context context) {

        String pseudoId = "35" +
                Build.BOARD.length() % 10 +
                Build.BRAND.length() % 10 +
                Build.CPU_ABI.length() % 10 +
                Build.DEVICE.length() % 10 +
                Build.DISPLAY.length() % 10 +
                Build.HOST.length() % 10 +
                Build.ID.length() % 10 +
                Build.MANUFACTURER.length() % 10 +
                Build.MODEL.length() % 10 +
                Build.PRODUCT.length() % 10 +
                Build.TAGS.length() % 10 +
                Build.TYPE.length() % 10 +
                Build.USER.length() % 10;

        String androidId = Settings.Secure.getString(context.getContentResolver(), Settings.Secure.ANDROID_ID);

        BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
        String btId = "";

        if (bluetoothAdapter != null) {
            btId = bluetoothAdapter.getAddress();
        }

        String longId = pseudoId + androidId + btId;

        try {
            MessageDigest messageDigest = MessageDigest.getInstance("MD5");
            messageDigest.update(longId.getBytes(), 0, longId.length());

            // get md5 bytes
            byte md5Bytes[] = messageDigest.digest();

            // creating a hex string
            String identifier = "";

            for (byte md5Byte : md5Bytes) {
                int b = (0xFF & md5Byte);

                // if it is a single digit, make sure it have 0 in front (proper padding)
                if (b <= 0xF) {
                    identifier += "0";
                }

                // add number to string
                identifier += Integer.toHexString(b);
            }

            // hex string to uppercase
            identifier = identifier.toUpperCase();
            return identifier;
        } catch (Exception e) {
            Log.e("TAG", e.toString());
        }
        return "";
}

1
Thêm UUID vào longIdvà lưu trữ nó trong một tệp, sẽ làm cho nó trở thành định danh duy nhất:String uuid = UUID.randomUUID().toString();
Mousa Alfhaily

1
Nếu vẫn thất bại, nếu người dùng có API thấp hơn (thấp hơn Gingerbread), đã đặt lại điện thoại của họ hoặc 'Secure.ANDROID_ID'. nếu trả về 'null', thì đơn giản ID được trả về sẽ chỉ dựa trên thông tin thiết bị Android của họ. Đây là nơi va chạm có thể xảy ra. Cố gắng không sử dụng HIỂN THỊ, HOST hoặc ID - những mục này có thể thay đổi. Nếu có va chạm, sẽ có dữ liệu chồng chéo. Nguồn: gist.github.com/pedja1/fe69e8a80ed505500caa
Mousa Alfh hàng

Nếu chúng ta cố gắng lấy số duy nhất theo dòng mã này, chúng ta có thể nói đó là Id duy nhất và nó sẽ không bao giờ xung đột với bất kỳ thiết bị nào khác không?
Ninja

1
@Ninja Vì địa chỉ mac BLE là duy nhất, nên ID được tạo sẽ luôn là duy nhất. Tuy nhiên, nếu bạn thực sự muốn chắc chắn, tôi khuyên bạn nên thêm UUID vào longId. Thay đổi một dòng như thế này: String longId = pseudoId + androidId + btId + UUID.randomUUID().toString();Điều này đảm bảo rằng ID được tạo sẽ là duy nhất.
'19

@ ᴛʜᴇᴘᴀᴛᴇʟ Cảm ơn bạn rất nhiều vì sự giúp đỡ to lớn này. Trên thực tế ứng dụng của tôi dữ liệu rất nhạy cảm vì vậy tôi cần chắc chắn về nó đó là lý do tại sao tôi chỉ xác nhận những điều này.
Ninja

7

Một cách khác là sử dụng /sys/class/android_usb/android0/iSerialtrong một ứng dụng mà không có bất kỳ quyền nào.

user@creep:~$ adb shell ls -l /sys/class/android_usb/android0/iSerial
-rw-r--r-- root     root         4096 2013-01-10 21:08 iSerial
user@creep:~$ adb shell cat /sys/class/android_usb/android0/iSerial
0A3CXXXXXXXXXX5

Để làm điều này trong Java, người ta chỉ cần sử dụng FileInputStream để mở tệp iSerial và đọc các ký tự. Chỉ cần chắc chắn rằng bạn bọc nó trong một trình xử lý ngoại lệ, bởi vì không phải tất cả các thiết bị đều có tệp này.

Ít nhất các thiết bị sau đây được biết là có tệp này có thể đọc được trên thế giới:

  • Galaxy Nexus
  • Nexus S
  • Motorola Xoom 3G
  • Toshiba AT300
  • HTC One V
  • MK MK Mini
  • Samsung Galaxy S II

Bạn cũng có thể thấy bài đăng trên blog của tôi Rò rỉ số sê-ri phần cứng Android cho các ứng dụng không có đặc quyền nơi tôi thảo luận về các tệp khác có sẵn cho thông tin.


Tôi chỉ đọc bài viết trên blog của bạn. Tôi tin rằng đây không phải là duy nhất: Build.SERIAL cũng có sẵn với bất kỳ quyền nào và (về lý thuyết) là một số sê-ri phần cứng duy nhất.
Tom

1
Bạn đúng. Đó chỉ là một cách nữa để thiết bị của bạn có thể được theo dõi và như bạn đã nói cả hai cách này đều không yêu cầu quyền ứng dụng.
insitusec

7

TelephonyManger.getDeviceId () Trả về ID thiết bị duy nhất, ví dụ: IMEI cho GSM và MEID hoặc ESN cho điện thoại CDMA.

final TelephonyManager mTelephony = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);            
String myAndroidDeviceId = mTelephony.getDeviceId(); 

Nhưng tôi khuyên bạn nên sử dụng:

Cài đặt.Secure.ANDROID_ID trả về ID Android dưới dạng chuỗi hex 64 bit duy nhất.

    String   myAndroidDeviceId = Secure.getString(getApplicationContext().getContentResolver(), Secure.ANDROID_ID); 

Đôi khi TelephonyManger.getDeviceId () sẽ trả về null, vì vậy để đảm bảo một id duy nhất bạn sẽ sử dụng phương thức này:

public String getUniqueID(){    
    String myAndroidDeviceId = "";
    TelephonyManager mTelephony = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
    if (mTelephony.getDeviceId() != null){
        myAndroidDeviceId = mTelephony.getDeviceId(); 
    }else{
         myAndroidDeviceId = Secure.getString(getApplicationContext().getContentResolver(), Secure.ANDROID_ID); 
    }
    return myAndroidDeviceId;
}

Gần đây tôi đã phát hiện ra rằng thiết bị của khách hàng loại SM-G928F / Galaxy S6 edge + chỉ cung cấp 15 thay vì 16 chữ số hex cho ID Android.
Holger Jakobs

7

Để nhận dạng phần cứng của một thiết bị Android cụ thể, bạn có thể kiểm tra Địa chỉ MAC.

bạn có thể làm theo cách đó:

trong AndroidManifest.xml

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

bây giờ trong mã của bạn:

List<NetworkInterface> interfacesList = Collections.list(NetworkInterface.getNetworkInterfaces());

for (NetworkInterface interface : interfacesList) {
   // This will give you the interface MAC ADDRESS
   interface.getHardwareAddress();
}

Trong mọi thiết bị Android, ít nhất một phù thủy Giao diện "wlan0" là chip WI-FI. Mã này hoạt động ngay cả khi WI-FI không được bật.

PS Chúng là một loạt các Giao diện khác mà bạn sẽ nhận được từ danh sách chứa MACS Nhưng điều này có thể thay đổi giữa các điện thoại.


7

Tôi sử dụng đoạn mã sau để lấy IMEIhoặc sử dụng Secure. ANDROID_IDthay thế, khi thiết bị không có khả năng của điện thoại:

String identifier = null;
TelephonyManager tm = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE));
if (tm != null)
      identifier = tm.getDeviceId();
if (identifier == null || identifier .length() == 0)
      identifier = Secure.getString(activity.getContentResolver(),Secure.ANDROID_ID);

7

Cụ thể hơn , Settings.Secure.ANDROID_ID. Đây là số lượng 64 bit được tạo và lưu trữ khi thiết bị khởi động lần đầu tiên. Nó được thiết lập lại khi thiết bị bị xóa.

ANDROID_IDcó vẻ là một lựa chọn tốt cho một định danh thiết bị duy nhất. Có một số nhược điểm: Thứ nhất, nó không đáng tin cậy 100% đối với các bản phát hành Android trước 2.2 (“Froyo”).Ngoài ra, đã có ít nhất một lỗi được quan sát rộng rãi trong một chiếc điện thoại phổ biến từ một nhà sản xuất lớn, trong đó mọi phiên bản đều có cùng ANDROID_ID.


1
câu trả lời này là một bản sao từ blog cũ của google android-developers.googleblog.com/2011/03/ . Vậy lỗi đã được giải quyết chưa?
Sergii


6

ID cá thể Google

Phát hành tại I / O 2015; trên Android yêu cầu dịch vụ chơi 7.5.

https://developers.google.com/instance-id/
https://developers.google.com/instance-id/guides/android-im THỰCation

InstanceID iid = InstanceID.getInstance( context );   // Google docs are wrong - this requires context
String id = iid.getId();  // blocking call

Có vẻ như Google dự định ID này sẽ được sử dụng để xác định các cài đặt trên Android, Chrome và iOS.

Nó xác định cài đặt thay vì thiết bị, nhưng sau đó, ANDROID_ID (là câu trả lời được chấp nhận) giờ đây cũng không còn nhận dạng thiết bị nữa. Với thời gian chạy ARC, ANDROID_ID mới được tạo cho mọi cài đặt ( chi tiết tại đây ), giống như ID cá thể mới này. Ngoài ra, tôi nghĩ rằng việc xác định cài đặt (không phải thiết bị) là điều mà hầu hết chúng ta đang thực sự tìm kiếm.

Ưu điểm của ID cá thể

Tôi thấy rằng Google dự định sẽ sử dụng nó cho mục đích này (xác định cài đặt của bạn), nó là nền tảng chéo và có thể được sử dụng cho một số mục đích khác (xem các liên kết ở trên).

Nếu bạn sử dụng GCM, thì cuối cùng bạn sẽ cần sử dụng ID cá thể này vì bạn cần nó để nhận mã thông báo GCM (thay thế ID đăng ký GCM cũ).

Những nhược điểm / vấn đề

Trong triển khai hiện tại (GPS 7.5), ID cá thể được lấy từ máy chủ khi ứng dụng của bạn yêu cầu. Điều này có nghĩa là cuộc gọi ở trên là cuộc gọi chặn - trong thử nghiệm không khoa học của tôi, sẽ mất 1-3 giây nếu thiết bị trực tuyến và 0,5 - 1,0 giây nếu ngoại tuyến (có lẽ đây là khoảng thời gian chờ đợi trước khi từ bỏ và tạo ra ID ngẫu nhiên). Điều này đã được thử nghiệm ở Bắc Mỹ trên Nexus 5 với Android 5.1.1 và GPS 7.5.

Nếu bạn sử dụng ID cho các mục đích họ dự định - ví dụ. xác thực ứng dụng, nhận dạng ứng dụng, GCM - Tôi nghĩ rằng 1-3 giây này có thể gây phiền toái (tất nhiên phụ thuộc vào ứng dụng của bạn).


1
một nhược điểm đáng kể khác của instanceID là một instanceID mới sẽ được tạo cho bạn nếu người dùng xóa dữ liệu của ứng dụng.
idanakav 8/07/2015

Thú vị, nhưng tôi không nghĩ nó thực sự thay đổi các trường hợp sử dụng tiềm năng: ID cá thể, như android_id, không phù hợp để nhận dạng thiết bị. Vì vậy, máy chủ của bạn sẽ thấy người dùng xóa dữ liệu giống như người dùng gỡ cài đặt và cài đặt lại ứng dụng của bạn - điều này không hợp lý.
Tom
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.