จะค้นหาหมายเลขประจำเครื่องของอุปกรณ์ Android ได้อย่างไร?


115

ฉันจำเป็นต้องใช้ ID เฉพาะสำหรับแอป Android และฉันคิดว่าหมายเลขซีเรียลของอุปกรณ์นั้นเป็นตัวเลือกที่ดี ฉันจะดึงหมายเลขประจำเครื่องของอุปกรณ์ Android ในแอปของฉันได้อย่างไร?


2
อย่าลืมเพิ่ม android: name = "android.permission.READ_PHONE_STATE" ในรายการของคุณ
Michael SIlveus


หากคุณต้องการที่จะได้รับบัตรประจำตัวที่ไม่ซ้ำกันโดยไม่ต้องสิทธิ์ใด ๆ คุณอาจจะใช้ห้องสมุดนี้เพื่อสร้างทั้ง ID ไม่ซ้ำกันต่ออุปกรณ์ที่มีIdentity.getDeviceId (บริบท)หรือตัวระบุสำหรับการติดตั้งแอปของคุณผ่านทางIdentity.getInstallationId (บริบท)
caw

คำตอบ:


105
TelephonyManager tManager = (TelephonyManager)myActivity.getSystemService(Context.TELEPHONY_SERVICE);
String uid = tManager.getDeviceId();

getSystemService เป็นวิธีการจากคลาสกิจกรรม getDeviceID () จะส่งคืน MDN หรือ MEID ของอุปกรณ์ขึ้นอยู่กับวิทยุที่โทรศัพท์ใช้ (GSM หรือ CDMA)

อุปกรณ์แต่ละเครื่องต้องส่งคืนค่าที่ไม่ซ้ำกันที่นี่ (สมมติว่าเป็นโทรศัพท์) สิ่งนี้ควรใช้กับอุปกรณ์ Android ที่มีช่องเสียบซิมหรือวิทยุ CDMA คุณเป็นเจ้าของด้วยไมโครเวฟที่ขับเคลื่อนด้วย Android ;-)


@Hasemam สิ่งนี้ใช้ไม่ได้สำหรับฉันทำให้เกิดข้อผิดพลาด "Force Close"
Paresh Mayani

23
@Hasemam ทำงานได้ดีในขณะนี้หลังจากเพิ่มสิทธิ์ <use-permission android: name = "android.permission.READ_PHONE_STATE"> </uses-permission> ในไฟล์ androidManifest.xml
Paresh Mayani

23
มีคำแนะนำในบล็อกของนักพัฒนา Android อย่างเป็นทางการเกี่ยวกับการใช้ตัวระบุนี้: android-developers.blogspot.com/2011/03/…
David Snabel-Caunt

8
นอกเหนือจากไมโครเวฟที่ขับเคลื่อนด้วย Android แล้วแท็บเล็ตที่ขับเคลื่อนด้วย Android ล่ะ? :)
ajacian81

21
ควรหลีกเลี่ยงวิธีนี้ซึ่งจะใช้ได้กับโทรศัพท์ แต่จะใช้ไม่ได้กับอุปกรณ์ที่ไม่มีชิปโทรศัพท์ (แท็บเล็ตเป็นตัวอย่างเดียว) จาก 2.3 คุณสามารถใช้ android.os.Build.SERIAL ได้ แต่ลองดูบล็อกนักพัฒนาที่ @DavidCaunt แนะนำ
John Mitchell

71

ดังที่ Dave Webb กล่าวถึงบล็อกของนักพัฒนาซอฟต์แวร์ Android มีบทความที่กล่าวถึงเรื่องนี้

