Ich muss eine eindeutige ID für eine Android App verwenden, und ich dachte, die Seriennummer für das Gerät wäre ein guter Kandidat. Wie kann ich die Seriennummer einer Android Gerät in meiner App?
TelephonyManager tManager = (TelephonyManager)myActivity.getSystemService(Context.TELEPHONY_SERVICE);
String uid = tManager.getDeviceId();
getSystemService ist eine Methode aus der Activity-Klasse. getDeviceID () gibt die MDN oder MEID des Geräts zurück, je nachdem, welches Funkgerät das Telefon verwendet (GSM oder CDMA).
Jedes Gerät MUSS hier einen eindeutigen Wert zurückgeben (vorausgesetzt, es ist ein Telefon). Dies sollte für jedes Android Gerät mit einem Sim-Slot oder CDMA-Radio funktionieren. Mit dieser Android Mikrowelle bist du allein ;-)
Wie Dave Webb erwähnt, enthält das Android Developer Blog einen Artikel , der dies behandelt.
Ich habe mit jemandem bei Google gesprochen, um zusätzliche Informationen zu einigen Punkten zu erhalten. Folgendes habe ich entdeckt, das in dem oben genannten Blog-Beitrag NICHT erwähnt wird:
Auf der Grundlage der Empfehlungen von Google habe ich eine Klasse implementiert, die für jedes Gerät eine eindeutige UUID generiert. Dabei habe ich gegebenenfalls Android_ID als Ausgangswert verwendet und bei Bedarf auf TelephonyManager.getDeviceId () zurückgegriffen. Falls dies fehlschlägt, habe ich auf eine zufällig generierte eindeutige UUID zurückgegriffen Dies gilt auch für App-Neustarts (jedoch nicht für App-Neuinstallationen).
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) {
}
Dieser Code gibt die Seriennummer des Geräts mit einer versteckten Android API zurück.
String deviceId = Settings.System.getString(getContentResolver(),
Settings.System.Android_ID);
Es kann jedoch nicht garantiert werden, dass die Android ID eine eindeutige Kennung ist.
Es gibt ein ausgezeichneter Beitrag im Android Entwickler-Blog diskutiert dies .
Es wird davon abgeraten, TelephonyManager.getDeviceId()
zu verwenden, da dies nicht auf Android) Geräten funktioniert, die keine Telefone wie Tablets sind. READ_PHONE_STATE
Berechtigung und es funktioniert nicht auf allen Handys zuverlässig.
Stattdessen können Sie eines der folgenden verwenden:
In diesem Beitrag werden die Vor- und Nachteile der einzelnen Themen besprochen, und es lohnt sich, sie zu lesen, damit Sie herausfinden können, welche für Ihre Zwecke am besten geeignet sind.
Verwenden Sie Settings.Secure.Android_ID für eine einfache Nummer, die für das Gerät eindeutig und für die gesamte Lebensdauer konstant ist (außer bei einem Factory-Reset oder Hacking).
String id = Secure.getString(getContentResolver(), Secure.Android_ID);
Um die Seriennummer des Geräts zu verwenden (die unter "Systemeinstellungen/Info/Status" angezeigte) und auf Android ID:
String serialNumber = Build.SERIAL != Build.UNKNOWN ? Build.SERIAL : Secure.getString(getContentResolver(), Secure.Android_ID);
Die IMEI ist gut, funktioniert aber nur auf Android Geräten mit Telefon. Sie sollten in Betracht ziehen, Tablets oder andere Android Geräte zu unterstützen, die kein Telefon haben .
Sie haben einige Alternativen wie: Klassenmitglieder aufbauen, BT-MAC, WLAN-MAC oder noch besser - eine Kombination aus all diesen.
Ich habe diese Details in einem Artikel in meinem Blog erklärt, siehe: http://www.pocketmagic.net/?p=1662
Da keine Antwort erfolgt, wird hier eine perfekte, ausfallsichere ID erwähnt, die sowohl PERSISTENT durch Systemaktualisierungen ist als auch in ALLEN Geräten vorhanden ist (hauptsächlich aufgrund der Tatsache, dass dort Ich habe mich entschlossen, eine Methode zu veröffentlichen, die das nächstbeste ist, indem ich zwei der verfügbaren Bezeichner kombiniert und zur Laufzeit eine Auswahl getroffen habe.
Vor dem Code 3 Fakten:
TelephonyManager.getDeviceId()
(akaIMEI) funktioniert nicht gut oder überhaupt nicht für Nicht-GSM-, 3G-, LTE- usw. Geräte, aber gibt bei verwandter Hardware immer eine eindeutige ID zurück ist vorhanden , auch wenn keine SIM-Karte eingelegt ist oder wenn kein SIM-Steckplatz vorhanden ist (einige OEMs haben dies getan).
Seit Lebkuchen (Android 2.3) Android.os.Build.SERIAL
muss auf jedem Gerät vorhanden sein, das keine IMEI bereitstellt, dh die oben genannte Hardware ist nicht vorhanden, wie in Android Richtlinie.
Aufgrund der Tatsache (2.), , dass mindestens einer dieser beiden eindeutigen Bezeichner IMMER vorhanden ist und SERIAL . kann gleichzeitig mit IMEI vorhanden sein.
Hinweis: Fakt (1.) und (2.) sind basierend auf Google-Anweisungen
[~ # ~] Lösung [~ # ~]
Mit den obigen Fakten kann man immer eine eindeutige Kennung erhalten, indem man prüft, ob IMEI-gebundene Hardware vorhanden ist, und auf SERIAL zurückgreift, wenn dies nicht der Fall ist, da man nicht prüfen kann, ob die vorhandene SERIAL gültig ist. Die folgende statische Klasse enthält zwei Methoden zum Überprüfen des Vorhandenseins und Verwenden von IMEI oder SERIAL:
import Java.lang.reflect.Method;
import Android.content.Context;
import Android.content.pm.PackageManager;
import Android.os.Build;
import Android.provider.Settings;
import Android.telephony.TelephonyManager;
import Android.util.Log;
public class IDManagement {
public static String getCleartextID_SIMCHECK (Context mContext){
String ret = "";
TelephonyManager telMgr = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
if(isSIMAvailable(mContext,telMgr)){
Log.i("DEVICE UNIQUE IDENTIFIER",telMgr.getDeviceId());
return telMgr.getDeviceId();
}
else{
Log.i("DEVICE UNIQUE IDENTIFIER", Settings.Secure.Android_ID);
// return Settings.Secure.Android_ID;
return Android.os.Build.SERIAL;
}
}
public static String getCleartextID_HARDCHECK (Context mContext){
String ret = "";
TelephonyManager telMgr = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
if(telMgr != null && hasTelephony(mContext)){
Log.i("DEVICE UNIQUE IDENTIFIER",telMgr.getDeviceId() + "");
return telMgr.getDeviceId();
}
else{
Log.i("DEVICE UNIQUE IDENTIFIER", Settings.Secure.Android_ID);
// return Settings.Secure.Android_ID;
return Android.os.Build.SERIAL;
}
}
public static boolean isSIMAvailable(Context mContext,
TelephonyManager telMgr){
int simState = telMgr.getSimState();
switch (simState) {
case TelephonyManager.SIM_STATE_ABSENT:
return false;
case TelephonyManager.SIM_STATE_NETWORK_LOCKED:
return false;
case TelephonyManager.SIM_STATE_PIN_REQUIRED:
return false;
case TelephonyManager.SIM_STATE_PUK_REQUIRED:
return false;
case TelephonyManager.SIM_STATE_READY:
return true;
case TelephonyManager.SIM_STATE_UNKNOWN:
return false;
default:
return false;
}
}
static public boolean hasTelephony(Context mContext)
{
TelephonyManager tm = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
if (tm == null)
return false;
//devices below are phones only
if (Build.VERSION.SDK_INT < 5)
return true;
PackageManager pm = mContext.getPackageManager();
if (pm == null)
return false;
boolean retval = false;
try
{
Class<?> [] parameters = new Class[1];
parameters[0] = String.class;
Method method = pm.getClass().getMethod("hasSystemFeature", parameters);
Object [] parm = new Object[1];
parm[0] = "Android.hardware.telephony";
Object retValue = method.invoke(pm, parm);
if (retValue instanceof Boolean)
retval = ((Boolean) retValue).booleanValue();
else
retval = false;
}
catch (Exception e)
{
retval = false;
}
return retval;
}
}
Ich würde zur Verwendung von getCleartextID_HARDCHECK
. Wenn das Spiegelbild nicht in Ihrer Umgebung haftet, verwenden Sie das getCleartextID_SIMCHECK
-Methode, aber berücksichtigen Sie, dass sie an Ihre spezifischen SIM-Anwesenheitsanforderungen angepasst werden sollte.
PS : Bitte beachten Sie, dass OEMs es geschafft haben, SERIAL gegen die Google-Richtlinien auszuspielen (mehrere Geräte mit derselben SERIAL) und Google, wie angegeben, gibt es mindestens einen bekannten Fall bei einem großen OEM (nicht bekannt gegeben und ich weiß auch nicht, um welche Marke es sich handelt, ich vermute, Samsung).
Haftungsausschluss : Hiermit wird die ursprüngliche Frage nach einer eindeutigen Geräte-ID beantwortet. Das OP führte jedoch zu Unklarheiten, indem es angab, dass für eine APP eine eindeutige ID erforderlich ist. Auch wenn Android_ID für solche Szenarien besser wäre, FUNKTIONIERT es NICHT, nachdem beispielsweise eine Titanium-Sicherung einer App über 2 verschiedene ROM installiert wurde (kann sogar dasselbe ROM sein). Meine Lösung wird beibehalten Persistenz, die unabhängig von einem Flash oder Factory Reset ist und nur dann fehlschlägt, wenn IMEI- oder SERIAL-Manipulationen durch Hacks/Hardware-Mods auftreten.
Es gibt Probleme mit allen oben genannten Ansätzen. Bei Google i/o hat Reto Meier eine robuste Antwort auf diese Frage veröffentlicht, die den Anforderungen der meisten Entwickler entsprechen sollte, um Benutzer über Installationen hinweg zu verfolgen.
Durch diesen Ansatz erhalten Sie eine anonyme, sichere Benutzer-ID, die für den Benutzer auf verschiedenen Geräten (einschließlich Tablets, basierend auf dem primären Google-Konto) und bei Installationen auf demselben Gerät persistent ist. Der grundlegende Ansatz besteht darin, eine zufällige Benutzer-ID zu generieren und diese in den gemeinsamen Einstellungen der Apps zu speichern. Anschließend verwenden Sie den Sicherungsagenten von Google, um die mit dem Google-Konto verknüpften gemeinsamen Einstellungen in der Cloud zu speichern.
Lassen Sie uns den vollständigen Ansatz durchgehen. Zuerst müssen wir mithilfe des Android Backup Service ein Backup für unsere SharedPreferences erstellen. Beginnen Sie mit der Registrierung Ihrer App über diesen Link: http://developer.Android.com/google/ backup/signup.html
Google gibt Ihnen einen Sicherungsdienstschlüssel, den Sie dem Manifest hinzufügen müssen. Sie müssen die Anwendung auch folgendermaßen anweisen, den BackupAgent zu verwenden:
<application Android:label="MyApplication"
Android:backupAgent="MyBackupAgent">
...
<meta-data Android:name="com.google.Android.backup.api_key"
Android:value="your_backup_service_key" />
</application>
Anschließend müssen Sie den Sicherungsagenten erstellen und ihn anweisen, den Hilfsagenten für gemeinsame Einstellungen zu verwenden:
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);
}
}
Um die Sicherung abzuschließen, müssen Sie in Ihrer Hauptaktivität eine Instanz von BackupManager erstellen:
BackupManager backupManager = new BackupManager(context);
Erstellen Sie schließlich eine Benutzer-ID, falls diese noch nicht vorhanden ist, und speichern Sie sie in den SharedPreferences:
public static String getUserID(Context context) {
private static String uniqueID = null;
private static final String PREF_UNIQUE_ID = "PREF_UNIQUE_ID";
if (uniqueID == null) {
SharedPreferences sharedPrefs = context.getSharedPreferences(
MyBackupAgent.PREFS, Context.MODE_PRIVATE);
uniqueID = sharedPrefs.getString(PREF_UNIQUE_ID, null);
if (uniqueID == null) {
uniqueID = UUID.randomUUID().toString();
Editor editor = sharedPrefs.edit();
editor.putString(PREF_UNIQUE_ID, uniqueID);
editor.commit();
//backup the changes
BackupManager mBackupManager = new BackupManager(context);
mBackupManager.dataChanged();
}
}
return uniqueID;
}
Diese User_ID bleibt nun für alle Installationen erhalten, auch wenn der Benutzer das Gerät wechselt.
Weitere Informationen zu diesem Ansatz finden Sie in Retos Vortrag hier http://www.google.com/events/io/2011/sessions/Android-protips-advanced-topics-for-expert-Android-app-developers). html
Ausführliche Informationen zum Implementieren des Sicherungsagenten finden Sie auf der Entwickler-Website hier: http://developer.Android.com/guide/topics/data/backup.html Ich empfehle insbesondere den Abschnitt im Zum Testen müssen Sie die Sicherung erzwingen, da die Sicherung nicht sofort ausgeführt wird.
Eine andere Möglichkeit ist die Verwendung von/sys/class/Android_usb/Android0/iSerial in einer App ohne jegliche Berechtigungen.
[email protected]:~$ adb Shell ls -l /sys/class/Android_usb/Android0/iSerial
-rw-r--r-- root root 4096 2013-01-10 21:08 iSerial
[email protected]:~$ adb Shell cat /sys/class/Android_usb/Android0/iSerial
0A3CXXXXXXXXXX5
Um dies in Java zu tun, würde man einfach einen FileInputStream verwenden, um die iSerial-Datei zu öffnen und die Zeichen auszulesen. Stellen Sie nur sicher, dass Sie sie in einen Ausnahmehandler einbinden, da nicht alle Geräte über diese Datei verfügen.
Zumindest die folgenden Geräte sind dafür bekannt, dass diese Datei weltweit lesbar ist:
Sie können meinen Blog-Beitrag auch hier sehen: http://insitusec.blogspot.com/2013/01/leaking-Android-hardware-serial-number.html wo ich diskutiere, für welche anderen Dateien verfügbar sind Info.
Eindeutige Geräte-ID von Android OS Device as String.
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);
}
ich empfehle diese von Google vorgeschlagene Methode jedoch strikt:
Build.SERIAL
ist der einfachste Weg, obwohl nicht ganz zuverlässig, da kann leer sein oder manchmal einen anderen Wert zurückgeben ( Beweis 1 , Beweis 2 =) als das, was Sie in den Einstellungen Ihres Geräts sehen können.
Es gibt verschiedene Möglichkeiten, um diese Nummer zu ermitteln, je nach Hersteller des Geräts und Android Version). Daher habe ich beschlossen, jede mögliche Lösung in einem einzigen Gist zu kompilieren eine vereinfachte Version davon:
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;
}
Wie @haserman sagt:
TelephonyManager tManager = (TelephonyManager)myActivity.getSystemService(Context.TELEPHONY_SERVICE);
String uid = tManager.getDeviceId();
Es ist jedoch erforderlich, die Berechtigung in die Manifestdatei aufzunehmen:
<uses-permission Android:name="Android.permission.READ_PHONE_STATE"/>
Ich weiß, dass diese Frage alt ist, aber sie kann in einer Codezeile erfolgen
String deviceID = Build.SERIAL;