Các thiết bị Android có ID duy nhất không và nếu có, cách đơn giản để truy cập nó bằng Java là gì?
Các thiết bị Android có ID duy nhất không và nếu có, cách đơn giản để truy cập nó bằng Java là gì?
Câu trả lời:
Settings.Secure#ANDROID_ID
trả 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);
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):
TelephonyManager.getDeviceId()
TelephonyManager.getSimSerialNumber()
getSimSerialNumber()
(như mong đợi)ANDROID_ID
ANDROID_ID
và TelephonyManager.getDeviceId()
- miễn là tài khoản Google đã được thêm trong quá trình thiết lập.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 TelephonyManager
thuộ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;
<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ự.
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ể.
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).
Email người dùng - Phần mềm
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
trở lên<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
<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
)
<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)
Địa chỉ MAC WLAN - Phần cứng (nhu cầu android.permission.ACCESS_WIFI_STATE
)
<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
)
<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)
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ự.
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!
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 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:
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();
}
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
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 ().
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!
Build
lớ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)
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:
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;
}
}
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 đó :).
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_STATE
trong 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
android.permission.ACCESS_WIFI_STATE
02:00:00:00:00:00
Có thông tin khá hữu ích ở đây .
Nó bao gồm năm loại ID khác nhau:
android.permission.READ_PHONE_STATE
)android.permission.ACCESS_WIFI_STATE
)android.permission.BLUETOOTH
)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 .
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.
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 .)
Đ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) {
}
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ị.
ANDROID_ID
được bắt nguồn từ nó.
android.os.Build.SERIAL
android.os.Build.SERIAL
sẽ hết hạn vào Android O, xem android-developers.googleblog.com/2017/04/...
Đó 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 FirebaseInstanceId
thê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ự.
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);
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.
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.
9774d56d682e549c
?
Để 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();
}
}
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" />
TelephonyManager
và ANDROID_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 .
Có rất nhiều cách tiếp cận khác nhau để giải quyết các ANDROID_ID
vấ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:
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_ID
dự phòng cho những vấn đề được đề cập ở trên.
Làm thế nào về IMEI . Đó là duy nhất cho Android hoặc các thiết bị di động khác.
Đâ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;
}
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 đây và tạ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);
}
}
}
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 longId
chuỗ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 "";
}
longId
và 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();
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.
Một cách khác là sử dụng /sys/class/android_usb/android0/iSerial
trong 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:
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.
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;
}
Để 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.
Tôi sử dụng đoạn mã sau để lấy IMEI
hoặc sử dụng Secure. ANDROID_ID
thay 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);
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_ID
có 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.
Để hiểu Id duy nhất có sẵn trong thiết bị Android. Sử dụng hướng dẫn chính thức này.
Thực tiễn tốt nhất cho các định danh duy nhất:
IMEI, Địa chỉ Mac, Id Instance, GUID, SSAID, Id quảng cáo, API mạng an toàn để xác minh thiết bị.
https://developer.android.com/training/articles/user-data-ids
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).
ANDROID_ID
hãy chắc chắn đọc câu trả lời này và lỗi này .