ฉันได้พูดคุยกับใครบางคนที่ Google เพื่อขอคำชี้แจงเพิ่มเติมเกี่ยวกับบางรายการ นี่คือสิ่งที่ฉันค้นพบที่ไม่ได้กล่าวถึงในบล็อกโพสต์ข้างต้น:

  • ANDROID_ID เป็นโซลูชันที่ต้องการ ANDROID_ID เชื่อถือได้อย่างสมบูรณ์บน Android เวอร์ชัน <= 2.1 หรือ> = 2.3 เพียง 2.2 มีปัญหาที่กล่าวถึงในโพสต์
  • อุปกรณ์จำนวนมากจากผู้ผลิตหลายรายได้รับผลกระทบจากข้อบกพร่อง ANDROID_ID ใน 2.2
  • เท่าที่ผมได้รับสามารถที่จะตรวจสอบอุปกรณ์ได้รับผลกระทบทุกคนมีANDROID_ID เดียวกันซึ่งเป็น9774d56d682e549c ซึ่งเป็นรหัสอุปกรณ์เดียวกับที่โปรแกรมจำลองรายงานด้วย btw
  • Google เชื่อว่า OEM ได้แก้ไขปัญหาสำหรับอุปกรณ์จำนวนมากหรือเกือบทั้งหมด แต่ฉันสามารถตรวจสอบได้ว่าเมื่อต้นเดือนเมษายน 2011 อย่างน้อยก็ยังหาอุปกรณ์ที่มี ANDROID_ID เสียได้ค่อนข้างง่าย

ตามคำแนะนำของ Google ฉันใช้คลาสที่จะสร้าง UUID ที่ไม่ซ้ำกันสำหรับแต่ละอุปกรณ์โดยใช้ ANDROID_ID เป็นเมล็ดพันธุ์ตามความเหมาะสมโดยถอยกลับไปที่ TelephonyManager.getDeviceId () ตามความจำเป็นและหากล้มเหลวให้ใช้ UUID เฉพาะที่สร้างขึ้นแบบสุ่ม ที่ยังคงอยู่ระหว่างการรีสตาร์ทแอป (แต่ไม่ใช่การติดตั้งแอปซ้ำ)

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

1
แอปต้องมีสิทธิ์ใดบ้างในการใช้สิ่งนี้
Dave L.

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

1
@ ef2011 เป็นรูปแบบการล็อกที่ตรวจสอบซ้ำแล้ว: en.wikipedia.org/wiki/Double-checked_locking
emmby

3
ขอบคุณสำหรับการโพสต์ แต่จะหยุดคนที่มีโทรศัพท์ที่รูทไม่ได้เพียงแค่แก้ไข device_id.xml เพื่อใส่ UUID ใหม่ที่พวกเขาเลือก? (กล่าวคือเพื่อหลีกเลี่ยงการตรวจสอบ 'การทดลองใช้ฟรี') จะดีกว่าไหมหากคลาสเก็บค่าไว้ในไฟล์ค่ากำหนดเท่านั้นหากต้องใช้วิธีสุ่ม ID มิฉะนั้นไม่จำเป็นต้องคงอยู่ระหว่างการเรียกใช้แอปพลิเคชัน ปลอดภัยกว่าที่จะสร้างใหม่
Carlos P

1
"ANDROID_ID" เป็นโซลูชันที่ต้องการ "โปรดทราบว่า ANDROID_ID ไม่ได้ระบุอุปกรณ์ที่ไม่ซ้ำกันอีกต่อไป: stackoverflow.com/a/13465373/150016
ทอม

32
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) {
}

รหัสนี้ส่งคืนหมายเลขซีเรียลของอุปกรณ์โดยใช้ Android API ที่ซ่อนอยู่


7
สิ่งนี้ทำให้ฉันได้รับค่าเดียวกับที่ฉันได้รับจาก android.os.Build.SERIAL
josephus

ฉันเข้าใจผิดหรือหมายเลขซีเรียลนี้เหมือนกันในทุกอุปกรณ์ที่มี ROM ที่กำหนดเองโดยเฉพาะ หมายเลขซีเรียลอุปกรณ์ของฉัน (ในตัวเรียกใช้อุปกรณ์ eclipse) แสดง 01234567890ABC สำหรับโทรศัพท์ที่มี ROM ที่กำหนดเอง
Peterdk

