Android qurilmalarida noyob identifikator bormi va agar shunday bo'lsa, Java yordamida unga kirishning oddiy usuli qanday?
Noyob Android qurilma identifikatori bormi?
Javoblar (50)
Settings.Secure#ANDROID_ID
Android identifikatorini < sifatida qaytaradi. a href="https://developer.android.com/reference/android/provider/Settings.Secure.html#ANDROID_ID" rel="noreferrer">har bir foydalanuvchi uchun noyob 64-bit hex ip.
import android.provider.Settings.Secure;
private String android_id = Secure.getString(getContext().getContentResolver(),
Secure.ANDROID_ID);
Shuningdek, Noyob identifikatorlar uchun eng yaxshi amaliyotlarni oʻqing: https://developer.android.com/training/articles/user-data-ids
ANDROID_ID
- testda buni takrorlay olmayman - har qanday holatda ham xabardor bo'lishga arziydi...
- person Dori; 06.03.2014
YANGILASH: Androidning soʻnggi versiyalarida ANDROID_ID
bilan bogʻliq koʻplab muammolar hal qilindi va men bu yondashuvni endi kerak emas deb hisoblayman. Entoni javobiga qarang.
To'liq ma'lumot: mening ilovam dastlab quyidagi yondashuvdan foydalangan, ammo endi bu yondashuvdan foydalanmaydi va endi biz Android Developer Blog yozuvi emmby javobi havolasi (ya'ni , UUID#randomUUID()
yaratish va saqlash).
Bu savolga ko'plab javoblar mavjud, ularning aksariyati faqat bir muncha vaqt ishlaydi va afsuski, bu etarli emas.
Mening sinovlarim asosida (barcha telefonlar, kamida bittasi yoqilmagan):
- Sinov qilingan barcha qurilmalar
TelephonyManager.getDeviceId()
qiymatini qaytardi - Barcha GSM qurilmalari (hammasi SIM karta bilan tekshirilgan)
TelephonyManager.getSimSerialNumber()
qiymatini qaytardi - Barcha CDMA qurilmalari
getSimSerialNumber()
uchun null qiymatini qaytardi (kutilganidek) - Google hisobi qoʻshilgan barcha qurilmalar
ANDROID_ID
qiymatini qaytardi - Barcha CDMA qurilmalari
ANDROID_ID
vaTelephonyManager.getDeviceId()
uchun bir xil qiymatni (yoki bir xil qiymatdan olingan) qaytardi -- agarki sozlash vaqtida Google hisobi qo'shilgan bo'lsa. - SIM kartasiz GSM qurilmalarini, Google hisobi qo‘shilmagan GSM qurilmasini yoki samolyot rejimidagi qurilmalarni hali sinab ko‘rish imkonim yo‘q edi.
Shunday qilib, agar siz qurilmaning o'ziga xos bo'lishini istasangiz, TM.getDeviceId()
bu etarli bo'lishi kerak. Shubhasiz, ba'zi foydalanuvchilar boshqalarga qaraganda ko'proq paranoyakdir, shuning uchun 1 yoki undan ko'p identifikatorni xeshlash foydali bo'lishi mumkin, shunda satr hali ham qurilma uchun deyarli yagona bo'lib qoladi, lekin foydalanuvchining haqiqiy qurilmasini aniq belgilamaydi. Masalan, UUID bilan birlashtirilgan String.hashCode()
dan foydalanish:
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();
Quyidagi kabi narsaga olib kelishi mumkin: 00000000-54b3-e7c7-0000-000046bffd97
Bu men uchun etarlicha yaxshi ishlaydi.
Richard quyida aytib o'tganidek, TelephonyManager
xususiyatlarini o'qish uchun ruxsat kerakligini unutmang, shuning uchun buni manifestingizga qo'shing:
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
kutubxonalarni import qilish
import android.content.Context;
import android.telephony.TelephonyManager;
import android.view.View;
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
qo'shishni unutmang. Agar ma'lumotlar bazasida saqlansa, qaytarilgan satr 36 belgidan iborat.
- person Richard; 28.02.2011
#Oxirgi yangilangan: 6/2/15
Noyob identifikator, Google ishlab chiquvchi blogi va Android hujjatlarini yaratish haqidagi har bir Stack Overflow postini o‘qib chiqqanimdan so‘ng, “Pseudo ID” eng yaxshi variant deb o‘ylayman.
Asosiy muammo: Uskuna va dasturiy ta'minot
Uskuna
- Foydalanuvchilar apparat, Android plansheti yoki telefonini oʻzgartirishi mumkin, shuning uchun uskunaga asoslangan noyob identifikatorlar FOYDALANUVCHILARNI KUZATISH uchun yaxshi gʻoya emas.
- TRACKING HARDWARE uchun bu ajoyib g'oya
Dasturiy ta'minot
- Foydalanuvchilar, agar ular ildiz otgan bo'lsa, ROMni o'chirishi/o'zgartirishi mumkin
- Siz foydalanuvchilarni turli platformalarda kuzatishingiz mumkin (iOS, Android, Windows va Web)
- INDIVIDUAL FOYDALANUVCHIni uning roziligi bilan kuzatmoqchi bo'lgan eng yaxshi narsa shunchaki tizimga kirish (OAuth yordamida muammosiz qilish)dir.
#Android bilan umumiy parchalanish
###- API ›= 9/10 (Android qurilmalarining 99,5%) uchun o‘ziga xoslik kafolati (ildizli qurilmalar ham kiradi) ###- Qo‘shimcha ruxsatlar yo‘q
Psuedo kodi:
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)
barcha variantlarimizni joylaganingiz uchun @stansultga rahmat (ushbu Stack Overflow savolida).
##Variantlar ro'yxati - ularni nima uchun / nima uchun ishlatmaslik sabablari:
Foydalanuvchi elektron pochtasi - Dasturiy ta'minot
Foydalanuvchi elektron pochta manzilini o'zgartirishi mumkin - YUQORI dargumon
API 5+
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
yokiAPI 14+
<uses-permission android:name="android.permission.READ_PROFILE" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
(Android qurilmasini qanday olish mumkin asosiy elektron pochta manzili)Foydalanuvchi telefon raqami - Dasturiy ta'minot
Foydalanuvchilar telefon raqamlarini o'zgartirishi mumkin - YUQORI dargumon
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
IMEI - Uskuna (faqat telefonlar uchun
android.permission.READ_PHONE_STATE
kerak)Ko'pchilik foydalanuvchilar ruxsatnomada Telefon qo'ng'iroqlari yozilganidan nafratlanadi. Ba'zi foydalanuvchilar noto'g'ri baho berishadi, chunki ular sizning shaxsiy ma'lumotlaringizni o'g'irlayotganingizga ishonishadi, chunki siz faqat qurilma o'rnatilishini kuzatishni xohlaysiz. Siz ma'lumot to'playotganingiz aniq.
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
Android ID - Uskuna (nol bo'lishi mumkin, zavod sozlamalariga qaytarilganda o'zgarishi mumkin, ildiz otgan qurilmada o'zgartirilishi mumkin)
U "null" bo'lishi mumkinligi sababli, biz "null" ni tekshirishimiz va uning qiymatini o'zgartirishimiz mumkin, ammo bu endi u noyob bo'lmaydi.
Agar sizda zavod sozlamalarini tiklash qurilmasi bo'lgan foydalanuvchi bo'lsa, qiymat ildiz otgan qurilmada o'zgargan yoki o'zgartirilgan bo'lishi mumkin, shuning uchun foydalanuvchi o'rnatishlarini kuzatayotgan bo'lsangiz, takroriy yozuvlar bo'lishi mumkin.
WLAN MAC manzili - Uskuna (kerak
android.permission.ACCESS_WIFI_STATE
)Bu ikkinchi eng yaxshi variant bo'lishi mumkin, lekin siz hali ham to'g'ridan-to'g'ri foydalanuvchidan keladigan noyob identifikatorni yig'ib va saqlayapsiz. Bu siz ma'lumot to'playotganingiz aniq.
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE "/>
Bluetooth MAC manzili - Uskuna (Bluetooth bilan jihozlangan qurilmalar uchun
android.permission.BLUETOOTH
kerak)Bozordagi aksariyat ilovalar Bluetooth-dan foydalanmaydi, shuning uchun ilovangiz Bluetooth-dan foydalanmasa va siz buni qo'shsangiz, foydalanuvchi shubhalanishi mumkin.
<uses-permission android:name="android.permission.BLUETOOTH "/>
Pseudo-unique ID - dasturiy ta'minot (barcha Android qurilmalar uchun)
Juda mumkin, to'qnashuvlar bo'lishi mumkin - Quyida e'lon qilingan usulimni ko'ring!
Bu sizga shaxsiy hech narsa olmasdan foydalanuvchidan "deyarli noyob" identifikatorga ega bo'lish imkonini beradi. Qurilma ma'lumotlaridan o'zingizning anonim identifikatoringizni yaratishingiz mumkin.
Ruxsatlardan foydalanmasdan noyob identifikatorni olishning "mukammal" usuli yo'qligini bilaman; ammo, ba'zan biz faqat, albatta, qurilma o'rnatish kuzatish kerak. Noyob identifikatorni yaratish haqida gap ketganda, biz qo'shimcha ruxsatlardan foydalanmasdan faqat Android API bizga beradigan ma'lumotlar asosida "soxta noyob identifikator" yaratishimiz mumkin. Shunday qilib, biz foydalanuvchiga hurmat ko'rsatishimiz va yaxshi foydalanuvchi tajribasini taklif qilishga harakat qilishimiz mumkin.
Pseudo-noyob identifikator bilan siz haqiqatan ham shunga o'xshash qurilmalar mavjudligiga asoslanib, dublikatlar bo'lishi mumkinligiga duch kelasiz. Uni yanada noyob qilish uchun birlashtirilgan usulni sozlashingiz mumkin; biroq, ba'zi ishlab chiquvchilar qurilma o'rnatilishini kuzatishlari kerak va bu o'xshash qurilmalarga asoslangan hiyla yoki ishlashni amalga oshiradi.
##API ›= 9:
Agar ularning Android qurilmasi API 9 yoki undan yuqori boʻlsa, “Build.SERIAL” maydoni tufayli bu noyob boʻlishi kafolatlanadi.
ESDA OLING, siz texnik jihatdan faqat taxminan 0,5% foydalanuvchilardan API ‹ 9ga ega. Shunday qilib, siz qolgan narsalarga e'tibor qaratishingiz mumkin: Bu foydalanuvchilarning 99,5% ni tashkil qiladi!
##API ‹ 9:
Agar foydalanuvchining Android qurilmasi API 9 dan past bo'lsa; umid qilamanki, ular zavod sozlamalarini tiklamagan va ularning "Secure.ANDROID_ID" saqlanadi yoki "null" bo'lmaydi. (qarang: http://developer.android.com/about/dashboards/index.html)
##Agar hammasi bajarilmasa:
Agar barchasi bajarilmasa, agar foydalanuvchi API 9 dan pastroq bo‘lsa (Gingerbread’dan pastroq), qurilmasini asl holatiga qaytargan bo‘lsa yoki “Secure.ANDROID_ID” “null” qiymatini qaytarsa, qaytarilgan identifikator faqat Android qurilmasi ma’lumotlariga asoslanadi. . Bu erda to'qnashuvlar sodir bo'lishi mumkin.
O'zgarishlar:
- “Android.SECURE_ID” olib tashlandi, chunki zavod sozlamalari qiymat o‘zgarishiga olib kelishi mumkin
- APIda o'zgartirish uchun kod tahrirlangan
- Pseudo-ni o'zgartirdi
Iltimos, quyidagi usulni ko'rib chiqing:
/**
* 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();
}
#Yangi (reklamali ilovalar va Google Play xizmatlari uchun):
Google Play Developer konsolidan:
2014-yil 1-avgustdan boshlab Google Play Developer dasturi siyosati har qanday reklama maqsadlarida boshqa doimiy identifikatorlar o‘rniga reklama identifikatoridan foydalanish uchun butunlay yangi ilovalarni yuklash va yangilashni talab qiladi. Ko'proq ma'lumot olish
Amalga olish:
Ruxsat:
<uses-permission android:name="android.permission.INTERNET" />
Kod:
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();
}
Manba/Hujjatlar:
http://developer.android.com/google/play-services/id.html http://developer.android.com/reference/com/google/android/gms/ads/identifier/AdvertisingIdClient.html
##Muhim:
Google Play xizmatlari mavjud boʻlganda, reklama identifikatori reklama maqsadlarida (masalan, Settings.Secureʼda ANDROID_IDʼdan foydalanish) boshqa identifikatorlardan foydalanishni toʻliq almashtirishi moʻljallangan. Google Play xizmatlaridan foydalanish mumkin bo'lmagan holatlar getAdvertisingIdInfo() tomonidan yuborilgan GooglePlayServicesNotAvailableException bilan ko'rsatilgan.
##Ogohlantirish, foydalanuvchilar quyidagi sozlamalarni tiklashlari mumkin:
http://en.kioskea.net/faq/34732-android-reset-your-advertising-id
Men ma'lumot olgan har bir havolaga havola qilishga harakat qildim. Agar siz etishmayotgan bo'lsangiz va qo'shishingiz kerak bo'lsa, izoh qoldiring!
Google Player xizmatlari InstanceID
https://developers.google.com/instance-id/
Deyv Uebb ta'kidlaganidek, Android Developers blogida maqola bor buni qamrab oladi. Ularning afzal ko'rgan yechimi qurilmalardan ko'ra ilovalarni o'rnatishni kuzatishdir va bu ko'pchilik foydalanish holatlarida yaxshi ishlaydi. Blog posti sizga buni amalga oshirish uchun kerakli kodni ko'rsatadi va men uni tekshirishni tavsiya qilaman.
Biroq, blog postida sizga ilovani o'rnatish identifikatori emas, balki qurilma identifikatori kerak bo'lsa, echimlarni muhokama qilish davom etadi. Agar kerak bo'lsa, ba'zi narsalar bo'yicha qo'shimcha tushuntirish olish uchun Google'dagi kimdir bilan gaplashdim. Men yuqorida aytib o'tilgan blog postida EMAS qurilma identifikatorlari haqida bilib oldim:
- ANDROID_ID afzal qilingan qurilma identifikatoridir. ANDROID_ID Android ‹=2.1 yoki >=2.3 versiyalarida juda ishonchli. Faqat 2.2-da postda aytib o'tilgan muammolar mavjud.
- Bir nechta ishlab chiqaruvchilarning bir nechta qurilmalari 2.2.1-dagi ANDROID_ID xatosidan ta'sirlangan.
- Aniqlashimcha, barcha zararlangan qurilmalar bir xil ANDROID_IDga ega, ya'ni 9774d56d682e549c. Bu emulyator tomonidan bildirilgan bir xil qurilma identifikatoridir, btw.
- Google OEM’lar ko‘p yoki ko‘pchilik qurilmalari uchun muammoni tuzatgan deb hisoblaydi, biroq men 2011-yil aprel oyi boshidan boshlab, hech bo‘lmaganda ANDROID_ID buzilgan qurilmalarni topish hali ham oson ekanligini tasdiqladim.
Google tavsiyalariga asoslanib, men har bir qurilma uchun noyob UUID ni yaratadigan sinfni joriy qildim, agar kerak bo'lsa, ANDROID_ID ni urug' sifatida ishlatib, kerak bo'lganda TelephonyManager.getDeviceId() ga qaytadi va agar bu muvaffaqiyatsiz bo'lsa, tasodifiy yaratilgan noyob UUID ga murojaat qildim. bu ilovalarni qayta ishga tushirishda (ilovani qayta o'rnatishda emas) saqlanib qoladi.
Esda tutingki, qurilma identifikatorida qayta tiklanishi kerak bo'lgan qurilmalar uchun noyob ID BO'LADI zavod sozlamalariga qaytarilganda ham saqlanib qoladi. Bu xabardor bo'lishi kerak bo'lgan narsa. Zavod sozlamalarini tiklash sizning noyob identifikatoringizni qayta tiklashiga ishonch hosil qilishingiz kerak bo'lsa, qurilma identifikatori o'rniga to'g'ridan-to'g'ri tasodifiy UUID ga qaytish haqida o'ylashingiz mumkin.
Shunga qaramay, ushbu kod ilovani o'rnatish identifikatori emas, balki qurilma identifikatori uchundir. Ko'pgina hollarda, ilovani o'rnatish identifikatori siz qidirayotgan narsadir. Ammo agar sizga qurilma identifikatori kerak bo'lsa, unda quyidagi kod sizga mos kelishi mumkin.
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;
}
}
Bu yil Reto Meyer Google I/O taqdimotida noyob identifikatorni olish uchun ishlatgan kod. foydalanuvchi:
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;
}
Agar siz buni bulutga afzalliklarni yuborish uchun zaxira strategiyasi bilan birlashtirsangiz (shuningdek, Reto suhbat uchun sizda foydalanuvchi bilan bog'langan va qurilma o'chirilgandan yoki hatto almashtirilgandan keyin ham yopishib oladigan identifikatoringiz bo'lishi kerak. Men bundan tahlilda foydalanishni rejalashtirmoqdaman. oldinga (boshqacha aytganda, men hali buni qilmaganman :).
Shuningdek, siz Wi-Fi adapterining MAC manzilini ko'rib chiqishingiz mumkin. Quyidagi tarzda olindi:
WifiManager wm = (WifiManager)Ctxt.getSystemService(Context.WIFI_SERVICE);
return wm.getConnectionInfo().getMacAddress();
Manifestda android.permission.ACCESS_WIFI_STATE
ruxsat talab qiladi.
Wi-Fi ulanmagan bo'lsa ham foydalanish mumkinligi xabar qilingan. Agar yuqoridagi javobdan Jou buni o'zining ko'plab qurilmalarida sinab ko'rsa, bu yaxshi bo'lardi.
Ba'zi qurilmalarda Wi-Fi o'chirilgan bo'lsa, u ishlamaydi.
QAYD: Android 6.x-dan u doimiy soxta mac manzilini qaytaradi: 02:00:00:00:00:00
Muammo shundaki, sizning XML standart nom maydonidan foydalanmoqda, ammo XSD maqsadli nom maydonini belgilaydi. Agar siz XML-da <BadManifest xmlns="http://www.engagesoftware.com/Schemas/EngageManifest">
ni belgilasangiz, tekshiruvchi xatolar haqida kutilganidek xabar berishini bilib olishingiz kerak. Aks holda, u XML nom maydonini tanimaganligi sababli, uni e'tiborsiz qoldiradi.
02:00:00:00:00:00
- person Behrouz.M; 10.07.2016
Juda foydali ma'lumot bu yerda.
U besh xil ID turini qamrab oladi:
- IMEI (faqat Telefon ishlatadigan Android qurilmalari uchun;
android.permission.READ_PHONE_STATE
kerak) - Pseudo-unique ID (barcha Android qurilmalar uchun)
- Android ID (null boʻlishi mumkin, zavod sozlamalariga qaytarilgandan soʻng oʻzgarishi mumkin, ildiz otgan telefonda oʻzgartirilishi mumkin)
- WLAN MAC manzili qatori (kerak:
android.permission.ACCESS_WIFI_STATE
) - BT MAC manzili qatori (Bluetooth'li qurilmalar uchun
android.permission.BLUETOOTH
kerak)
Bu oddiy savol, oddiy javob yo'q.
Bundan tashqari, bu erda mavjud bo'lgan barcha javoblar eskirganmi yoki ishonchsizmi.
Shunday qilib, agar siz 2020-yilda yechim izlayotgan bo'lsangiz.
Bu erda bir nechta narsalarni yodda tutish kerak:
Uskunaga asoslangan barcha identifikatorlar (SSAID, IMEI, MAC va boshqalar) butun dunyo bo'ylab faol qurilmalarning 50% dan ortig'ini tashkil etuvchi Google-ga tegishli bo'lmagan qurilmalar (Pixels va Nexus-dan tashqari hamma narsa) uchun ishonchsizdir. Shuning uchun rasmiy Android identifikatorlari bo‘yicha eng yaxshi amaliyotlar aniq ko‘rsatilgan:
SSAID (Android ID), IMEI, MAC manzili va h.k. kabi apparat identifikatorlaridan foydalanmang...
Bu yuqoridagi javoblarning aksariyatini bekor qiladi. Shuningdek, turli xil android xavfsizlik yangilanishlari tufayli, ulardan ba'zilari foydalanuvchi tomonidan rad etilishi mumkin bo'lgan yangiroq va qattiqroq ish vaqti ruxsatnomalarini talab qiladi.
Misol sifatida, yuqorida aytib o'tilgan barcha WIFI-ga asoslangan texnikalarga ta'sir qiluvchi CVE-2018-9489
.
Bu esa o'sha identifikatorlarni nafaqat ishonchsiz, balki ko'p hollarda ularga kirish imkonsiz qiladi.
Shunday qilib, oddiyroq so'zlar bilan aytganda: bu usullardan foydalanmang.
Bu erda ko'plab boshqa javoblar AdvertisingIdClient
dan foydalanishni taklif qiladi, bu ham mos kelmaydi, chunki uning dizayni faqat reklama profilini yaratish uchun ishlatilishi kerak. Bu rasmiy ma'lumotnomada ham aytilgan.
Foydalanuvchi profilini yaratish yoki reklamalardan foydalanish holatlari uchun faqat reklama identifikatoridan foydalaning
Bu nafaqat qurilmani identifikatsiyalashda ishonchsiz, balki reklamani kuzatish bo'yicha foydalanuvchi maxfiyligi siyosati, unda foydalanuvchi istalgan vaqtda uni qayta o'rnatishi yoki bloklashi mumkinligi aniq ko'rsatilgan.
Shuning uchun uni ham ishlatmang.
Istalgan statik global noyob va ishonchli qurilma identifikatoriga ega bo'lolmaysiz. Androidning rasmiy ma'lumotnomasi quyidagilarni taklif qiladi:
Toʻlov firibgarligining oldini olish va telefoniyadan tashqari, iloji boʻlsa, FirebaseInstanceId yoki shaxsiy saqlangan GUIDdan foydalaning.
Bu qurilmada ilovalarni o'rnatish uchun noyobdir, shuning uchun foydalanuvchi dasturni o'chirib tashlaganida - u o'chib ketadi, shuning uchun u 100% ishonchli emas, lekin bu keyingi eng yaxshi narsa.
FirebaseInstanceId
dan foydalanish uchun gradleingizga oxirgi firebase-messaging bog‘liqligini qo‘shing.
implementation 'com.google.firebase:firebase-messaging:20.2.4'
Va fonda quyidagi koddan foydalaning:
String reliableIdentifier = FirebaseInstanceId.getInstance().getId();
Agar siz qurilma identifikatorini masofaviy serveringizda saqlashingiz kerak bo'lsa, uni avvalgidek saqlamang (oddiy matn), balki tuz bilan xash.
Bugungi kunda bu nafaqat eng yaxshi amaliyot, balki uni GDPR - identifikatorlar< ga muvofiq qonun bo'yicha bajarishingiz kerak. /a> va shunga o'xshash qoidalar.
UUID.randomUUID()
psuedo-tasodifiy platformasi vaqtga asoslangan tabiatga bog'liq.
- person Nikita Kurtin; 25.02.2021
Rasmiy Android Developers blogida endi aynan shu mavzu haqida toʻliq maqola bor, Identifying Ilovalarni oʻrnatish.
Google I/O da Reto Meier ko‘pchilik ishlab chiquvchilar kuzatishi kerak bo‘lgan talablarga javob beradigan bunga qanday yondashish kerakligi haqidagi ishonchli javobni e’lon qildi. o'rnatish bo'ylab foydalanuvchilar. Entoni Nolan o'z javobida yo'nalishni ko'rsatadi, lekin boshqalar buni qanday qilishni osonlik bilan ko'rishlari uchun men to'liq yondashuvni yozaman deb o'yladim (tafsilotlarni tushunish uchun biroz vaqt ketdi).
Ushbu yondashuv sizga anonim, xavfsiz foydalanuvchi identifikatorini beradi, u foydalanuvchi uchun turli qurilmalarda (asosiy Google hisobiga asoslangan) va oʻrnatishlarda doimiy boʻladi. Asosiy yondashuv tasodifiy foydalanuvchi identifikatorini yaratish va uni ilovalarning umumiy afzalliklarida saqlashdir. Keyin Google hisobiga bog'langan umumiy afzalliklarni bulutda saqlash uchun Google zaxira agentidan foydalanasiz.
Keling, to'liq yondashuvni ko'rib chiqaylik. Birinchidan, Android Zaxiralash xizmati yordamida SharedPreferences uchun zaxira nusxasini yaratishimiz kerak. Ilovangizni http://developer.android.com/google/backup/signup.html
orqali roʻyxatdan oʻtkazishdan boshlang.
Google sizga manifestga qo'shishingiz kerak bo'lgan zaxira xizmat kalitini beradi. Shuningdek, dasturga BackupAgent-dan quyidagi tarzda foydalanishni aytishingiz kerak:
<application android:label="MyApplication"
android:backupAgent="MyBackupAgent">
...
<meta-data android:name="com.google.android.backup.api_key"
android:value="your_backup_service_key" />
</application>
Keyin zaxira agentini yaratishingiz va unga umumiy afzalliklar uchun yordamchi agentdan foydalanishni aytishingiz kerak:
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);
}
}
Zaxiralashni yakunlash uchun asosiy faoliyatingizda BackupManager nusxasini yaratishingiz kerak:
BackupManager backupManager = new BackupManager(context);
Nihoyat, agar u mavjud bo'lmasa, foydalanuvchi identifikatorini yarating va uni SharedPreferences-da saqlang:
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;
}
Ushbu User_ID endi, hatto foydalanuvchi qurilmani boshqa joyga ko'chirsa ham, o'rnatishlarda doimiy bo'lib qoladi.
Ushbu yondashuv haqida qo'shimcha ma'lumot olish uchun Retoning nutqi.
Zaxira agentini qanday amalga oshirish haqida toʻliq maʼlumot olish uchun Maʼlumotlarni zaxiralash. Men, ayniqsa, testning pastki qismidagi bo'limni tavsiya qilaman, chunki zaxira bir zumda sodir bo'lmaydi va shuning uchun siz zahira nusxasini majburlashingiz kerak.
Menimcha, bu noyob identifikator uchun skelet yasashning ishonchli usuli... buni tekshiring.
Barcha Android qurilmalarida ishlaydigan Pseudo-Unique ID Ba'zi qurilmalarda telefon yo'q (masalan, planshetlar) yoki ba'zi sabablarga ko'ra siz READ_PHONE_STATE ruxsatini qo'shishni xohlamaysiz. Siz hali ham ROM versiyasi, ishlab chiqaruvchi nomi, protsessor turi va boshqa apparat tafsilotlarini o'qishingiz mumkin, agar siz identifikatordan seriya kalitini tekshirish yoki boshqa umumiy maqsadlarda foydalanmoqchi bo'lsangiz juda mos keladi. Shu tarzda hisoblangan identifikator noyob bo'lmaydi: bir xil identifikatorga ega bo'lgan ikkita qurilmani topish mumkin (bir xil apparat va ROM tasviriga asoslangan), lekin real ilovalardagi o'zgarishlar ahamiyatsiz. Buning uchun siz Build sinfidan foydalanishingiz mumkin:
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 a'zolarining aksariyati satrlardir, biz bu erda ularning uzunligini olish va modul orqali raqamga aylantirishdir. Bizda 13 ta bunday raqam bor va biz IMEI (15 ta raqam) bilan bir xil o'lchamdagi identifikatorga ega bo'lish uchun old tomonga (35) yana ikkitasini qo'shmoqdamiz. Bu erda boshqa imkoniyatlar ham bor, shunchaki ushbu satrlarni ko'rib chiqing. 355715565309247
kabi narsalarni qaytaradi. Hech qanday maxsus ruxsat talab qilinmaydi, bu yondashuvni juda qulay qiladi.
(Qoʻshimcha maʼlumot: Yuqorida keltirilgan texnika Pocket Magic dagi maqoladan koʻchirilgan.)
Quyidagi kod yashirin Android API yordamida qurilma seriya raqamini qaytaradi. Biroq, bu kod Samsung Galaxy Tab-da ishlamaydi, chunki bu qurilmada "ro.serialno" o'rnatilmagan.
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) {
}
Quyidagi koddan foydalanib, siz Android OS qurilmasining noyob qurilma identifikatorini qator sifatida olishingiz mumkin.
deviceId = Secure.getString(getApplicationContext().getContentResolver(), Secure.ANDROID_ID);
API 9-darajadagi Build
sinfiga Serial maydoni qo‘shildi. (Android 2.3 - Gingerbread). Hujjatlarda aytilishicha, u apparat seriya raqamini ifodalaydi. Shunday qilib, agar u qurilmada mavjud bo'lsa, u noyob bo'lishi kerak.
API darajasi >= 9 bo'lgan barcha qurilmalar tomonidan aslida qo'llab-quvvatlanadimi yoki yo'qligini bilmayman (= null emas).
Men bir narsani qo'shaman - menda o'sha noyob vaziyatlardan biri bor.
Foydalanish:
deviceId = Secure.getString(this.getContext().getContentResolver(), Secure.ANDROID_ID);
Ma'lum bo'lishicha, mening Viewsonic G planshetim Null bo'lmagan DeviceID haqida xabar bergan bo'lsa ham, har bir G plansheti bir xil raqam haqida xabar beradi.
“Noyob” DeviceID asosida kimningdir akkauntiga bir zumda kirish imkonini beruvchi “Pocket Empires” oʻyinini qiziqarli qiladi.
Mening qurilmamda uyali radio yo'q.
Ilovangiz oʻrnatilgan har bir Android qurilmasi uchun noyob identifikatorni qanday olish boʻyicha batafsil koʻrsatmalar uchun Android Developers.blogspot.com/2011/03-dagi rasmiy Android Developers blogiga qarang. /identifying-app-installations.html" rel="noreferrer">Ilova o‘rnatishlarini aniqlash.
O'rnatishdan so'ng uni o'zingiz yaratishingiz va keyinchalik dastur qayta ishga tushirilganda uni o'qib chiqishingiz eng yaxshi yo'l bo'lib tuyuladi.
Shaxsan men buni maqbul deb bilaman, lekin ideal emas. Android tomonidan taqdim etilgan hech bir identifikator barcha holatlarda ishlamaydi, chunki ko'pchilik telefonning radio holatiga bog'liq (Wi-Fi yoqish/o'chirish, uyali aloqani yoqish/o'chirish, Bluetooth yoqish/o'chirish). Boshqalar, masalan, Settings.Secure.ANDROID_ID
ishlab chiqaruvchi tomonidan amalga oshirilishi kerak va noyob bo'lishi kafolatlanmaydi.
Quyida ilova mahalliy sifatida saqlaydigan boshqa maʼlumotlar bilan birga saqlanadigan oʻrnatish fayliga maʼlumotlarni yozish misoli keltirilgan.
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();
}
}
Sinf fayliga quyidagi kodni qo'shing:
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 ga qo'shing:
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
Ushbu ANDROID_ID
muammolarni hal qilish uchun juda ko'p turli xil yondashuvlar mavjud (ba'zida null
bo'lishi mumkin yoki muayyan modeldagi qurilmalar har doim bir xil identifikatorni qaytaradi) ijobiy va salbiy tomonlari bilan:
- Shaxsiy identifikatorni yaratish algoritmini amalga oshirish (statik bo'lishi kerak bo'lgan va o'zgarmaydigan qurilma xususiyatlariga asoslangan -> kim biladi)
- IMEI, seriya raqami, Wi-Fi/Bluetooth-MAC manzili (ular yutadi) kabi boshqa identifikatorlarni suiiste'mol qilish t barcha qurilmalarda mavjud yoki qo'shimcha ruxsatlar kerak bo'ladi)
Men o'zim mavjud OpenUDID ilovasidan foydalanishni afzal ko'raman (qarang: https://github.com/ylechelle/OpenUDID). Android (qarang: https://github.com/vieux/OpenUDID). U integratsiya qilish oson va yuqorida aytib o'tilgan muammolar uchun ANDROID_ID
-dan zaxiralar bilan foydalanadi.
TelephonyManager
va ANDROID_ID
dan foydalangan holda String sifatida Android OS qurilmasining noyob qurilma identifikatori quyidagilar orqali olinadi:
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);
}
Lekin men Google tomonidan tavsiya etilgan usulni tavsiya qilaman, qarang: Identifikatsiya qilish Ilovalarni oʻrnatish.
Bu erda 30 dan ortiq javoblar mavjud va ba'zilari bir xil va ba'zilari noyobdir. Bu javob o'sha javoblarning bir nechtasiga asoslanadi. Ulardan biri @Lenn Dollingning javobidir.
U 3 ta identifikatorni birlashtiradi va 32 xonali olti burchakli qatorni yaratadi. Bu men uchun juda yaxshi ishladi.
3 identifikator:
Pseudo-ID - U jismoniy qurilma spetsifikatsiyalari asosida yaratilgan
ANDROID_ID - Settings.Secure.ANDROID_ID
Bluetooth manzili - Bluetooth adapter manzili
U shunday qaytaradi: 551F27C060712A72730B0A0F734064B1
Eslatma: Siz har doim longId
qatoriga qoʻshimcha identifikatorlar qoʻshishingiz mumkin. Masalan, seriya #. Wi-Fi adapter manzili. IMEI. Shunday qilib, siz uni har bir qurilma uchun yanada noyob qilasiz.
@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
raqamiga qo‘shish va uni faylda saqlash uni eng noyob identifikatorga aylantiradi. : String uuid = UUID.randomUUID().toString();
- person Mousa Alfhaily; 11.04.2017
longId
ga UUID qo'shishni taklif qilaman. Bir qatorni shunday o'zgartiring: String longId = pseudoId + androidId + btId + UUID.randomUUID().toString();
Bu yaratilgan ID noyob bo'lishini kafolatlaydi.
- person ᴛʜᴇᴘᴀᴛᴇʟ; 03.04.2019
IMEI haqida nima deyish mumkin? Bu Android yoki boshqa mobil qurilmalar uchun noyobdir.
Men noyob identifikatorni qanday yarataman:
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;
}
Mening ikki sentim - bu qurilma (xato) noyob identifikatori uchun - Android ishlab chiquvchilar blogi.
Shuni esda tutingki, @emmby tomonidan taqdim etilgan yechim har bir ilova identifikatoriga to'g'ri keladi, chunki SharedPreferences jarayonlar bo'ylab sinxronlashtirilmaydi (qarang. bu yerda va bu yerda). Shunday qilib, men bundan butunlay voz kechdim.
Buning o'rniga, enumda (qurilma) identifikatorini olishning turli strategiyalarini qamrab oldim - enum konstantalarining tartibini o'zgartirish ID olishning turli usullarining ustuvorligiga ta'sir qiladi. Birinchi null bo'lmagan identifikator qaytariladi yoki istisno qilinadi (Javaning null ma'nosini bermaslik amaliyotiga ko'ra). Masalan, menda birinchi TELEPHONY bor - lekin yaxshi birlamchi tanlov ANDROID_ID beta: bo'ladi.
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);
}
}
}
Boshqa usul - /sys/class/android_usb/android0/iSerial
ilovasida hech qanday ruxsatsiz foydalanish.
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-da buni amalga oshirish uchun iSerial faylini ochish va belgilarni o'qish uchun FileInputStream-dan foydalanish kifoya. Uni istisno ishlovchiga o'rashingizga ishonch hosil qiling, chunki hamma qurilmalarda ham bu fayl mavjud emas.
Hech bo'lmaganda quyidagi qurilmalar ushbu faylni dunyo tomonidan o'qilishi mumkinligi ma'lum:
- Galaxy Nexus
- Nexus S
- Motorola Xoom 3G
- Toshiba AT300
- HTC One V
- Mini MK802
- Samsung Galaxy S II
Siz mening blogimdagi postimni ham ko'rishingiz mumkin Android uskunasining sizib chiqishi imtiyozsiz ilovalar uchun seriya raqami, bu erda men ma'lumot olish uchun qanday boshqa fayllar mavjudligini muhokama qilaman.
TelephonyManger.getDeviceId() Noyob qurilma identifikatorini qaytaradi, masalan, GSM uchun IMEI va CDMA telefonlari uchun MEID yoki ESN.
final TelephonyManager mTelephony = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
String myAndroidDeviceId = mTelephony.getDeviceId();
Lekin men foydalanishni tavsiya qilaman:
Settings.Secure.ANDROID_ID bu Android identifikatorini noyob 64 bitli olti burchakli qator sifatida qaytaradi.
String myAndroidDeviceId = Secure.getString(getApplicationContext().getContentResolver(), Secure.ANDROID_ID);
Ba'zan TelephonyManger.getDeviceId() null qiymatini qaytaradi, shuning uchun noyob identifikatorga ishonch hosil qilish uchun siz ushbu usuldan foydalanasiz:
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;
}
Google Instance ID
I/O 2015 da chiqarilgan; Android-da o'yin xizmatlarini talab qiladi 7.5.
https://developers.google.com/instance-id/
https://developers.google.com/instance-id/guides/android-implementation
InstanceID iid = InstanceID.getInstance( context ); // Google docs are wrong - this requires context
String id = iid.getId(); // blocking call
Google ushbu identifikatordan Android, Chrome va iOS qurilmalaridagi oʻrnatishlarni aniqlash uchun foydalanish niyatida.
U qurilmani emas, balki o'rnatishni aniqlaydi, lekin yana ANDROID_ID (bu qabul qilingan javob) endi qurilmalarni ham aniqlamaydi. ARC ish vaqti bilan har bir o'rnatish uchun yangi ANDROID_ID yaratiladi (tafsilotlari bu yerda), xuddi shu yangi namuna identifikatori kabi. Bundan tashqari, menimcha, o'rnatishlarni aniqlash (qurilmalar emas) ko'pchiligimiz izlayotgan narsadir.
Identifikator namunasining afzalliklari
Menimcha, Google uni shu maqsadda qo'llashni (o'rnatishlaringizni aniqlash) mo'ljallangan, u o'zaro platformalardir va boshqa bir qator maqsadlarda foydalanish mumkin (yuqoridagi havolalarga qarang).
Agar siz GCM dan foydalansangiz, oxir-oqibat ushbu misol identifikatoridan foydalanishingiz kerak bo'ladi, chunki u sizga GCM tokenini (eski GCM ro'yxatga olish identifikatori o'rnini bosuvchi) olish uchun kerak bo'ladi.
Kamchiliklar/muammolar
Joriy tatbiqda (GPS 7.5) misol identifikatori ilovangiz talab qilganda serverdan olinadi. Bu shuni anglatadiki, yuqoridagi qo'ng'iroq blokirovka qiluvchi qo'ng'iroqdir - mening ilmiy asossiz sinovlarimga ko'ra, agar qurilma onlayn bo'lsa, bu 1-3 soniyani oladi, agar oflayn bo'lsa - 0,5 - 1,0 soniya (ehtimol, bu qo'ng'iroqdan voz kechishdan va yaratishdan oldin qancha vaqt kutadi). tasodifiy ID). Bu Shimoliy Amerikada Android 5.1.1 va GPS 7.5 bilan Nexus 5 da sinovdan o'tkazildi.
Agar siz identifikatordan ular mo'ljallangan maqsadlarda foydalansangiz - masalan. ilova autentifikatsiyasi, ilova identifikatsiyasi, GCM - Menimcha, bu 1-3 soniya noqulaylik tug'dirishi mumkin (albatta ilovangizga qarab).
Muayyan Android qurilmasini apparat tomonidan tanib olish uchun MAC manzillarini tekshirishingiz mumkin.
buni shunday qilishingiz mumkin:
AndroidManifest.xml ichida
<uses-permission android:name="android.permission.INTERNET" />
endi sizning kodingizda:
List<NetworkInterface> interfacesList = Collections.list(NetworkInterface.getNetworkInterfaces());
for (NetworkInterface interface : interfacesList) {
// This will give you the interface MAC ADDRESS
interface.getHardwareAddress();
}
Har bir Android qurilmasida ularning kamida "wlan0" interfeysi jodugar WI-FI chipidir. Ushbu kod WI-FI yoqilmaganda ham ishlaydi.
P.S. Ular MACS o'z ichiga olgan ro'yxatdagi boshqa interfeyslar to'plamidir, ammo bu telefonlar o'rtasida o'zgarishi mumkin.
Men IMEI
ni olish uchun quyidagi koddan foydalanaman yoki qurilma telefon imkoniyatlariga ega boʻlmasa, muqobil sifatida Secure.ANDROID_ID
dan foydalanaman:
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);
Android qurilmalaridagi mavjud noyob identifikatorlarni tushunish uchun. Ushbu rasmiy qo'llanmadan foydalaning.
Noyob identifikatorlar uchun eng yaxshi amaliyotlar:
Qurilmalarni tekshirish uchun IMEI, Mac manzillari, namuna identifikatori, GUIDlar, SSAID, reklama identifikatori, Safety Net API.
https://developer.android.com/training/articles/user-data-ids
Google endi Reklama identifikatoriga ega.
Bu ham mumkin foydalanish mumkin, lekin shuni yodda tuting:
Reklama identifikatori foydalanuvchiga xos, noyob, qayta tiklanadigan identifikatordir
va
foydalanuvchilarga identifikatorini tiklash yoki Google Play ilovalaridagi qiziqishlarga asoslangan reklamalardan voz kechish imkonini beradi.
Bu identifikator o'zgarishi mumkin bo'lsa-da, tez orada bizda tanlov bo'lmasligi mumkin, bu identifikatorning maqsadiga bog'liq.
Batafsil ma'lumot @ develper.android
Kodni shu yerdan nusxalash-joylashtirish
HTH
1. Noyob identifikatorni (ya'ni IMEI) taqdim etadigan telefoniya menejeridan foydalaning. Misolga qarang,
import android.telephony.TelephonyManager;
import android.content.Context;
// ...
TelephonyManager telephonyManager;
telephonyManager = (TelephonyManager) getSystemService(Context.
TELEPHONY_SERVICE);
/*
* getDeviceId() returns the unique device ID.
* For example,the IMEI for GSM and the MEID or ESN for CDMA phones.
*/
String deviceId = telephonyManager.getDeviceId();
/*
* getSubscriberId() returns the unique subscriber ID,
*/
String subscriberId = telephonyManager.getSubscriberId();
Buning uchun foydalanuvchingizdan android.permission.READ_PHONE_STATE
talab qilinadi, bu siz yaratgan ilova turiga qarab oqlash qiyin bo'lishi mumkin.
Planshetlar kabi telefoniya xizmatlariga ega bo‘lmagan qurilmalar Android 2.3 Gingerbread’dan beri
android.os.Build.SERIAL
orqali mavjud bo‘lgan noyob qurilma identifikatorini bildirishi kerak. Telefoniya xizmatlariga ega bo'lgan ba'zi telefonlar seriya raqamini ham belgilashi mumkin. Barcha Android qurilmalari seriya raqamiga ega emasligi kabi, bu yechim ishonchli emas.Qurilmaning birinchi yuklanishida tasodifiy qiymat hosil qilinadi va saqlanadi. Bu qiymat
Settings.Secure.ANDROID_ID
orqali mavjud. Bu 64 bitli raqam bo'lib, u qurilmaning ishlash muddati davomida doimiy bo'lib qolishi kerak.ANDROID_ID
noyob qurilma identifikatori uchun yaxshi tanlov ko'rinadi, chunki u smartfon va planshetlar uchun mavjud. Qiymatni olish uchun siz quyidagi koddan foydalanishingiz mumkin:String androidId = Settings.Secure.getString(getContentResolver(), Settings.Secure.ANDROID_ID);
Biroq, agar qurilmada zavod sozlamalari o'zgartirilsa, qiymat o'zgarishi mumkin. Bundan tashqari, ishlab chiqaruvchining mashhur telefonida ma'lum xatolik mavjud bo'lib, har bir nusxada bir xil ANDROID_ID
mavjud. Shubhasiz, yechim 100% ishonchli emas.
- UUID dan foydalaning. Ko'pgina ilovalar uchun talab jismoniy qurilma emas, balki ma'lum bir o'rnatishni aniqlash bo'lgani uchun, agar UUID sinfidan foydalansa, foydalanuvchi uchun noyob identifikatorni olish uchun yaxshi yechim. Quyidagi yechim Google kompaniyasidan Reto Meier tomonidan Google I/O taqdimotida taqdim etilgan,
SharedPreferences sharedPrefs = context.getSharedPreferences(
PREF_UNIQUE_ID, Context.MODE_PRIVATE);
uniqueID = sharedPrefs.getString(PREF_UNIQUE_ID, null);
Yangilanish : #1 va #2 opsiyalari google tomonidan maxfiylik yangilanishi sifatida Android 10-dan keyin endi mavjud emas. chunki 2 va 3 variant muhim ruxsatni talab qiladi.
DeviceInfoProvider
bu Android SDK qismi emas
- person user924; 06.02.2020
Android qurilmasi mac identifikatori ham noyob identifikator hisoblanadi. Qurilmaning o'zi formatlangan bo'lsa ham, u o'zgarmaydi.
Mac identifikatorini olish uchun quyidagi koddan foydalaning:
WifiManager manager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
WifiInfo info = manager.getConnectionInfo();
String address = info.getMacAddress();
Shuningdek, AndroidManifest.xml faylingizga tegishli ruxsatnomalarni qo‘shishni unutmang:
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
O'qiyotgan har bir kishi uchun eng so'nggi ma'lumotni qidirib toping. Android O bilan tizim ushbu identifikatorlarni qanday boshqarishi bo'yicha ba'zi o'zgarishlar mavjud.
https://android-developers.googleblog.com/2017/04/changes-to-device-identifiers-in.html
tl;dr Serial PHONE ruxsatini talab qiladi va Android identifikatori paket nomi va imzosiga qarab turli ilovalar uchun o'zgaradi.
Shuningdek, Google apparat va dasturiy ta'minot identifikatorlaridan qachon foydalanish bo'yicha takliflarni taqdim etadigan yaxshi hujjat tuzdi.
https://developer.android.com/training/articles/user-data-ids.html
Odatda ilovalarim uchun qurilmaning noyob identifikatoridan foydalanaman. Lekin ba'zida men IMEI-dan foydalanaman. Ikkalasi ham noyob raqamlar.
IMEI (xalqaro mobil uskunalar identifikatori) olish uchun
public String getIMEI(Activity activity) {
TelephonyManager telephonyManager = (TelephonyManager) activity
.getSystemService(Context.TELEPHONY_SERVICE);
return telephonyManager.getDeviceId();
}
qurilma noyob identifikatorini olish uchun
public String getDeviceUniqueID(Activity activity){
String device_unique_id = Secure.getString(activity.getContentResolver(),
Secure.ANDROID_ID);
return device_unique_id;
}
Men bu savolga bir necha yil oldin duch kelganman va turli javoblar asosida umumlashtirilgan yechimni amalga oshirishni o'rgandim.
Men umumlashtirilgan yechimni bir necha yil davomida haqiqiy mahsulotda ishlatganman. Hozirgacha bu menga juda yaxshi xizmat qilmoqda. Turli xil javoblarga asoslangan kod parchasi.
E'tibor bering, getEmail
ko'pincha null qiymatini qaytaradi, chunki biz aniq ruxsat so'ramaganmiz.
private static UniqueId getUniqueId() {
MyApplication app = MyApplication.instance();
// Our prefered method of obtaining unique id in the following order.
// (1) Advertising id
// (2) Email
// (2) ANDROID_ID
// (3) Instance ID - new id value, when reinstall the app.
////////////////////////////////////////////////////////////////////////////////////////////
// ADVERTISING ID
////////////////////////////////////////////////////////////////////////////////////////////
AdvertisingIdClient.Info adInfo = null;
try {
adInfo = AdvertisingIdClient.getAdvertisingIdInfo(app);
} catch (IOException e) {
Log.e(TAG, "", e);
} catch (GooglePlayServicesNotAvailableException e) {
Log.e(TAG, "", e);
} catch (GooglePlayServicesRepairableException e) {
Log.e(TAG, "", e);
}
if (adInfo != null) {
String aid = adInfo.getId();
if (!Utils.isNullOrEmpty(aid)) {
return UniqueId.newInstance(aid, UniqueId.Type.aid);
}
}
////////////////////////////////////////////////////////////////////////////////////////////
// EMAIL
////////////////////////////////////////////////////////////////////////////////////////////
final String email = Utils.getEmail();
if (!Utils.isNullOrEmpty(email)) {
return UniqueId.newInstance(email, UniqueId.Type.eid);
}
////////////////////////////////////////////////////////////////////////////////////////////
// ANDROID ID
////////////////////////////////////////////////////////////////////////////////////////////
final String sid = Settings.Secure.getString(app.getContentResolver(), Settings.Secure.ANDROID_ID);
if (!Utils.isNullOrEmpty(sid)) {
return UniqueId.newInstance(sid, UniqueId.Type.sid);
}
////////////////////////////////////////////////////////////////////////////////////////////
// INSTANCE ID
////////////////////////////////////////////////////////////////////////////////////////////
final String iid = com.google.android.gms.iid.InstanceID.getInstance(MyApplication.instance()).getId();
if (!Utils.isNullOrEmpty(iid)) {
return UniqueId.newInstance(iid, UniqueId.Type.iid);
}
return null;
}
public final class UniqueId implements Parcelable {
public enum Type implements Parcelable {
aid,
sid,
iid,
eid;
////////////////////////////////////////////////////////////////////////////
// Handling Parcelable nicely.
public static final Parcelable.Creator<Type> CREATOR = new Parcelable.Creator<Type>() {
public Type createFromParcel(Parcel in) {
return Type.valueOf(in.readString());
}
public Type[] newArray(int size) {
return new Type[size];
}
};
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel parcel, int flags) {
parcel.writeString(this.name());
}
// Handling Parcelable nicely.
////////////////////////////////////////////////////////////////////////////
}
public static boolean isValid(UniqueId uniqueId) {
if (uniqueId == null) {
return false;
}
return uniqueId.isValid();
}
private boolean isValid() {
return !org.yccheok.jstock.gui.Utils.isNullOrEmpty(id) && type != null;
}
private UniqueId(String id, Type type) {
if (org.yccheok.jstock.gui.Utils.isNullOrEmpty(id) || type == null) {
throw new java.lang.IllegalArgumentException();
}
this.id = id;
this.type = type;
}
public static UniqueId newInstance(String id, Type type) {
return new UniqueId(id, type);
}
@Override
public int hashCode() {
int result = 17;
result = 31 * result + id.hashCode();
result = 31 * result + type.hashCode();
return result;
}
@Override
public boolean equals(Object o) {
if (o == this) {
return true;
}
if (!(o instanceof UniqueId)) {
return false;
}
UniqueId uniqueId = (UniqueId)o;
return this.id.equals(uniqueId.id) && this.type == uniqueId.type;
}
@Override
public String toString() {
return type + ":" + id;
}
////////////////////////////////////////////////////////////////////////////
// Handling Parcelable nicely.
public static final Parcelable.Creator<UniqueId> CREATOR = new Parcelable.Creator<UniqueId>() {
public UniqueId createFromParcel(Parcel in) {
return new UniqueId(in);
}
public UniqueId[] newArray(int size) {
return new UniqueId[size];
}
};
private UniqueId(Parcel in) {
this.id = in.readString();
this.type = in.readParcelable(Type.class.getClassLoader());
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel parcel, int flags) {
parcel.writeString(this.id);
parcel.writeParcelable(this.type, 0);
}
// Handling Parcelable nicely.
////////////////////////////////////////////////////////////////////////////
public final String id;
public final Type type;
}
public static String getEmail() {
Pattern emailPattern = Patterns.EMAIL_ADDRESS; // API level 8+
AccountManager accountManager = AccountManager.get(MyApplication.instance());
Account[] accounts = accountManager.getAccountsByType("com.google");
for (Account account : accounts) {
if (emailPattern.matcher(account.name).matches()) {
String possibleEmail = account.name;
return possibleEmail;
}
}
accounts = accountManager.getAccounts();
for (Account account : accounts) {
if (emailPattern.matcher(account.name).matches()) {
String possibleEmail = account.name;
return possibleEmail;
}
}
return null;
}
DeviceId sifatida tavsiya etilmaydi, uchinchi tomon qo'llarida kuzatuv sifatida ishlatilishi mumkin, ammo bu boshqa usul.
@SuppressLint("HardwareIds")
private String getDeviceID() {
deviceId = Settings.Secure.getString(getApplicationContext().getContentResolver(),
Settings.Secure.ANDROID_ID);
return deviceId;
}
Mana, AAID olish uchun oddiy javob, 2019-yil iyun oyida toʻgʻri ishlagan
AsyncTask<Void, Void, String> task = new AsyncTask<Void, Void, String>() {
@Override
protected String doInBackground(Void... params) {
String token = null;
Info adInfo = null;
try {
adInfo = AdvertisingIdClient.getAdvertisingIdInfo(getApplicationContext());
} catch (IOException e) {
// ...
} catch ( GooglePlayServicesRepairableException e) {
// ...
} catch (GooglePlayServicesNotAvailableException e) {
// ...
}
String android_id = adInfo.getId();
Log.d("DEVICE_ID",android_id);
return android_id;
}
@Override
protected void onPostExecute(String token) {
Log.i(TAG, "DEVICE_ID Access token retrieved:" + token);
}
};
task.execute();
to'liq javobni batafsil o'qing bu yerda:
Quyidagi funksiya yordamida Device UUID, brend nomi bilan model raqami va uning versiya raqamini oling.
Android 10 da mukammal ishlaydi va telefon holatini oʻqishga ruxsat berish shart emas.
Kod parchalari:
private void fetchDeviceInfo() {
String uniquePseudoID = "35" +
Build.BOARD.length() % 10 +
Build.BRAND.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 serial = Build.getRadioVersion();
String uuid=new UUID(uniquePseudoID.hashCode(), serial.hashCode()).toString();
String brand=Build.BRAND;
String modelno=Build.MODEL;
String version=Build.VERSION.RELEASE;
Log.e(TAG, "fetchDeviceInfo: \n "+
"\n uuid is : "+uuid+
"\n brand is: "+brand+
"\n model is: "+modelno+
"\n version is: "+version);
}
Yuqoridagi qo'ng'iroq funksiyasi va yuqoridagi kodning chiqishini tekshirish uchun. Iltimos, android studiodagi jurnalga kiruvchi mushukingizni ko'ring. Bu quyida ko'rinadi:
Android 9ni qo'shish uchun menda (ehtimol) hech qanday shartlarni buzmaydigan, ruxsat talab qiladigan va o'rnatish va ilovalarda ishlashi mumkin bo'lgan faqat bitta fikr bor.
Server ishtirokidagi barmoq izi qurilmani noyob tarzda aniqlay olishi kerak. Uskuna ma'lumotlari + o'rnatilgan ilovalar va o'rnatish vaqtlarining kombinatsiyasi yordam berishi kerak. Ilova oʻchirilmasa va qayta oʻrnatilmasa, birinchi oʻrnatish vaqtlari oʻzgarmaydi. Ammo bu qurilmani aniqlab bo'lmasligi uchun (ya'ni zavod sozlamalarini tiklashdan keyin) qurilmadagi barcha ilovalar uchun bajarilishi kerak.
Men bu borada shunday yo'l tutgan bo'lardim:
- Uskuna ma'lumotlarini, ilovalar paketi nomlarini va birinchi o'rnatish vaqtlarini chiqarib oling.
Android-dan barcha ilovalarni shu tarzda chiqarasiz (ruxsat shart emas):
final PackageManager pm = application.getPackageManager();
List<ApplicationInfo> packages =
pm.getInstalledApplications(PackageManager.GET_META_DATA);
for (ApplicationInfo packageInfo : packages) {
try {
Log.d(TAG, "Installed package :" + packageInfo.packageName);
Log.d(TAG, "Installed :" + pm.getPackageInfo(packageInfo.packageName, 0).firstInstallTime);
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
}
- Siz uni serverga yuborishdan oldin har bir paket nomi va oʻrnatish vaqt tamgʻasi kombinatsiyasidan xeshni yasashni xohlashingiz mumkin, chunki u foydalanuvchi qurilmaga oʻrnatgan biznesingiz boʻlishi mumkin yoki boʻlmasligi mumkin.
- Ba'zi ilovalar (aslida juda ko'p) tizim ilovalari. Ular zavod sozlamalariga qaytarilgandan so'ng oxirgi tizim yangilanishiga mos keladigan bir xil o'rnatish vaqt tamg'asiga ega bo'lishi mumkin. Ular bir xil o'rnatish vaqt belgisiga ega bo'lgani uchun ularni foydalanuvchi o'rnatib bo'lmaydi va ularni filtrlash mumkin.
- Ma'lumotni serverga yuboring va unga avval saqlangan ma'lumotlar orasida eng yaqin moslikni izlashga ruxsat bering. Ilovalar oʻrnatilgan va oʻchirilganda, avval saqlangan qurilma maʼlumotlari bilan solishtirganda chegara qoʻyishingiz kerak. Ammo mening taxminimcha, bu chegara juda past bo'lishi mumkin, chunki har qanday paket nomi va birinchi marta o'rnatish vaqt tamg'asi kombinatsiyasi faqat qurilma uchun juda noyob bo'ladi va ilovalar tez-tez o'rnatilmaydi va o'chirilmaydi. Bir nechta ilovalarga ega bo'lish noyob bo'lish ehtimolini oshiradi.
- Oʻyin uchun yaratilgan noyob identifikatorni qaytaring yoki noyob identifikatorni yarating, qurilma maʼlumotlarini saqlang va ushbu yangi identifikatorni qaytaring.
E'tibor bering: Bu sinovdan o'tmagan va isbotlanmagan usul! Ishonchim komilki, bu ishlaydi, lekin agar bu davom etsa, ular uni u yoki bu tarzda yopishlariga ishonchim komil.
Agar siz qo'shsangiz:
Settings.Secure.getString(context.contentResolver,
Settings.Secure.ANDROID_ID)
Android Lint sizga quyidagi ogohlantirishni beradi:
Qurilma identifikatorlarini olish uchun getString dan foydalanish tavsiya etilmaydi. Tekshiruv haqida ma'lumot: Ushbu qurilma identifikatorlaridan foydalanish yuqori qiymatli firibgarlikning oldini olish va telefoniyadan foydalanishning ilg'or holatlaridan tashqari tavsiya etilmaydi. Reklamadan foydalanish holatlari uchun AdvertisingIdClient$Info#getId va tahlillar uchun InstanceId#getId dan foydalaning.
Shunday ekan, buni ishlatishdan qochishingiz kerak.
Android dasturchi hujjatlarida aytib o'tilganidek :
1: Uskuna identifikatorlaridan foydalanishdan saqlaning.
Aksariyat hollarda siz SSAID (Android ID) va IMEI kabi apparat identifikatorlaridan kerakli funksiyalarni cheklamasdan foydalanishdan qochishingiz mumkin.
2: Foydalanuvchi profili yoki reklamalardan foydalanish holatlari uchun faqat reklama identifikatoridan foydalaning.
Reklama identifikatoridan foydalanganda har doim foydalanuvchilarning reklama kuzatuviga oid tanlovlarini hurmat qiling. Shuningdek, identifikatorni shaxsni identifikatsiya qiluvchi maʼlumotlarga (PII) ulab boʻlmasligiga ishonch hosil qiling va Reklama identifikatori sozlamalarini tiklashdan saqlaning.
3: Toʻlovlarni firibgarlikning oldini olish va telefoniyadan tashqari, iloji boricha boshqa barcha foydalanish holatlari uchun Instance ID yoki shaxsiy saqlangan GUID dan foydalaning.
Reklamasiz foydalanish holatlarining aksariyati uchun Instance ID yoki GUID etarli bo'lishi kerak.
4: Maxfiylik xavfini minimallashtirish uchun foydalanish holatlaringizga mos API-lardan foydalaning.
Yuqori qiymatli kontentni himoya qilish uchun DRM API va suiiste'moldan himoya qilish uchun SafetyNet API'laridan foydalaning. SafetyNet API'lari maxfiylikka xavf tug'dirmasdan qurilmaning haqiqiyligini aniqlashning eng oson yo'lidir.
String SERIAL_NUMER = Build.SERIAL;
SERIAL NUMBER ni har bir qurilmada noyob bo'lgan qator sifatida qaytaradi.
Seriya raqami - bu android.os.Build.SERIAL orqali mavjud bo'lgan noyob qurilma identifikatoridir.
public static String getSerial() {
String serial = "";
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){
serial = Build.getSerial();
}else{
serial = Build.SERIAL;
}
return serial;
}
getSerial() ga qo‘ng‘iroq qilishdan oldin READ_PHONE_STATE ruxsatiga ega ekanligingizga ishonch hosil qiling.
QAYD:- Bu Telefoniyasiz qurilmalarda ishlamaydi (masalan, faqat Wi-Fi planshetlari).
Build.SERIAL
(yoki Build.getSerial()
) har doim ham mavjud emasligini ko'rsatadi. Batafsil ma'lumotni blog postida topishingiz mumkin O'zgartirishlar Android Oda qurilma identifikatorlari. Shuningdek, o‘qishga arziydi: Noyob identifikatorlar bo‘yicha eng yaxshi amaliyotlar.
- person Ted Hopp; 14.12.2017
To'liqlik uchun Xamarin.Android
va C# da Id
ni qanday qilib olishingiz mumkin:
var id = Settings.Secure.GetString(ContentResolver, Settings.Secure.AndroidId);
Yoki Activity
ichida bo'lmasangiz:
var id = Settings.Secure.GetString(context.ContentResolver, Settings.Secure.AndroidId);
Bu erda context
kontekstda uzatilgan.
android.telephony.TelephonyManager.getDeviceId()
Bu qurilmani noyob tarzda identifikatsiya qiladigan har qanday satrni qaytaradi (GSM da IMEI, CDMA uchun MEID).
AndroidManifest.xml faylida sizga quyidagi ruxsat kerak boʻladi:
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
Ha, har bir Android qurilmasi noyob seriya raqamlariga ega, uni ushbu koddan olishingiz mumkin. Build.SERIAL
. E'tibor bering, u faqat API 9-darajasida qo'shilgan va u barcha qurilmalarda mavjud bo'lmasligi mumkin. Oldingi platformalarda noyob identifikatorni olish uchun siz MAC manzili yoki IMEI kabi narsalarni o'qishingiz kerak bo'ladi.
SystemInfo.deviceUniqueIdentifier-ni tekshiring
Hujjatlar: http://docs.unity3d.com/Documentation/ScriptReference/SystemInfo-deviceUniqueIdentifier.html
Noyob qurilma identifikatori. Har bir qurilma uchun noyob bo'lishi kafolatlangan (Faqat o'qish).
iOS: iOS7-dan oldingi qurilmalarda u MAC manzilining xeshini qaytaradi. iOS7 qurilmalarida u UIDevice identifierForVendor yoki biron sababga ko'ra muvaffaqiyatsiz bo'lsa, ASIdentifierManager advertisingIdentifier bo'ladi.
Qurilma identifikatorini faqat bir marta oling va keyin uni ma'lumotlar bazasida yoki faylda saqlang. Bunday holda, agar u ilovaning birinchi yuklanishi bo'lsa, u identifikatorni yaratadi va uni saqlaydi. Keyingi safar u faqat faylda saqlangan identifikatorni oladi.
Foydalanuvchi identifikatorini olish uchun siz Google Play Litsenziyalash kutubxonasidan foydalanishingiz mumkin.
Ushbu kutubxonani yuklab olish uchun SDK Manager => SDK Tools-ni oching. Yuklab olingan kutubxona fayllariga yo'l:
path_to_android_sdk_on_your_pc/extras/google/market_licensing/library
Kutubxonani loyihangizga qo'shing (uning fayllarini shunchaki nusxalashingiz mumkin).
Keyin sizga Policy
interfeysini bir oz amalga oshirish kerak (siz shunchaki kutubxonadagi ikkita fayldan birini ishlatishingiz mumkin: ServerManagedPolicy
yoki StrictPolicy
).
Foydalanuvchi identifikatori processServerResponse()
funksiyasi ichida sizga taqdim etiladi:
public void processServerResponse(int response, ResponseData rawData) {
if(rawData != null) {
String userId = rawData.userId
// use/save the value
}
// ...
}
Keyin LicenseChecker
ni siyosat bilan qurishingiz va checkAccess()
funksiyasini chaqirishingiz kerak. Buni qanday qilish kerakligiga misol sifatida MainActivity.java
dan foydalaning. MainActivity.java
ushbu jild ichida joylashgan:
path_to_android_sdk_on_your_pc/extras/google/market_licensing/sample/src/com/example/android/market/licensing
AndroidManifest.xml faylingizga CHECK_LICENSE ruxsatini qo‘shishni unutmang.
Litsenziyalash kutubxonasi haqida batafsil: https://developer.android.com/google/play/licensing
Android Android O dan keyin apparat bilan bog'liq identifikatorni cheklaydi, shuning uchun Android_Id noyob identifikator uchun yechimdir, lekin qurilma reflektor paytida muammo yuzaga keladi, bu muammoni bartaraf etish uchun yangi android_id hosil qiladi, biz DRUMIDdan foydalanishimiz mumkin.
val WIDEVINE_UUID = UUID(-0x121074568629b532L, -0x5c37d8232ae2de13L)
val drumIDByteArray = MediaDrm(WIDEVINE_UUID).getPropertyByteArray(MediaDrm.PROPERTY_DEVICE_UNIQUE_ID)
val drumID = android.util.Base64.encodeToString(drumIDByteArray,android.util.Base64.DEFAULT)
Wi-Fi-ga ulanishga harakat qilganingizda tasodifiy manzildan foydalanganingiz yoki ishlatmaganligingizdan va Wi-Fi yoqilgan yoki o'chirilganligidan qat'i nazar, quyidagi kod yordamida Wi-Fi mac manzilini olasiz.
Men quyidagi havoladagi usuldan foydalandim va tasodifiy manzil o'rniga aniq manzilni olish uchun kichik o'zgartirish qo'shdim:
Android 6.0 da MAC manzilini olish
public static String getMacAddr() {
StringBuilder res1 = new StringBuilder();
try {
List<NetworkInterface> all =
Collections.list(NetworkInterface.getNetworkInterfaces());
for (NetworkInterface nif : all) {
if (!nif.getName().equalsIgnoreCase("p2p0")) continue;
byte[] macBytes = nif.getHardwareAddress();
if (macBytes == null) {
continue;
}
res1 = new StringBuilder();
for (byte b : macBytes) {
res1.append(String.format("%02X:",b));
}
if (res1.length() > 0) {
res1.deleteCharAt(res1.length() - 1);
}
}
} catch (Exception ex) {
}
return res1.toString();
}
ANDROID_ID
dan foydalanayotgan bo‘lsangiz, ushbu javobni va . - person Dheeraj Vepakomma   schedule 16.01.2013