شناسه یکتای دستگاه اندرویدی android device unique id

سلام. در برنامه نویسی اندروید، یه موضوعی که خیلی وقت پیش بهش برخورده بودم و جدیداً دوباره توی یکی از پروژه ها برام پیش اومد، پیدا کردن کد یکتا برای احراز هویت بود! در حقیقت میخواستیم مطمئن شیم که شناسه ی اصطلاحاً uniqueی رو برای دستگاه میتونیم بدست بیاریم. گفتم شاید بهتر باشه راه حلش رو با بقیه به اشتراک بذارم:

روش اول: AndroidId

خب اولین راه حل شاید استفاده از android_id باشه:

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

ولی باید حواسمون باشه که این روش ممکنه null برگردونه و توی داکیومنت نوشته شده که با فکرتوری ریست میتونه تغییر کنه.

روش دوم: IMEI

خب روش بعدی که ممکنه به ذهن همه برسه IMEI هست. این کد در واقع خلاصه ی عبارت "International Mobile Equipment Identity" یا «شناسه بین المللی تجهیزات موبایل» هست که بصورت زیر بدست میاد:

TelephonyManager TelephonyMgr = (TelephonyManager)getSystemService(TELEPHONY_SERVICE);
String imei = TelephonyMgr.getDeviceId();

این روش هم مشکلاتی داره مثل اینکه برای دسترسی به این کد باید اجازه ی READ_PHONE_STATE رو داشته باشیم و همونطور که میدونیم از نسخه ی اندروید لالیپاپ به بعد این پرمیشن جزو پرمیشن های ران-تایم هست (زمان اجرا باید از کاربر گرفته بشه) و طبیعتاً زیاد خوشآیند نیست.

روش سوم: MAC وای فای

خب هر دستگاهی که وای فای داشته باشه، طبیعتاً باید یه mac هم داشته باشه که به WLAN MAC معروفه و بصورت زیر بدست میاد:

WifiManager wm = (WifiManager)getSystemService(Context.WIFI_SERVICE);
String macAddress = wm.getConnectionInfo().getMacAddress();

مشکل این روش هم (علاوه بر اینکه با درصد خیلی پایینی ممکنه دستگاه اندرویدی wifi نداشته باشه) دقیقاً مثل مورد قبلی نیاز به اجازه ی دستری READ_PHONE_STATE هست. علاوه بر اینکه توی بعضی دستگاه ها null برگردونده میشه.

روش چهارم: MAC بلوتوث

و دقیقاً شبیه مورد قبلی ولی این بار میتونیم به mac بلوتوث دسترسی پیدا کنیم:

BluetoothAdapter m_BluetoothAdapter	= null;
m_BluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
String m_szBTMAC = m_BluetoothAdapter.getAddress();

که البته باز هم علاوه بر اینکه ممکنه دستگاهی بلوتوث نداشته باشه (هرچقدر هم احتمالش کم باشه)، ممکنه توی بعضی دستگاه ها null برگردونده بشه، همچنین با این روش نیاز به اجازه ی android.permission.BLUETOOTH داریم.

روش پنجم: Pseudo-UniqueID

میشه از روش های ترکیبی هم استفاده کرد، برای مثال تابع لینک زیر که اصطلاحاً Psuedo رو پیاده سازی کرده:

https://gist.github.com/pedja1/fe69e8a80ed505500caa

یا برای مثال استفاده از یسری اطلاعات که احتمال بسیار کمی وجود داره که بین دو دستگاه این مورد تکراری بشه:

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

روش ششم: ترکیبی

خب همونطور که توی هر کدوم از این روشا گفته شد، مشکلاتی وجود داره که ممکنه برای ما مهم باشه یا نباشه حتی بعضی از خروجی های این روش ها میتونه با روت شدن دستگاه توسط کاربر و دستکاری، تغییر بکنه. اما بصورت کلی برای کاهش احتمال خطا، میتونین هر محدودیتی خودتون بخواین رو به روش ها اعمال کنین! (مثلاً تعداد کاراکترهای روش پنجم رو تغییر بدین یا ...)
حتی میتونین ترکیبی از چند روش رو پیاده کنین، مثلاً تمامی رشته های چهار روش اول رو بگیرین (که ممکنه بعضیاشون null باشن یا دسترسی نداشته باشین بهشون) و یجوری که خودتون دوست دارین ترکیبشون کنین، یا اینکه نتیجه ی ترکیب رو به md5 تبدیل کنین. حتی توی مواردی شاید لازم باشه که اگه کاربر توی نرم افزار لاگین کرده، از id، توکن یا هرچیزی که ازش نگه میدارین هم استفاده کنین.


ممکنه روش های دیگه ای موجود باشه که خوشحال میشم اگه میدونین بگین تا با بقیه به اشتراک گذاشته بشه.