@Peterdk บนอุปกรณ์ของฉันด้วย cyanogen-9 ทั้งสองวิธี (ก่อนและ -9 เหมือนในคำตอบและวิธีที่ง่ายกว่าจาก andy-9 บน) รายงาน s / n ที่ถูกต้อง (เช่นเดียวกับสติกเกอร์ของผู้ผลิต) อาจขึ้นอยู่กับเวอร์ชันรอมที่กำหนดเองโดยเฉพาะ คุณใช้ rom / version อะไร?
morgwai

16
String deviceId = Settings.System.getString(getContentResolver(),
                                Settings.System.ANDROID_ID);

แม้ว่าจะไม่รับประกันว่า Android ID จะเป็นตัวระบุที่ไม่ซ้ำกัน


@ Paresh Mayani เป็นการยากที่จะบอกว่าอะไรเป็นปัญหาโดยไม่ต้องดูรหัส สมมติฐานเท่านั้นฉันว่าจะกลับมาgetContentResolver nullอย่างไรก็ตามอาจคุ้มค่าในขณะที่เปิดคำถามและโพสต์รหัสของคุณ
Anthony Forloney

4
รหัสนี้มาจากบัญชี Google ที่เชื่อมโยงกับโทรศัพท์ โดยทั่วไปเครื่องจำลองจะไม่มี โทรศัพท์จริงอาจไม่มีเช่นกัน นอกจากนี้ยังมีการบันทึกว่า "สามารถเปลี่ยนแปลงได้เมื่อรีเซ็ตเป็นค่าเริ่มต้นจากโรงงาน" และสามารถเปลี่ยนแปลงได้ทุกเมื่อบนโทรศัพท์ที่รูท ใช้ด้วยความเสี่ยงของคุณเอง ไม่มีทางเลือกอื่นที่ดี - รหัสอุปกรณ์เบื้องต้นอื่น ๆ อาจไม่มีให้ใช้งานทั่วไปหรือไม่ซ้ำกันหรือทั้งสองอย่าง ดูคำตอบอื่น ๆ สำหรับเรื่องราวที่น่าเศร้านี้
Seva Alekseyev

14

นอกจากนี้โพสต์ที่ยอดเยี่ยมในบล็อกของนักพัฒนาของ Android การอภิปรายนี้

ขอแนะนำให้ใช้TelephonyManager.getDeviceId()ไม่ได้กับอุปกรณ์ Android ที่ไม่ใช่โทรศัพท์เช่นแท็บเล็ตต้องREAD_PHONE_STATEได้รับอนุญาตและใช้งานไม่ได้กับโทรศัพท์ทุกรุ่น

คุณสามารถใช้สิ่งใดสิ่งหนึ่งต่อไปนี้แทน:

  • หมายเลขทางกายภาพ
  • หมายเลขซีเรียล
  • ANDROID_ID

โพสต์กล่าวถึงข้อดีข้อเสียของแต่ละข้อและควรค่าแก่การอ่านเพื่อให้คุณสามารถหาวิธีที่ดีที่สุดสำหรับการใช้งานของคุณ


+1 สวัสดี dave ขอบคุณสำหรับคำชี้แจงเนื่องจากตอนนี้ฉันกำลังพัฒนาแอปพลิเคชันสำหรับแท็บเล็ตซึ่งฉันต้องมีรหัสเฉพาะของอุปกรณ์ Android ดังนั้นฉันควรใช้อะไรเพื่อรับอุปกรณ์แท็บเล็ต Android ที่ไม่ซ้ำใคร
Paresh Mayani

12

สำหรับหมายเลขที่เรียบง่ายที่เป็นเอกลักษณ์ของอุปกรณ์และคงที่สำหรับอายุการใช้งาน (ยกเว้นตั้งโรงงานหรือแฮ็ค) ใช้Settings.Secure.ANDROID_ID

String id = Secure.getString(getContentResolver(), Secure.ANDROID_ID);

ในการใช้หมายเลขซีเรียลของอุปกรณ์ (หมายเลขที่แสดงใน "การตั้งค่าระบบ / เกี่ยวกับ / สถานะ") หากมีและกลับไปใช้ Android ID:

