Computer >> Hướng Dẫn Máy Tính >  >> Lập Trình >> Android

Lấy Device ID duy nhất (IMEI/Android ID) trong Android

Android hạn chế truy cập định danh phần cứng (IMEI, Serial) từ Android 10 (API 29) do quyền riêng tư. Cần hiểu rõ các identifier, quyền cần thiết, và phương án thay thế.

Các loại Device Identifier

IdentifierMô tảQuyềnAndroid 10+Đặc điểm
IMEI/MEIDSố định danh thiết bị di động (SIM slot)READ_PHONE_STATEChỉ system app / carrier appDuy nhất, không đổi, cần SIM
Serial NumberSố serial phần cứngREAD_PHONE_STATEChỉ system appDuy nhất, không đổi
Android ID (SSAID)ID ngẫu nhiên per app-signing-key + userKhông cầnĐược phép (scoped per app)Reset khi factory reset, khác nhau giữa app
Advertising ID (GAID)ID quảng cáo, user có thể resetKhông cần (Google Play Services)Được phépDùng cho ads/analytics, user opt-out
Instance ID / Firebase Installation IDID cài đặt app instanceKhông cầnĐược phépReset khi reinstall app
UUID tự sinhTạo random UUID, lưu SharedPreferencesKhông cầnĐược phépDuy nhất per install, dễ triển khai

Cách 1: Android ID (Khuyến nghị cho hầu hết trường hợp)

Không cần permission, hoạt động mọi phiên bản Android.

import android.provider.Settings.Secure;

public String getAndroidId(Context context) {
    return Secure.getString(context.getContentResolver(), Secure.ANDROID_ID);
}

// Kết quả: "a1b2c3d4e5f6g7h8" (hex string 64-bit)
// Lưu ý: Trên emulator có thể trả về null hoặc giá trị cố định

Cách 2: UUID tự sinh (Best practice cho tracking user/install)

import android.content.Context;
import android.content.SharedPreferences;
import java.util.UUID;

public class DeviceIdManager {
    private static final String PREFS_NAME = "device_id_prefs";
    private static final String KEY_DEVICE_ID = "device_id";
    private final SharedPreferences prefs;

    public DeviceIdManager(Context context) {
        prefs = context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE);
    }

    public String getDeviceId() {
        String deviceId = prefs.getString(KEY_DEVICE_ID, null);
        if (deviceId == null) {
            deviceId = UUID.randomUUID().toString();
            prefs.edit().putString(KEY_DEVICE_ID, deviceId).apply();
        }
        return deviceId;
    }
    
    public void resetDeviceId() {
        prefs.edit().remove(KEY_DEVICE_ID).apply();
    }
}

Cách 3: IMEI (Chỉ cho system/carrier app, Android < 10)

Deprecated/Restricted từ API 29. Chỉ để maintain legacy code.

// AndroidManifest.xml

 

// Java (Legacy)
TelephonyManager telephonyManager = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);

if (ActivityCompat.checkSelfPermission(this, Manifest.permission.READ_PHONE_STATE) 
    == PackageManager.PERMISSION_GRANTED) {
    
    // API 26+ (Oreo)
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        String imei = telephonyManager.getImei(); // Slot 1
        // String imei2 = telephonyManager.getImei(1); // Slot 2
    } else {
        // Deprecated
        String imei = telephonyManager.getDeviceId();
    }
}

Cách 4: Advertising ID (Google Play Services)

Dùng cho quảng cáo, analytics. Cần Google Play Services.

// build.gradle
implementation 'com.google.android.gms:play-services-ads-identifier:18.0.1'

// Java (Async - phải chạy background thread)
import com.google.android.gms.ads.identifier.AdvertisingIdClient;
import com.google.android.gms.common.GooglePlayServicesNotAvailableException;
import com.google.android.gms.common.GooglePlayServicesRepairableException;
import java.io.IOException;

public void fetchAdId(Context context) {
    new Thread(() -> {
        try {
            AdvertisingIdClient.Info adInfo = AdvertisingIdClient.getAdvertisingIdInfo(context);
            String adId = adInfo.getId();
            boolean limitAdTracking = adInfo.isLimitAdTrackingEnabled();
            // Gửi adId lên server/main thread
        } catch (GooglePlayServicesNotAvailableException | 
                 GooglePlayServicesRepairableException | IOException e) {
            e.printStackTrace();
        }
    }).start();
}

Cách 5: Firebase Installation ID (FID)

Dùng cho Firebase services, không cần permission.

// build.gradle
implementation 'com.google.firebase:firebase-installations:17.1.4'

// Java
FirebaseInstallations.getInstance().getId()
    .addOnSuccessListener(fid -> {
        // fid: "abc123..." - duy nhất cho app instance này
    })
    .addOnFailureListener(e -> { /* handle error */ });

So sánh & Khuyến nghị

Use CaseIdentifier khuyến nghịLý do
Analytics, tracking user behaviorFirebase Installation ID / UUID tự sinhKhông cần permission, ổn định per install
Licensing, anti-fraud, device bindingAndroid ID + UUID backupAndroid ID ổn định per app+user, UUID fallback
Advertising, marketingAdvertising ID (GAID)Tuân thủ policy, user có thể reset/opt-out
Banking, high-security (carrier partnership)IMEI (chỉ system app)Yêu cầu đặc quyền, không dùng cho app thông thường
Push notification targetingFCM Token / FIDTích hợp sẵn Firebase

Ví dụ tổng hợp: Lấy ID phù hợp nhất

public class DeviceIdentifier {
    public static String getBestDeviceId(Context context) {
        // 1. Thử Firebase Installation ID (nếu dùng Firebase)
        // 2. Fallback: UUID đã lưu
        // 3. Fallback: Android ID
        
        SharedPreferences prefs = context.getSharedPreferences("device_ids", Context.MODE_PRIVATE);
        String uuid = prefs.getString("uuid", null);
        
        if (uuid == null) {
            uuid = UUID.randomUUID().toString();
            prefs.edit().putString("uuid", uuid).apply();
        }
        return uuid;
    }
    
    public static String getAndroidId(Context context) {
        return Settings.Secure.getString(context.getContentResolver(), Settings.Secure.ANDROID_ID);
    }
}

Chạy ứng dụng (Demo IMEI - Legacy)

App demo cũ: Yêu cầu runtime permission READ_PHONE_STATE → User allow → Hiển thị IMEI (hoặc "Permission denied" trên Android 10+).

Lưu ý quan trọng

  • Không dùng IMEI/Serial cho app thông thường - Google Play sẽ reject từ API 29+
  • Android ID có thể reset khi factory reset, khác nhau giữa user/profile/work profile
  • UUID tự sinh mất khi clear data/uninstall - phù hợp cho "install ID"
  • Advertising ID cần Google Play Services, user có thể bật "Opt out of Ads Personalization"
  • Tuân thủ Best practices for unique identifiers