Bir Android uygulaması için benzersiz bir kimlik kullanmam gerekiyor ve cihazın seri numarasının iyi bir aday olacağını düşündüm. Uygulamamdaki bir Android cihazın seri numarasını nasıl alırım?
Bir Android uygulaması için benzersiz bir kimlik kullanmam gerekiyor ve cihazın seri numarasının iyi bir aday olacağını düşündüm. Uygulamamdaki bir Android cihazın seri numarasını nasıl alırım?
Yanıtlar:
TelephonyManager tManager = (TelephonyManager)myActivity.getSystemService(Context.TELEPHONY_SERVICE);
String uid = tManager.getDeviceId();
getSystemService, Activity sınıfından bir yöntemdir. getDeviceID (), telefonun kullandığı radyoya (GSM veya CDMA) bağlı olarak cihazın MDN veya MEID bilgisini döndürür.
Her aygıt burada benzersiz bir değer döndürmelidir (bir telefon olduğu varsayılarak). Bu, sim yuvası veya CDMA radyosu olan herhangi bir Android cihaz için çalışmalıdır. Android destekli mikrodalga ile tek başınasın ;-)
Dave Webb'in bahsettiği gibi, Android Geliştirici Blogunda bunu kapsayan bir makale var.
Birkaç öğe hakkında ek açıklama almak için Google'dan biriyle görüştüm. Yukarıda bahsedilen blog gönderisinde bahsedilmediğini keşfettiğim şey:
Google'ın önerilerine dayanarak, her cihaz için benzersiz bir UUID oluşturacak bir sınıf uyguladım, uygun olduğunda tohum olarak ANDROID_ID'yi kullanarak TelephonyManager.getDeviceId () 'e geri döndüm ve bu başarısız olursa rastgele oluşturulmuş benzersiz bir UUID'ye başvurdum bu, uygulama yeniden başlatılırken kalıcıdır (ancak uygulama yeniden yüklemelerinde kalmaz).
import android.content.Context;
import android.content.SharedPreferences;
import android.provider.Settings.Secure;
import android.telephony.TelephonyManager;
import java.io.UnsupportedEncodingException;
import java.util.UUID;
public class DeviceUuidFactory {
protected static final String PREFS_FILE = "device_id.xml";
protected static final String PREFS_DEVICE_ID = "device_id";
protected static volatile UUID uuid;
public DeviceUuidFactory(Context context) {
if (uuid == null) {
synchronized (DeviceUuidFactory.class) {
if (uuid == null) {
final SharedPreferences prefs = context
.getSharedPreferences(PREFS_FILE, 0);
final String id = prefs.getString(PREFS_DEVICE_ID, null);
if (id != null) {
// Use the ids previously computed and stored in the
// prefs file
uuid = UUID.fromString(id);
} else {
final String androidId = Secure.getString(
context.getContentResolver(), Secure.ANDROID_ID);
// Use the Android ID unless it's broken, in which case
// fallback on deviceId,
// unless it's not available, then fallback on a random
// number which we store to a prefs file
try {
if (!"9774d56d682e549c".equals(androidId)) {
uuid = UUID.nameUUIDFromBytes(androidId
.getBytes("utf8"));
} else {
final String deviceId = ((TelephonyManager)
context.getSystemService(
Context.TELEPHONY_SERVICE))
.getDeviceId();
uuid = deviceId != null ? UUID
.nameUUIDFromBytes(deviceId
.getBytes("utf8")) : UUID
.randomUUID();
}
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
// Write the value out to the prefs file
prefs.edit()
.putString(PREFS_DEVICE_ID, uuid.toString())
.commit();
}
}
}
}
}
/**
* Returns a unique UUID for the current android device. As with all UUIDs,
* this unique ID is "very highly likely" to be unique across all Android
* devices. Much more so than ANDROID_ID is.
*
* The UUID is generated by using ANDROID_ID as the base key if appropriate,
* falling back on TelephonyManager.getDeviceID() if ANDROID_ID is known to
* be incorrect, and finally falling back on a random UUID that's persisted
* to SharedPreferences if getDeviceID() does not return a usable value.
*
* In some rare circumstances, this ID may change. In particular, if the
* device is factory reset a new device ID may be generated. In addition, if
* a user upgrades their phone from certain buggy implementations of Android
* 2.2 to a newer, non-buggy version of Android, the device ID may change.
* Or, if a user uninstalls your app on a device that has neither a proper
* Android ID nor a Device ID, this ID may change on reinstallation.
*
* Note that if the code falls back on using TelephonyManager.getDeviceId(),
* the resulting ID will NOT change after a factory reset. Something to be
* aware of.
*
* Works around a bug in Android 2.2 for many devices when using ANDROID_ID
* directly.
*
* @see http://code.google.com/p/android/issues/detail?id=10603
*
* @return a UUID that may be used to uniquely identify your device for most
* purposes.
*/
public UUID getDeviceUuid() {
return uuid;
}
}
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) {
}
Bu kod, gizli bir Android API kullanarak cihaz seri numarasını döndürür.
String deviceId = Settings.System.getString(getContentResolver(),
Settings.System.ANDROID_ID);
Bununla birlikte, Android kimliğinin benzersiz bir tanımlayıcı olacağı garanti edilmez.
getContentResolver
geri döndüğü null
. Ancak, bir soruyu açarken ve kodunuzu gönderirken buna değer olabilir.
Orada Android Geliştirici blog bu tartışmaya üzerinde mükemmel sonrası .
TelephonyManager.getDeviceId()
Tablet gibi telefon olmayan Android cihazlarda çalışmadığı için kullanılmamasını önerir ,READ_PHONE_STATE
izin ve tüm telefonlarda güvenilir bir şekilde .
Bunun yerine aşağıdakilerden birini kullanabilirsiniz:
Gönderi, her birinin artılarını ve eksilerini tartışıyor ve okumaya değer, böylece kullanımınız için hangisinin en iyisi olduğunu anlayabilirsiniz.
Cihaza özgü ve kullanım ömrü boyunca sabit olan (fabrika ayarlarına sıfırlama veya bilgisayar korsanlığı dışında) basit bir numara için Settings.Secure.ANDROID_ID öğesini kullanın .
String id = Secure.getString(getContentResolver(), Secure.ANDROID_ID);
Varsa cihaz seri numarasını ("Sistem Ayarları / Hakkında / Durum" bölümünde gösterilen) kullanmak ve Android Kimliğine geri dönmek için:
String serialNumber = Build.SERIAL != Build.UNKNOWN ? Build.SERIAL : Secure.getString(getContentResolver(), Secure.ANDROID_ID);
IMEI iyidir, ancak yalnızca telefonlu Android cihazlarda çalışır. Telefon içermeyen Tabletler veya diğer Android cihazlar için desteği de düşünmelisiniz.
Aşağıdakiler gibi bazı alternatifleriniz var: Derleme sınıfı üyeleri, BT MAC, WLAN MAC veya daha iyisi - tüm bunların bir kombinasyonu.
Bu ayrıntıları blogumdaki bir makalede açıkladım, bkz: http://www.pocketmagic.net/?p=1662
Yana hiçbir cevap burada mükemmel bahseder, tedbirli sistem güncellemeleri yoluyla PERSİSTAN olduğundan hem de TÜM cihazlarda mevcut kimliği (özellikle nedeniyle Google'dan bireysel bir çözüm olmadığı gerçeği için), bir yöntem sonrası karar bir sonraki en iyi şey, mevcut tanımlayıcılardan ikisini birleştirerek ve çalışma zamanında bunlar arasında seçim yapmak için bir kontrol.
Kodlamadan önce 3 gerçek:
TelephonyManager.getDeviceId()
(akaIMEI), GSM dışı, 3G, LTE vb. cihazlar için iyi veya hiç çalışmayacaktır, ancak ilgili donanım mevcut olduğunda, SIM takılı olmadığında veya SIM yuvası olmadığında bile her zaman benzersiz bir kimlik döndürecektir ( bazı OEM'ler bunu yaptı).
Gingerbread (Android 2.3) android.os.Build.SERIAL
, IMEI sağlamayan herhangi bir cihazda bulunması gerektiğinden , yani Android politikasına göre yukarıda belirtilen donanıma sahip değildir.
Durum (2.) nedeniyle , bu iki benzersiz tanımlayıcıdan en az biri HER ZAMAN mevcut olacak ve SERIAL , IMEI ile aynı anda mevcut olabilir .
Not: Gerçek (1.) ve (2.) Google ifadelerine dayanmaktadır
ÇÖZÜM
Yukarıdaki gerçeklerle, IMEI'ye bağlı donanım olup olmadığını kontrol ederek her zaman benzersiz bir tanımlayıcıya sahip olabilir ve mevcut SERIAL'in geçerli olup olmadığını kontrol edemeyeceğinden, olmadığı zaman SERIAL'e geri dönülebilir. Aşağıdaki statik sınıf, bu tür bir varlığı denetlemek ve IMEI veya SERIAL kullanmak için 2 yöntem sunar:
import java.lang.reflect.Method;
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.Build;
import android.provider.Settings;
import android.telephony.TelephonyManager;
import android.util.Log;
public class IDManagement {
public static String getCleartextID_SIMCHECK (Context mContext){
String ret = "";
TelephonyManager telMgr = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
if(isSIMAvailable(mContext,telMgr)){
Log.i("DEVICE UNIQUE IDENTIFIER",telMgr.getDeviceId());
return telMgr.getDeviceId();
}
else{
Log.i("DEVICE UNIQUE IDENTIFIER", Settings.Secure.ANDROID_ID);
// return Settings.Secure.ANDROID_ID;
return android.os.Build.SERIAL;
}
}
public static String getCleartextID_HARDCHECK (Context mContext){
String ret = "";
TelephonyManager telMgr = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
if(telMgr != null && hasTelephony(mContext)){
Log.i("DEVICE UNIQUE IDENTIFIER",telMgr.getDeviceId() + "");
return telMgr.getDeviceId();
}
else{
Log.i("DEVICE UNIQUE IDENTIFIER", Settings.Secure.ANDROID_ID);
// return Settings.Secure.ANDROID_ID;
return android.os.Build.SERIAL;
}
}
public static boolean isSIMAvailable(Context mContext,
TelephonyManager telMgr){
int simState = telMgr.getSimState();
switch (simState) {
case TelephonyManager.SIM_STATE_ABSENT:
return false;
case TelephonyManager.SIM_STATE_NETWORK_LOCKED:
return false;
case TelephonyManager.SIM_STATE_PIN_REQUIRED:
return false;
case TelephonyManager.SIM_STATE_PUK_REQUIRED:
return false;
case TelephonyManager.SIM_STATE_READY:
return true;
case TelephonyManager.SIM_STATE_UNKNOWN:
return false;
default:
return false;
}
}
static public boolean hasTelephony(Context mContext)
{
TelephonyManager tm = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
if (tm == null)
return false;
//devices below are phones only
if (Build.VERSION.SDK_INT < 5)
return true;
PackageManager pm = mContext.getPackageManager();
if (pm == null)
return false;
boolean retval = false;
try
{
Class<?> [] parameters = new Class[1];
parameters[0] = String.class;
Method method = pm.getClass().getMethod("hasSystemFeature", parameters);
Object [] parm = new Object[1];
parm[0] = "android.hardware.telephony";
Object retValue = method.invoke(pm, parm);
if (retValue instanceof Boolean)
retval = ((Boolean) retValue).booleanValue();
else
retval = false;
}
catch (Exception e)
{
retval = false;
}
return retval;
}
}
Kullanmayı tavsiye ederim getCleartextID_HARDCHECK
. Yansıma çevrenize yapışmazsa,getCleartextID_SIMCHECK
bunun yerine yöntemi kullanın, ancak özel SIM varlığı ihtiyaçlarınıza göre uyarlanması gerektiğini dikkate alın.
Not : Lütfen OEM'lerin Google politikasına (aynı SERİ'ye sahip birden fazla cihaz) SERIAL'i engellemeyi başardığını ve Google'ın belirtildiği gibi, büyük bir OEM'de en az bir bilinen durum olduğunu (açıklanmadı ve hangi markayı bilmiyorum) ya, sanırım Samsung).
Feragatname : Bu, özgün bir cihaz kimliği alma sorusunu yanıtlar, ancak OP, bir APP için benzersiz bir kimliğe ihtiyaç duyduğunu belirterek belirsizlik yarattı. Bu tür senaryolar için Android_ID daha iyi olsa bile, bir uygulamanın 2 farklı ROM yüklemesi yoluyla bir Titanyum Yedeklemesinden sonra (aynı ROM bile olabilir) ÇALIŞMAYACAKTIR. Çözümüm, flaştan veya fabrika ayarlarına sıfırlamadan bağımsız kalıcılığı koruyor ve yalnızca IMEI veya SERİ kurcalama korsanlar / donanım modları aracılığıyla gerçekleştiğinde başarısız oluyor.
Yukarıdaki tüm yaklaşımlarla ilgili sorunlar var. Google i / o'da Reto Meier, buna nasıl yaklaşılacağına dair sağlam bir yanıt yayınladı. Bu yanıt, çoğu geliştiricinin kurulumlarda kullanıcıları izlemek için ihtiyaçlarını karşılamalıdır.
Bu yaklaşım size, kullanıcı için farklı cihazlarda (tabletler dahil, birincil Google hesabına dayalı) ve aynı cihazdaki yüklemelerde kalıcı olacak anonim, güvenli bir kullanıcı kimliği verecektir. Temel yaklaşım, rastgele bir kullanıcı kimliği oluşturmak ve bunu uygulamaların paylaşılan tercihlerinde saklamaktır. Ardından, Google hesabına bağlı paylaşılan tercihleri bulutta depolamak için Google'ın yedekleme aracısını kullanırsınız.
Tam yaklaşımı inceleyelim. Öncelikle, Android Yedekleme Hizmetini kullanarak Paylaşılan Tercihlerimiz için bir yedek oluşturmamız gerekiyor. Bu bağlantı yoluyla uygulamanızı kaydettirerek başlayın: http://developer.android.com/google/backup/signup.html
Google size bildirime eklemeniz gereken bir yedek hizmet anahtarı verecektir. Ayrıca, uygulamaya aşağıdaki gibi BackupAgent'ı kullanmasını söylemeniz gerekir:
<application android:label="MyApplication"
android:backupAgent="MyBackupAgent">
...
<meta-data android:name="com.google.android.backup.api_key"
android:value="your_backup_service_key" />
</application>
Ardından, yedekleme aracısını oluşturmanız ve ona, paylaşılan tercihler için yardımcı aracıyı kullanmasını söylemeniz gerekir:
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);
}
}
Yedeklemeyi tamamlamak için ana Etkinliğinizde bir BackupManager örneği oluşturmanız gerekir:
BackupManager backupManager = new BackupManager(context);
Son olarak, mevcut değilse bir kullanıcı kimliği oluşturun ve bunu SharedPreferences'da saklayın:
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;
}
Bu User_ID, kullanıcı cihazları değiştirse bile artık kurulumlarda kalıcı olacaktır.
Bu yaklaşım hakkında daha fazla bilgi için http://www.google.com/events/io/2011/sessions/android-protips-advanced-topics-for-expert-android-app-developers.html Reto'nun konuşmasına bakın
Yedekleme aracısının nasıl uygulanacağına ilişkin tüm ayrıntılar için geliştirici sitesine buradan bakın: http://developer.android.com/guide/topics/data/backup.html Yedeklemede olduğu gibi test etmek için en alttaki bölümü özellikle tavsiye ederim anında gerçekleşmez ve bu nedenle test etmek için yedeklemeyi zorlamanız gerekir.
Başka bir yol da / sys / class / android_usb / android0 / iSerial'ı herhangi bir izne sahip olmayan bir Uygulamada kullanmaktır.
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
Bunu java'da yapmak için, iSerial dosyasını açmak ve karakterleri okumak için sadece bir FileInputStream kullanılır. Sadece bir istisna işleyicisine sardığınızdan emin olun çünkü tüm cihazlarda bu dosya yoktur.
En azından aşağıdaki cihazların bu dosyanın herkes tarafından okunabilir olduğu bilinmektedir:
Blog gönderimi burada da görebilirsiniz: http://insitusec.blogspot.com/2013/01/leaking-android-hardware-serial-number.html , bilgi için başka hangi dosyaların mevcut olduğunu tartıştığım yer.
@Haserman'ın dediği gibi:
TelephonyManager tManager = (TelephonyManager)myActivity.getSystemService(Context.TELEPHONY_SERVICE);
String uid = tManager.getDeviceId();
Ancak, manifest dosyasındaki iznin dahil edilmesi gereklidir:
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
Dize olarak Android OS Cihazının benzersiz cihaz kimliği.
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);
}
ancak Google tarafından önerilen bu yöntemi şiddetle tavsiye ediyorum ::
Build.SERIAL
tamamen güvenilir olmasa da , boş olabileceği veya bazen cihazınızın ayarlarında görebildiğinizden farklı bir değer ( kanıt 1 , kanıt 2 ) döndürebileceği için en basit yoldur .
Cihazın üreticisine ve Android sürümüne bağlı olarak bu numarayı elde etmenin birkaç yolu vardır, bu yüzden bulabildiğim her olası çözümü tek bir özde derlemeye karar verdim . İşte bunun basitleştirilmiş bir versiyonu:
public static String getSerialNumber() {
String serialNumber;
try {
Class<?> c = Class.forName("android.os.SystemProperties");
Method get = c.getMethod("get", String.class);
serialNumber = (String) get.invoke(c, "gsm.sn1");
if (serialNumber.equals(""))
serialNumber = (String) get.invoke(c, "ril.serialnumber");
if (serialNumber.equals(""))
serialNumber = (String) get.invoke(c, "ro.serialno");
if (serialNumber.equals(""))
serialNumber = (String) get.invoke(c, "sys.serialnumber");
if (serialNumber.equals(""))
serialNumber = Build.SERIAL;
// If none of the methods above worked
if (serialNumber.equals(""))
serialNumber = null;
} catch (Exception e) {
e.printStackTrace();
serialNumber = null;
}
return serialNumber;
}
Bu sorunun eski olduğunu biliyorum ama bir satır kodla yapılabilir
String deviceID = Build.SERIAL;
Yukarıda @emmby tarafından yayınlanan örnek sınıfı harika bir başlangıç noktası olarak buldum. Ancak diğer afişlerde de belirtildiği gibi birkaç kusuru var. Bunlardan en önemlisi, UUID'yi gereksiz yere bir XML dosyasına devam ettirmesi ve daha sonra her zaman bu dosyadan almasıdır. Bu, sınıfı kolay bir saldırıya açık hale getirir: Rootlu bir telefonu olan herkes, kendilerine yeni bir UUID vermek için XML dosyasını düzenleyebilir.
Kodu, yalnızca kesinlikle gerekliyse (yani rastgele oluşturulmuş bir UUID kullanırken) XML'de kalması için güncelledim ve @Brill Pappin'in cevabına göre mantığı yeniden faktörlendirdim:
import android.content.Context;
import android.content.SharedPreferences;
import android.provider.Settings.Secure;
import android.telephony.TelephonyManager;
import java.io.UnsupportedEncodingException;
import java.util.UUID;
public class DeviceUuidFactory {
protected static final String PREFS_FILE = "device_id.xml";
protected static final String PREFS_DEVICE_ID = "device_id";
protected static UUID uuid;
public DeviceUuidFactory(Context context) {
if( uuid ==null ) {
synchronized (DeviceUuidFactory.class) {
if( uuid == null) {
final SharedPreferences prefs = context.getSharedPreferences( PREFS_FILE, 0);
final String id = prefs.getString(PREFS_DEVICE_ID, null );
if (id != null) {
// Use the ids previously computed and stored in the prefs file
uuid = UUID.fromString(id);
} else {
final String androidId = Secure.getString(context.getContentResolver(), Secure.ANDROID_ID);
// Use the Android ID unless it's broken, in which case fallback on deviceId,
// unless it's not available, then fallback on a random number which we store
// to a prefs file
try {
if ( "9774d56d682e549c".equals(androidId) || (androidId == null) ) {
final String deviceId = ((TelephonyManager) context.getSystemService( Context.TELEPHONY_SERVICE )).getDeviceId();
if (deviceId != null)
{
uuid = UUID.nameUUIDFromBytes(deviceId.getBytes("utf8"));
}
else
{
uuid = UUID.randomUUID();
// Write the value out to the prefs file so it persists
prefs.edit().putString(PREFS_DEVICE_ID, uuid.toString() ).commit();
}
}
else
{
uuid = UUID.nameUUIDFromBytes(androidId.getBytes("utf8"));
}
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
}
}
}
}
}
/**
* Returns a unique UUID for the current android device. As with all UUIDs, this unique ID is "very highly likely"
* to be unique across all Android devices. Much more so than ANDROID_ID is.
*
* The UUID is generated by using ANDROID_ID as the base key if appropriate, falling back on
* TelephonyManager.getDeviceID() if ANDROID_ID is known to be incorrect, and finally falling back
* on a random UUID that's persisted to SharedPreferences if getDeviceID() does not return a
* usable value.
*
* In some rare circumstances, this ID may change. In particular, if the device is factory reset a new device ID
* may be generated. In addition, if a user upgrades their phone from certain buggy implementations of Android 2.2
* to a newer, non-buggy version of Android, the device ID may change. Or, if a user uninstalls your app on
* a device that has neither a proper Android ID nor a Device ID, this ID may change on reinstallation.
*
* Note that if the code falls back on using TelephonyManager.getDeviceId(), the resulting ID will NOT
* change after a factory reset. Something to be aware of.
*
* Works around a bug in Android 2.2 for many devices when using ANDROID_ID directly.
*
* @see http://code.google.com/p/android/issues/detail?id=10603
*
* @return a UUID that may be used to uniquely identify your device for most purposes.
*/
public UUID getDeviceUuid() {
return uuid;
}
Evet. Bir cihaz donanım seri numarasıdır ve benzersizdir. Yani api 2.3 ve üzeri sürümlerde bunu elde etmek için android.os.Build.ANDROID_ID'yi kullanabilirsiniz . 2.3 API seviyesinin altında TelephonyManager.getDeviceID () kullanın .
bu http://android-developers.blogspot.in/2011/03/identifying-app-installations.html okuyabilirsiniz