String serialNumber = Build.SERIAL != Build.UNKNOWN ? Build.SERIAL : Secure.getString(getContentResolver(), Secure.ANDROID_ID);

ตอบตรงๆ !!
faris faris

Build.SERİALเลิกใช้งานใน java
EyyüpAlkış

7

IMEI นั้นดี แต่ใช้งานได้กับอุปกรณ์ Android กับโทรศัพท์เท่านั้น คุณควรพิจารณาการสนับสนุนแท็บเล็ตหรืออุปกรณ์ Android อื่น ๆ ด้วยเช่นกันที่ไม่มีโทรศัพท์

คุณมีทางเลือกอื่นเช่น: สร้างสมาชิกชั้นเรียน BT MAC, WLAN MAC หรือดีกว่า - การรวมกันของสิ่งเหล่านี้

ฉันได้อธิบายรายละเอียดเหล่านี้ในบทความในบล็อกของฉันโปรดดู: http://www.pocketmagic.net/?p=1662


6

เนื่องจากไม่มีคำตอบที่นี่กล่าวถึง ID ที่สมบูรณ์แบบและป้องกันการล้มเหลวซึ่งมีทั้ง PERSISTENT ผ่านการอัปเดตระบบและมีอยู่ในอุปกรณ์ทั้งหมด (สาเหตุหลักมาจากข้อเท็จจริงที่ว่าไม่มีโซลูชันส่วนบุคคลจาก Google) ฉันจึงตัดสินใจโพสต์วิธีการที่เป็น สิ่งที่ดีที่สุดถัดไปโดยการรวมตัวระบุที่มีอยู่สองตัวเข้าด้วยกันและตรวจสอบเพื่อเลือกระหว่างตัวบ่งชี้ที่ทำงาน

ก่อนรหัส 3 ข้อเท็จจริง:

  1. TelephonyManager.getDeviceId()(akaIMEI) จะทำงานได้ไม่ดีหรือเลยสำหรับอุปกรณ์ที่ไม่ใช่ GSM, 3G, LTE และอื่น ๆ แต่จะส่งคืน ID ที่ไม่ซ้ำกันเสมอเมื่อมีฮาร์ดแวร์ที่เกี่ยวข้องแม้ว่าจะไม่มีการใส่ซิมหรือแม้ว่าจะไม่มีช่องใส่ซิมก็ตาม ( OEM บางรายได้ทำสิ่งนี้แล้ว)

  2. เนื่องจาก Gingerbread (Android 2.3) android.os.Build.SERIAL ต้องมีอยู่ในอุปกรณ์ใด ๆ ที่ไม่มี IMEIกล่าวคือไม่มีฮาร์ดแวร์ดังกล่าวข้างต้นตามนโยบายของ Android

  3. เนื่องจากข้อเท็จจริง (2. ) จะมีตัวระบุที่ไม่ซ้ำกันอย่างน้อยหนึ่งในสองตัวนี้อยู่เสมอและ SERIAL สามารถแสดงพร้อมกันกับ IMEI ได้

หมายเหตุ: ข้อเท็จจริง (1. ) และ (2. ) อ้างอิงจากแถลงการณ์ของ Google

สารละลาย

ด้วยข้อเท็จจริงข้างต้นเราสามารถมีตัวระบุที่ไม่ซ้ำกันได้โดยการตรวจสอบว่ามีฮาร์ดแวร์ที่ผูกกับ IMEI หรือไม่และถอยกลับไปที่ SERIAL เมื่อไม่เป็นเช่นนั้นเนื่องจากไม่สามารถตรวจสอบได้ว่า SERIAL ที่มีอยู่นั้นถูกต้องหรือไม่ คลาสคงที่ต่อไปนี้นำเสนอ 2 วิธีในการตรวจสอบสถานะดังกล่าวและใช้ IMEI หรือ SERIAL:

import java.lang.reflect.Method;

import android.content.Context;
import android.content.pm.PackageManager;
import android.os.Build;
import android.provider.Settings;
import android.telephony.TelephonyManager;
import android.util.Log;

