هل هناك معرّف فريد لجهاز Android؟




uniqueidentifier (20)

آخر تحديث: 6/2/15

بعد قراءة كل مشاركة حول Stack Overflow حول إنشاء معرف فريد ، مدونة مطوّري برامج Google ووثائق Android ، أشعر كما لو أن "Pseudo ID" هو أفضل خيار ممكن.

القضية الرئيسية: الأجهزة مقابل البرامج

المعدات

  • يمكن للمستخدمين تغيير أجهزتهم أو أجهزة Android اللوحية أو هواتفهم ، لذلك فإن المعرفات الفريدة المستندة إلى الأجهزة ليست أفكارًا جيدة لمستخدمي التتبع
  • لتتبع الأجهزة ، هذه فكرة رائعة

البرمجيات

  • يمكن للمستخدمين مسح / تغيير ROM الخاصة بهم إذا كانت متجذرة
  • يمكنك تعقب المستخدمين عبر الأنظمة الأساسية (iOS و Android و Windows وويب)
  • إن أفضل ما تريد تتبع المستخدم الفردي بموافقته هو ببساطة جعله يسجل الدخول (اجعل هذا سلسًا باستخدام OAuth)

الانهيار الشامل مع أندرويد

- ضمان التفرد (بما في ذلك الأجهزة ذات الجذور) لواجهة برمجة التطبيقات> = 9/10 (99.5٪ من أجهزة Android)

- لا أذونات إضافية

رمز Psuedo:

if API >= 9/10: (99.5% of devices)

return unique ID containing serial id (rooted devices may be different)

else

return unique ID of build information (may overlap data - API < 9)

بفضلstansult لنشر جميع خياراتنا (في هذا السؤال تجاوز المكدس).

قائمة الخيارات - أسباب / لماذا لا تستخدمها:

  • البريد الإلكتروني للمستخدم - البرامج

  • رقم هاتف المستخدم - البرامج

    • يمكن للمستخدمين تغيير أرقام الهواتف - من غير المحتمل للغاية
    • <uses-permission android:name="android.permission.READ_PHONE_STATE" />
  • IMEI - الأجهزة (الهواتف فقط ، تحتاج إلى android.permission.READ_PHONE_STATE )

    • يكره معظم المستخدمين حقيقة أنه يقول "المكالمات الهاتفية" في الإذن. بعض المستخدمين يقدمون تقييمات سيئة ، لأنهم يعتقدون أنك ببساطة سرقة معلوماتهم الشخصية ، عندما يكون كل ما تريد فعله هو تتبع عمليات تثبيت الجهاز. من الواضح أنك تقوم بجمع البيانات.
    • <uses-permission android:name="android.permission.READ_PHONE_STATE" />
  • معرف Android - يمكن أن تكون الأجهزة (فارغة ، يمكن تغييرها عند إعادة ضبط المصنع ، يمكن تغييرها على جهاز متجذر)

    • بما أنه يمكن أن يكون "فارغًا" ، يمكننا التحقق من "القيمة" وتغيير قيمتها ، ولكن هذا يعني أنها لن تكون فريدة من نوعها.
    • إذا كان لديك مستخدم لديه جهاز إعادة ضبط إعدادات المصنع ، فقد تكون القيمة قد تغيرت أو غيرت على الجهاز المتجذر ، لذلك قد تكون هناك إدخالات مكررة إذا كنت تتبع عمليات تثبيت المستخدم.
  • عنوان WLAN MAC - الأجهزة (يحتاج إلى android.permission.ACCESS_WIFI_STATE )

    • قد يكون هذا هو الخيار الثاني الأفضل ، ولكنك لا تزال تجمع وتعرّف معرفًا فريدًا يأتي مباشرةً من المستخدم. هذا واضح أنك تقوم بجمع البيانات.
    • <uses-permission android:name="android.permission.ACCESS_WIFI_STATE "/>
  • عنوان MAC الخاص بتقنية Bluetooth - الأجهزة (أجهزة مزودة بتقنية Bluetooth ، تحتاج إلى android.permission.BLUETOOTH )

    • لا تستخدم معظم التطبيقات في السوق البلوتوث ، ولذلك إذا كان تطبيقك لا يستخدم البلوتوث وكنت بذلك ، فقد يصبح المستخدم مشبوهًا.
    • <uses-permission android:name="android.permission.BLUETOOTH "/>
  • Pseudo-Unique ID - برنامج (لجميع أجهزة Android)

    • ممكن جدا ، قد يحتوي على الاصطدامات - انظر طريقي المنشورة أدناه!
    • يتيح لك هذا الحصول على معرف "فريد من نوعه" من المستخدم دون أخذ أي شيء خاص. يمكنك إنشاء معرف مجهول خاص بك من معلومات الجهاز.