public class IDManagement {

    public static String getCleartextID_SIMCHECK (Context mContext){
        String ret = "";

        TelephonyManager telMgr = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);

        if(isSIMAvailable(mContext,telMgr)){
            Log.i("DEVICE UNIQUE IDENTIFIER",telMgr.getDeviceId());
            return telMgr.getDeviceId();

        }
        else{
            Log.i("DEVICE UNIQUE IDENTIFIER", Settings.Secure.ANDROID_ID);

//          return Settings.Secure.ANDROID_ID;
            return android.os.Build.SERIAL;
        }
    }


    public static String getCleartextID_HARDCHECK (Context mContext){
        String ret = "";

        TelephonyManager telMgr = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
        if(telMgr != null && hasTelephony(mContext)){           
            Log.i("DEVICE UNIQUE IDENTIFIER",telMgr.getDeviceId() + "");

            return telMgr.getDeviceId();    
        }
        else{
            Log.i("DEVICE UNIQUE IDENTIFIER", Settings.Secure.ANDROID_ID);

//          return Settings.Secure.ANDROID_ID;
            return android.os.Build.SERIAL;
        }
    }


    public static boolean isSIMAvailable(Context mContext, 
            TelephonyManager telMgr){

        int simState = telMgr.getSimState();

        switch (simState) {
        case TelephonyManager.SIM_STATE_ABSENT:
            return false;
        case TelephonyManager.SIM_STATE_NETWORK_LOCKED:
            return false;
        case TelephonyManager.SIM_STATE_PIN_REQUIRED:
            return false;
        case TelephonyManager.SIM_STATE_PUK_REQUIRED:
            return false;
        case TelephonyManager.SIM_STATE_READY:
            return true;
        case TelephonyManager.SIM_STATE_UNKNOWN:
            return false;
        default:
            return false;
        }
    }

    static public boolean hasTelephony(Context mContext)
    {
        TelephonyManager tm = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
        if (tm == null)
            return false;

        //devices below are phones only
        if (Build.VERSION.SDK_INT < 5)
            return true;

        PackageManager pm = mContext.getPackageManager();

        if (pm == null)
            return false;

        boolean retval = false;
        try
        {
            Class<?> [] parameters = new Class[1];
            parameters[0] = String.class;
            Method method = pm.getClass().getMethod("hasSystemFeature", parameters);
            Object [] parm = new Object[1];
            parm[0] = "android.hardware.telephony";
            Object retValue = method.invoke(pm, parm);
            if (retValue instanceof Boolean)
                retval = ((Boolean) retValue).booleanValue();
            else
                retval = false;
        }
        catch (Exception e)
        {
            retval = false;
        }

        return retval;
    }


}

getCleartextID_HARDCHECKฉันจะให้คำแนะนำเกี่ยวกับการใช้ หากภาพสะท้อนไม่ติดในสภาพแวดล้อมของคุณให้ใช้getCleartextID_SIMCHECKวิธีนี้แทน แต่ควรพิจารณาว่าควรปรับให้เข้ากับความต้องการในการแสดงซิมของคุณโดยเฉพาะ

PS : โปรดทราบว่า OEM ได้จัดการข้อผิดพลาด SERIAL ที่ขัดต่อนโยบายของ Google (อุปกรณ์หลายเครื่องที่มี SERIAL เดียวกัน) และ Google ตามที่ระบุไว้มีกรณีที่ทราบอย่างน้อยหนึ่งกรณีใน OEM รายใหญ่ (ไม่เปิดเผยและฉันไม่รู้ว่าแบรนด์ใด เป็นอย่างใดอย่างหนึ่งฉันคาดเดา Samsung)

คำเตือน : สิ่งนี้ตอบคำถามเดิมเกี่ยวกับการรับ ID อุปกรณ์ที่ไม่ซ้ำใคร แต่ OP นำเสนอความคลุมเครือโดยระบุว่าเขาต้องการ ID เฉพาะสำหรับแอป แม้ว่าในสถานการณ์เช่นนี้ Android_ID จะดีกว่า แต่ก็จะไม่ทำงานในภายหลังกล่าวคือ Titanium Backup ของแอปผ่านการติดตั้ง ROM ที่แตกต่างกัน 2 แบบ (อาจเป็น ROM เดียวกันก็ได้) วิธีแก้ปัญหาของฉันรักษาความคงอยู่ที่ไม่ขึ้นกับแฟลชหรือการรีเซ็ตเป็นค่าเริ่มต้นจากโรงงานและจะล้มเหลวก็ต่อเมื่อเกิดการปลอมแปลง IMEI หรือ SERIAL ผ่านการแฮ็ก / ตัวดัดแปลงฮาร์ดแวร์


5

มีปัญหากับวิธีการข้างต้นทั้งหมด ที่ Google i / o Reto Meier ได้เปิดตัวคำตอบที่ชัดเจนเกี่ยวกับวิธีการเข้าถึงสิ่งนี้ซึ่งตรงกับความต้องการของนักพัฒนาส่วนใหญ่ในการติดตามผู้ใช้ระหว่างการติดตั้ง

วิธีนี้จะให้ ID ผู้ใช้ที่ไม่ระบุตัวตนและปลอดภัยซึ่งจะคงอยู่สำหรับผู้ใช้ในอุปกรณ์ต่างๆ (รวมถึงแท็บเล็ตตามบัญชี Google หลัก) และทุกการติดตั้งบนอุปกรณ์เดียวกัน แนวทางพื้นฐานคือการสร้าง ID ผู้ใช้แบบสุ่มและเก็บไว้ในการตั้งค่าที่แชร์ของแอพ จากนั้นคุณใช้ตัวแทนสำรองข้อมูลของ Google เพื่อจัดเก็บค่ากำหนดที่ใช้ร่วมกันที่เชื่อมโยงกับบัญชี Google ในระบบคลาวด์

มาดูวิธีการแบบเต็ม ก่อนอื่นเราต้องสร้างข้อมูลสำรองสำหรับ SharedPreferences โดยใช้ Android Backup Service เริ่มต้นด้วยการลงทะเบียนแอปของคุณผ่านลิงค์นี้: http://developer.android.com/google/backup/signup.html

Google จะให้คีย์บริการสำรองซึ่งคุณต้องเพิ่มลงในไฟล์ Manifest คุณต้องแจ้งให้แอปพลิเคชันใช้ BackupAgent ดังนี้:

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

จากนั้นคุณจะต้องสร้างเอเจนต์สำรองและบอกให้ใช้ตัวแทนผู้ช่วยเหลือสำหรับ sharedpreferences:

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

ในการสำรองข้อมูลให้เสร็จสมบูรณ์คุณต้องสร้างอินสแตนซ์ของ BackupManager ในกิจกรรมหลักของคุณ:

BackupManager backupManager = new BackupManager(context);

สุดท้ายสร้าง ID ผู้ใช้หากยังไม่มีและเก็บไว้ใน 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 นี้จะคงอยู่ตลอดการติดตั้งแม้ว่าผู้ใช้จะเปลี่ยนอุปกรณ์ก็ตาม

สำหรับข้อมูลเพิ่มเติมเกี่ยวกับแนวทางนี้โปรดดูคำพูดของ Reto ที่นี่http://www.google.com/events/io/2011/sessions/android-protips-advanced-topics-for-expert-android-app-developers.html

และสำหรับรายละเอียดทั้งหมดเกี่ยวกับวิธีการใช้งานตัวแทนสำรองโปรดดูที่เว็บไซต์สำหรับนักพัฒนาที่นี่: http://developer.android.com/guide/topics/data/backup.html โดยเฉพาะฉันขอแนะนำส่วนที่ด้านล่างของการทดสอบเนื่องจากการสำรองข้อมูลทำ ไม่ได้เกิดขึ้นทันทีดังนั้นในการทดสอบคุณต้องบังคับให้สำรองข้อมูล


2