أعلم أنه لا توجد طريقة "مثالية" للحصول على معرف فريد بدون استخدام الأذونات ؛ ومع ذلك ، فإننا في بعض الأحيان نحتاج فقط إلى تتبع تثبيت الجهاز. عندما يتعلق الأمر بإنشاء معرّف فريد ، يمكننا إنشاء "هوية فريدة زائفة" تستند فقط إلى المعلومات التي تقدمها لنا واجهة برمجة تطبيقات Android بدون استخدام أذونات إضافية. بهذه الطريقة ، يمكننا إظهار احترام المستخدم ومحاولة تقديم تجربة مستخدم جيدة أيضًا.

باستخدام معرّف زائف فريد من نوعه ، فإنك لا تتحدث إلا حقيقة أنه قد توجد نسخ مكررة استنادًا إلى حقيقة وجود أجهزة مشابهة. يمكنك تعديل الطريقة المجمعة لجعلها أكثر تميزًا ؛ ومع ذلك ، يحتاج بعض المطورين إلى تتبع عمليات التثبيت على الأجهزة وهذا سيؤدي إلى الأداء أو الخدعة استنادًا إلى الأجهزة المماثلة.

واجهة برمجة التطبيقات> = 9:

إذا كان جهاز Android الخاص به هو واجهة برمجة التطبيقات API 9 أو أكثر ، فسيضمن ذلك أن يكون فريدًا بسبب حقل "Build.SERIAL".

تذكر ، أنت تفقد من الناحية الفنية حوالي 0.5٪ من المستخدمين الذين لديهم API <9 . حتى تتمكن من التركيز على الباقي: هذا هو 99.5 ٪ من المستخدمين!

API <9:

إذا كان جهاز Android الخاص بالمستخدم أقل من API 9 ؛ نأمل أن يكونوا لم يعيدوا ضبط المصنع وسيتم الحفاظ على "Secure.ANDROID_ID" الخاصة بهم أو لا تكون "خالية". (راجع http://developer.android.com/about/dashboards/index.html )

إذا فشل كل شيء آخر:

إذا فشلت كل الأشياء الأخرى ، إذا كان المستخدم أقل من API 9 (أقل من Gingerbread) ، فقم بإعادة ضبط جهازه أو "Secure.ANDROID_ID" بإرجاع "null" ، ثم ببساطة سيتم إرجاع المعرف الذي تم إرجاعه فقط من معلومات جهاز Android الخاص به. هذا هو المكان الذي يمكن أن يحدث الاصطدامات.

التغييرات:

  • تمت إزالة "Android.SECURE_ID" نظرًا لعمليات إعادة تعيين إعدادات المصنع ، فقد يؤدي ذلك إلى تغيير القيمة
  • عدلت الرمز للتغيير على API
  • غيرت الزائفة

يرجى إلقاء نظرة على الطريقة أدناه:

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

جديد (للتطبيقات مع الإعلانات وخدمات Google Play):

من وحدة تحكم مطوري برامج Google Play:

اعتبارًا من 1 آب 2014 ، تتطلب سياسة برنامج مطوّري البرامج في Google Play من جميع التحميلات والتحديثات الجديدة للتطبيقات استخدام معرّف الإعلانات بدلاً من أي معرفات دائمة أخرى لأي أغراض إعلانية. أعرف أكثر

التنفيذ :

الإذن:

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

الشفرة:

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

المصدر / مستندات:

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

مهم:

من المفترض أن يحل معرّف الإعلانات محل الاستخدام الحالي للمعرفات الأخرى لأغراض الإعلانات (مثل استخدام ANDROID_ID في Settings.Secure) عند توفر خدمات Google Play. تتم الإشارة إلى الحالات التي لا تتوفر فيها خدمات Google Play بواسطة GooglePlayServicesNotAvailableException التي يتم طرحها عن طريق getAdvertisingIdInfo ().

تحذير ، يمكن للمستخدمين إعادة ضبط:

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

لقد حاولت الإشارة إلى كل رابط أخذته من المعلومات. إذا كنت في عداد المفقودين وتحتاج إلى إدراجها ، يرجى التعليق!

خدمات لاعب جوجل InstanceID

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

هل تمتلك أجهزة Android معرفًا فريدًا ، وإذا كان الأمر كذلك ، فما هي الطريقة البسيطة للوصول إليه باستخدام جافا؟


يتم الحصول على معرف الجهاز الفريد الخاص بجهاز نظام التشغيل Android كسلسلة ، باستخدام TelephonyManagerو ANDROID_ID، بواسطة:

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 ، راجع تحديد عمليات تثبيت التطبيقات .


إليك الشفرة التي استخدمها Reto Meier في عرض Google I / O هذا العام للحصول على معرف فريد للمستخدم:

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

إذا قمت بالاقتران مع إستراتيجية النسخ الاحتياطي لإرسال التفضيلات إلى السحابة (كما هو موضح في talk Reto ، يجب أن يكون لديك معرف يربط المستخدم ويستمر بالالتفاف بعد أن يتم مسح الجهاز ، أو حتى استبداله. أخطط لاستخدام هذا في التحليلات إلى الأمام (وبعبارة أخرى ، لم أفعل ذلك بعد البت :).



كما يذكر Dave Webb ، تحتوي مدونة مطوّري برامج Android على مقالة تغطي ذلك. يتمثل الحل المفضل لديهم في تتبع عمليات تثبيت التطبيق بدلاً من الأجهزة ، وسيعمل هذا بشكل جيد في معظم حالات الاستخدام. ستعرض لك مشاركة المدونة الشفرة اللازمة لإجراء ذلك ، وأوصيك بالتأكد من ذلك.

ومع ذلك ، تستمر مشاركة المدونة في مناقشة الحلول إذا كنت تحتاج إلى معرف الجهاز بدلاً من معرف تثبيت التطبيق. لقد تحدثت مع شخص ما في Google للحصول على بعض التوضيحات الإضافية حول بعض العناصر في حال احتجت إلى ذلك. إليك ما اكتشفته بشأن معرّفات الأجهزة غير المذكورة في مشاركة المدونة المذكورة أعلاه:

  • ANDROID_ID هو معرف الجهاز المفضل. يُعد ANDROID_ID موثوقًا تمامًا على إصدارات Android <= 2.1 أو> = 2.3. 2.2 فقط لديه المشاكل المذكورة في هذا المنصب.
  • تتأثر العديد من الأجهزة من قبل العديد من الشركات المصنعة من خلل ANDROID_ID في 2.2.
  • بقدر ما كنت قادراً على تحديد ، جميع الأجهزة المتأثرة لها نفس ANDROID_ID ، وهو 9774d56d682e549c . وهو أيضًا نفس معرف الجهاز الذي أبلغ عنه المحاكي ، راجع للشغل.
  • تعتقد Google أن شركات تصنيع المعدات الأصلية قامت بتصحيح المشكلة للعديد من أجهزتها أو معظمها ، لكنني تمكنت من التحقق من أنه بدءًا من بداية شهر نيسان 2011 ، على الأقل ، لا يزال من السهل العثور على الأجهزة التي بها ANDROID_ID مكسورة.

استنادًا إلى توصيات Google ، طبّقت فئة ستنشئ UUID فريدًا لكل جهاز ، وذلك باستخدام ANDROID_ID كبذور عند اللزوم ، مع الرجوع مرة أخرى إلى TelephonyManager.getDeviceId () حسب الضرورة ، وإذا فشل ذلك ، فانتقل إلى UUID فريد تم إنشاؤه عشوائيًا يستمر عبر إعادة تشغيل التطبيق (لكن ليس إعادة تثبيت التطبيق).

لاحظ أنه بالنسبة للأجهزة التي تحتاج إلى التراجع على معرّف الجهاز ، سيظل المعرف الفريد موجودًا عبر عمليات إعادة ضبط المصنع. هذا شيء يجب أن تدركه. إذا كنت بحاجة إلى التأكد من أن إعادة تعيين إعدادات المصنع ستعيد تعيين معرفك الفريد ، فيمكنك التفكير في الرجوع إلى الرمز التعريفي العشوائي العشوائي (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 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;
    }
}

هناك معلومات مفيدة إلى حد ما here .

يغطي خمسة أنواع معرّفات مختلفة:

  1. IMEI (فقط للأجهزة التي تعمل بنظام Android مع استخدام الهاتف ؛ يحتاج إلى android.permission.READ_PHONE_STATE )
  2. معرّف زائف فريد (لجميع أجهزة Android)
  3. معرف Android (يمكن أن يكون فارغًا ، ويمكن تغييره عند إعادة تعيين إعدادات المصنع ، ويمكن تعديله على الهاتف الجذر)
  4. سلسلة عنوان MAC لشبكة WLAN (تحتاج إلى android.permission.ACCESS_WIFI_STATE )
  5. سلسلة عنوان MAC BT (الأجهزة التي تحتوي على Bluetooth ، تحتاج إلى android.permission.BLUETOOTH )

TelephonyManger.getDeviceId () إرجاع معرف الجهاز الفريد ، على سبيل المثال ، IMEI لـ GSM و MEID أو ESN لهواتف CDMA.

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

لكنني أوصي باستخدام:

Settings.Secure.ANDROID_ID تقوم بإرجاع معرف Android كسلسلة عرافة 64 بت فريدة.

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

أحيانًا ، يُرجع الهاتف telephonyManger.getDeviceId () فارغًا ، لذا لضمان استخدام معرف فريد ، ستستخدم هذه الطريقة:

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

تحديث : اعتبارًا من الإصدارات الحديثة لنظام التشغيل Android ، تم حل العديد من المشكلات المتعلقة بـ ANDROID_ID ، وأعتقد أن هذا النهج لم يعد ضروريًا. يرجى إلقاء نظرة على إجابة أنتوني .

الإفصاح الكامل: استخدم تطبيقي النهج التالي في الأصل ولكنه لم يعد يستخدم هذا النهج ، ونستخدم الآن النهج الموضح في إدخال android-developers.blogspot.com/2011/03/… التي ترتبط بها إجابة emmby (وهي إنشاء UUID#randomUUID() .

هناك العديد من الإجابات على هذا السؤال ، ومعظمها سيعمل فقط "بعض" الوقت ، وللأسف هذا ليس جيدًا بما فيه الكفاية.

بناءً على اختباراتي للأجهزة (جميع الهواتف ، واحد منها على الأقل غير نشط):

  1. عرض جميع الأجهزة التي تم اختبارها قيمة لـ TelephonyManager.getDeviceId()
  2. جميع أجهزة GSM (جميعها تم اختبارها باستخدام بطاقة SIM) تقوم بإرجاع قيمة TelephonyManager.getSimSerialNumber()
  3. إرجاع كافة الأجهزة CDMA فارغة لـ getSimSerialNumber() (كما هو متوقع)
  4. عرضت جميع الأجهزة التي تتضمن حساب Google تمت إضافتها إلى ANDROID_ID
  5. عرضت جميع أجهزة CDMA نفس القيمة (أو اشتقاق القيمة نفسها) لكل من ANDROID_ID و TelephonyManager.getDeviceId() - طالما تمت إضافة حساب Google أثناء الإعداد.
  6. لم تتح لي بعد فرصة اختبار أجهزة GSM بدون بطاقة SIM أو جهاز GSM مع عدم إضافة حساب Google أو أي من الأجهزة في وضع الطائرة.

لذلك إذا كنت تريد شيئًا فريدًا للجهاز نفسه ، يجب أن يكون TM.getDeviceId() كافياً. من الواضح أن بعض المستخدمين أكثر جنونًا من الآخرين ، لذا قد يكون من المفيد تجزئة 1 أو أكثر من هذه المعرّفات ، بحيث لا تزال السلسلة فريدة من نوعها فعليًا للجهاز ، ولكنها لا تحدد الجهاز الفعلي للمستخدم صراحةً. على سبيل المثال ، باستخدام String.hashCode() ، جنبا إلى جنب مع 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();

قد يؤدي إلى شيء من هذا القبيل: 00000000-54b3-e7c7-0000-000046bffd97

وهو يعمل جيدا بما فيه الكفاية بالنسبة لي.

كما ذكر ريتشارد أدناه ، لا تنس أنك بحاجة إلى إذن لقراءة خصائص TelephonyManager ، لذلك أضف هذا إلى بيانك:

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

استيراد libs

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

أضف شفرة أدناه في ملف الفصل الدراسي:

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

أضف في AndroidManifest.xml:

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

أعتقد أن هذا هو بالتأكيد طريقة إطلاق النار لبناء هيكل عظمي لمعرف فريد ... تحقق من ذلك.

معرّف زائف فريد ، يعمل على جميع أجهزة Android لا تحتوي بعض الأجهزة على هاتف (على سبيل المثال ، أجهزة لوحية) أو لسبب ما ، فأنت لا تريد تضمين إذن READ_PHONE_STATE. لا يزال بإمكانك قراءة التفاصيل مثل إصدار ROM ، واسم الشركة المصنّعة ، ونوع وحدة المعالجة المركزية ، وتفاصيل الأجهزة الأخرى ، التي ستكون مناسبة تمامًا إذا كنت ترغب في استخدام المعرّف لإجراء فحص مفتاح تسلسلي ، أو لأغراض عامة أخرى. لن يكون المعرّف الذي يتم حسابه بهذه الطريقة فريداً من نوعه: فمن الممكن العثور على جهازين لهما نفس المعرف (على أساس نفس الجهاز وصورة ROM) ولكن التغييرات في التطبيقات في الواقع لا تكاد تذكر. لهذا الغرض ، يمكنك استخدام فئة البناء:

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

معظم أعضاء Build عبارة عن سلاسل ، ما نفعله هنا هو أخذ طولهم وتحويله عبر modulo في رقم. لدينا 13 رقما من هذا القبيل ، ونحن نضيف اثنين آخرين في الأمام (35) للحصول على نفس حجم ID IMEI (15 رقما). هناك احتمالات أخرى هنا جيدا ، مجرد إلقاء نظرة على هذه السلاسل. يعود شيء من هذا القبيل 355715565309247. مطلوب أي إذن خاص ، مما يجعل هذا النهج مناسب للغاية.

(معلومات إضافية: تم نسخ التقنية المذكورة أعلاه من مقالة في here .)


باستخدام الرمز أدناه ، يمكنك الحصول على معرف الجهاز الفريد لجهاز Android OS كسلسلة.

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

شيء واحد سأضيف - لدي واحدة من تلك الحالات الفريدة.

عن طريق:

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

تبين أنه على الرغم من أن جهاز Viewsonic G Tablet الخاص به قد أبلغ عن DeviceID غير خالية ، فإن كل جهاز G Tablet نفسه يقوم بالإبلاغ عن نفس الرقم.

يجعلها مثيرة للاهتمام لعب "Pocket Empires" التي تمنحك الوصول الفوري إلى حساب شخص ما استنادًا إلى DeviceID "الفريد".

لا يحتوي جهازي على راديو خلية.


معرف جهاز Android الخاص بجهاز Android أيضًا هو معرف فريد ، ولن يتغير افتراضًا إذا قمنا بتنسيق الجهاز نفسه باستخدام التعليمة البرمجية التالية للحصول على معرف mac

WifiManager manager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
WifiInfo info = manager.getConnectionInfo();
String address = info.getMacAddress();

لا تنس أيضًا إضافة الأذونات المناسبة إلى AndroidManifest.xml

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

بشكل أكثر تحديدا Settings.Secure.ANDROID_ID. هذه هي كمية 64 بت التي يتم إنشاؤها وتخزينها عند تشغيل الجهاز لأول مرة. تتم إعادة ضبطه عند مسح الجهاز.

ANDROID_IDيبدو اختيار جيد لمعرف جهاز فريد. هناك جوانب سلبية: أولاً ، إنها غير موثوقة بنسبة 100٪ في إصدارات Android قبل 2.2 (“Froyo”).، كما أن هناك علة واحدة على الأقل ملاحظتها على نطاق واسع في هاتف شائع من جهة تصنيع رئيسية ، حيث كل مثيل له نفس ANDROID_ID.


سنتي الثانية - ملاحظة: هذا مخصص لمعرف فريد لجهاز (يخطئ) - وليس تركيبة واحدة كما تمت مناقشتها في مدونة مطوري Android .

من ملاحظة أن solution المقدمة منemmby يرتد في في التطبيق ID لا تتم مزامنة SharedPreferences عبر العمليات (انظر here و here ). لذلك تجنبت هذا تماما.

بدلاً من ذلك ، قمت بتغليف الاستراتيجيات المختلفة للحصول على معرف (جهاز) في التعداد - تغيير ترتيب ثواب التعداد يؤثر على أولوية الطرق المختلفة للحصول على المعرف. يتم إرجاع أول معرف غير فارغ أو يتم طرح استثناء (وفقا لممارسات جافا جيدة لعدم إعطاء معنى فارغ). على سبيل المثال ، لدي جهاز TELEPHONY واحدًا أولاً - ولكن خيارًا افتراضيًا جيدًا سيكون ANROID_ID beta:

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

طريقة أخرى هي استخدام /sys/class/android_usb/android0/iSerialفي التطبيق دون أي أذونات على الإطلاق.

[email protected]:~$ adb shell ls -l /sys/class/android_usb/android0/iSerial
-rw-r--r-- root     root         4096 2013-01-10 21:08 iSerial
[email protected]:~$ adb shell cat /sys/class/android_usb/android0/iSerial
0A3CXXXXXXXXXX5

للقيام بذلك في Java ، يمكن استخدام FileInputStream فقط لفتح الملف iSerial وقراءة الأحرف. فقط تأكد من التفافه في معالج استثناء ، لأنه ليس كل الأجهزة لديها هذا الملف.

من المعروف أن الأجهزة التالية على الأقل تحتوي على هذا الملف القابل للقراءة في العالم:

  • Galaxy Nexus
  • Nexus S
  • موتورولا Xoom 3G
  • توشيبا AT300
  • HTC One V
  • ميني MK802
  • Samsung Galaxy S II

يمكنك أيضًا الاطلاع على مشاركة مدونتي بعنوان Leaking Android serial serial to apps unprivileged ، حيث ناقش ما هي الملفات الأخرى المتوفرة للمعلومات.


للحصول على إرشادات تفصيلية حول كيفية الحصول على معرف فريد لكل جهاز Android تم تثبيت تطبيقك منه ، اطلع على نشر مدونة مطوّري البرامج لنظام Android الرسمي android-developers.blogspot.com/2011/03/… .

يبدو أن أفضل طريقة هي أن تولد نفسك عند التثبيت ثم تقرأه عند إعادة تشغيل التطبيق.

أنا شخصيا أجد هذا مقبولا ولكن ليس مثاليا. لا يعمل أحد المعرفات التي يوفرها Android في جميع الحالات حيث يعتمد معظمها على حالات الراديو في الهاتف (تشغيل / إيقاف Wi-Fi ، تشغيل / إيقاف الهاتف الخلوي ، تشغيل / إيقاف البلوتوث). يجب على الآخرين ، مثل Settings.Secure.ANDROID_IDيجب تنفيذها من قبل الشركة المصنعة وغير مضمونة لتكون فريدة من نوعها.

فيما يلي مثال على كتابة البيانات إلى ملف التثبيت الذي سيتم تخزينه مع أي بيانات أخرى يحفظها التطبيق محليًا.

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

ماذا عن IMEI . هذا فريد للأندرويد أو أجهزة الجوال الأخرى.


هناك الكثير من الطرق المختلفة للتغلب على هذه ANDROID_IDالمشكلات (قد تكون nullأحيانًا أو أجهزة من طراز معين دائمًا ما تُرجع نفس الرقم) مع إيجابيات وسلبيات:

  • تنفيذ خوارزمية جيل معرف مخصص (على أساس خصائص الجهاز التي من المفترض أن تكون ثابتة ولن تتغير -> من يدري)
  • سيصبح من الضروري استخدام معرفات أخرى مثل IMEI والرقم التسلسلي وعنوان Wi-Fi / Bluetooth-MAC (لن تكون موجودة على جميع الأجهزة أو تصاريح إضافية)

أنا شخصياً أفضل استخدام تطبيق OpenUDID موجود (انظر https://github.com/ylechelle/OpenUDID ) لـ Android (راجع https://github.com/vieux/OpenUDID ). من السهل دمج واستخدام ANDROID_IDالاستغناء عن المشاكل المذكورة أعلاه.


و Serial تم إضافة الحقل إلى Buildفئة في مستوى API 9 (أندرويد 2.3 - الزنجبيل). تقول الوثائق انها تمثل الرقم التسلسلي للجهاز. وبالتالي يجب أن تكون فريدة ، إذا كانت موجودة على الجهاز.

لا أعرف ما إذا كانت مدعومة بالفعل (= لا فارغة) من قبل جميع الأجهزة مع مستوى API> = 9 رغم ذلك.





uniqueidentifier