อีกวิธีหนึ่งคือใช้ / sys / class / android_usb / android0 / iSerial ในแอปโดยไม่มีสิทธิ์ใด ๆ

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

ในการทำสิ่งนี้ใน java เราเพียงแค่ใช้ FileInputStream เพื่อเปิดไฟล์ iSerial และอ่านอักขระ ตรวจสอบให้แน่ใจว่าคุณได้ห่อไว้ในตัวจัดการข้อยกเว้นเนื่องจากอุปกรณ์บางชนิดไม่มีไฟล์นี้

อย่างน้อยอุปกรณ์ต่อไปนี้เป็นที่รู้กันว่าไฟล์นี้สามารถอ่านได้ทั่วโลก:

  • Galaxy Nexus
  • Nexus S
  • Motorola Xoom 3g
  • โตชิบา AT300
  • HTC One V.
  • มินิ MK802
  • Samsung Galaxy S II

คุณยังสามารถดูโพสต์บล็อกของฉันได้ที่นี่: http://insitusec.blogspot.com/2013/01/leaking-android-hardware-serial-number.htmlซึ่งฉันจะพูดคุยเกี่ยวกับไฟล์อื่น ๆ ที่สามารถดูข้อมูลได้


ขอบคุณสำหรับการโพสต์คำตอบของคุณ! โปรดอ่านคำถามที่พบบ่อยเกี่ยวกับการส่งเสริมตนเองอย่างละเอียด โปรดทราบว่าคุณจำเป็นต้องโพสต์ข้อจำกัดความรับผิดชอบทุกครั้งที่คุณเชื่อมโยงไปยังไซต์ / ผลิตภัณฑ์ของคุณเอง
Andrew Barber

1

ดังที่ @haserman กล่าวว่า:

TelephonyManager tManager = (TelephonyManager)myActivity.getSystemService(Context.TELEPHONY_SERVICE);
String uid = tManager.getDeviceId();

แต่จำเป็นต้องมีการอนุญาตในไฟล์รายการ:

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

1

รหัสอุปกรณ์เฉพาะของอุปกรณ์ Android OS เป็นสตริง

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

แต่ฉันขอแนะนำวิธีนี้ที่แนะนำโดย Google ::

การระบุการติดตั้งแอป


1

Build.SERIALเป็นวิธีที่ง่ายที่สุดแม้ว่าจะไม่น่าเชื่อถือทั้งหมดเนื่องจากอาจเป็นค่าว่างเปล่าหรือบางครั้งก็ส่งคืนค่าที่แตกต่างกัน ( หลักฐาน 1 , หลักฐาน 2 ) มากกว่าที่คุณเห็นในการตั้งค่าอุปกรณ์ของคุณ

มีหลายวิธีที่จะได้รับตัวเลขที่ขึ้นอยู่กับผู้ผลิตและอุปกรณ์ Android ของรุ่นดังนั้นฉันตัดสินใจที่จะรวบรวมทุกวิธีการแก้ปัญหาที่เป็นไปได้ฉันจะได้พบในครั้งเดียวเค้า นี่คือเวอร์ชันที่เรียบง่าย:

public static String getSerialNumber() {
    String serialNumber;

    try {
        Class<?> c = Class.forName("android.os.SystemProperties");
        Method get = c.getMethod("get", String.class);

        serialNumber = (String) get.invoke(c, "gsm.sn1");
        if (serialNumber.equals(""))
            serialNumber = (String) get.invoke(c, "ril.serialnumber");
        if (serialNumber.equals(""))
            serialNumber = (String) get.invoke(c, "ro.serialno");
        if (serialNumber.equals(""))
            serialNumber = (String) get.invoke(c, "sys.serialnumber");
        if (serialNumber.equals(""))
            serialNumber = Build.SERIAL;

        // If none of the methods above worked
        if (serialNumber.equals(""))
            serialNumber = null;
    } catch (Exception e) {
        e.printStackTrace();
        serialNumber = null;
    }

    return serialNumber;
}

0

ฉันรู้ว่าคำถามนี้เก่า แต่สามารถทำได้ในโค้ดบรรทัดเดียว

String deviceID = Build.SERIAL;


AFAIK สิ่งนี้จะเปลี่ยนไปหลังจากอัปเดตระบบปฏิบัติการของอุปกรณ์เช่นจาก 4.4.2 เป็น 4.4.4 หรืออะไรก็ตาม
Den Drobiazko

-1

ฉันพบว่าคลาสตัวอย่างที่โพสต์โดย @emmby ด้านบนเป็นจุดเริ่มต้นที่ดี แต่มันก็มีข้อบกพร่องอยู่สองสามอย่างตามที่ผู้โพสต์อื่นกล่าวไว้ สิ่งสำคัญคือมันยังคง UUID ไปยังไฟล์ XML โดยไม่จำเป็นและหลังจากนั้นจะดึงข้อมูลจากไฟล์นี้เสมอ นี่เป็นการเปิดคลาสให้แฮ็คง่าย ๆ : ทุกคนที่มีโทรศัพท์ที่รูทสามารถแก้ไขไฟล์ XML เพื่อสร้าง UUID ใหม่ให้ตัวเองได้

ฉันได้อัปเดตโค้ดเพื่อให้ยังคงเป็น XML หากจำเป็นจริงๆเท่านั้น (เช่นเมื่อใช้ UUID ที่สร้างขึ้นแบบสุ่ม) และพิจารณาตรรกะอีกครั้งตามคำตอบของ @Brill Pappin:

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 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) || (androidId == null) ) {
                                final String deviceId = ((TelephonyManager) context.getSystemService( Context.TELEPHONY_SERVICE )).getDeviceId();

                                if (deviceId != null)
                                {
                                    uuid = UUID.nameUUIDFromBytes(deviceId.getBytes("utf8"));
                                }
                                else
                                {
                                    uuid = UUID.randomUUID();

                                    // Write the value out to the prefs file so it persists
                                    prefs.edit().putString(PREFS_DEVICE_ID, uuid.toString() ).commit();
                                }
                            }
                            else
                            {
                                uuid = UUID.nameUUIDFromBytes(androidId.getBytes("utf8"));
                            } 
                        } catch (UnsupportedEncodingException e) {
                            throw new RuntimeException(e);
                        }



                    }

                }
            }
        }

    }


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

การใส่รหัสลงในคำนำหน้าที่ใช้ร่วมกันจะทำให้เป้าหมายเดิมลดลงเพื่อให้ได้รหัสที่ไม่ซ้ำกันจริงๆ เช่นคุณหากคุณต้องการใช้รหัสนั้นเป็นกุญแจสำคัญสำหรับข้อ จำกัด บางประการคุณจะถูกเมาเมื่อผู้ใช้ที่มีทักษะรูทอุปกรณ์และสามารถเข้าถึงไฟล์การกำหนดลักษณะที่แชร์ของคุณได้ เนื้อหาอาจถูกคัดลอกซึ่งหมายความว่า ...
Eugene Wechsler

นอกจากนี้ยังมีข้อผิดพลาดอีกประการหนึ่งสำหรับคำตอบของ MB และของคุณหากคุณใช้ randomUUID เป็นรหัสอุปกรณ์และรหัสแอปจะใช้ได้กับอุปกรณ์ทั้งหมดในบอร์ดไม่ว่าจะเป็นโทรศัพท์หรือไม่หรือเป็นอุปกรณ์ google exp หรือไม่ก็ตาม
Fred Grott

-2

ใช่. เป็นหมายเลขซีเรียลฮาร์ดแวร์ของอุปกรณ์และไม่ซ้ำกัน ดังนั้นใน api ระดับ 2.3 ขึ้นไปคุณสามารถใช้android.os.Build.ANDROID_IDเพื่อรับมันได้ สำหรับด้านล่าง 2.3 API ใช้ระดับTelephonyManager.getDeviceID ()

คุณสามารถอ่านhttp://android-developers.blogspot.in/2011/03/identifying-app-installations.html

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.