Androidアプリには一意のIDを使用する必要があり、デバイスのシリアル番号が適していると思いました。アプリでAndroidデバイスのシリアル番号を取得するにはどうすればよいですか?
Androidアプリには一意のIDを使用する必要があり、デバイスのシリアル番号が適していると思いました。アプリでAndroidデバイスのシリアル番号を取得するにはどうすればよいですか?
回答:
TelephonyManager tManager = (TelephonyManager)myActivity.getSystemService(Context.TELEPHONY_SERVICE);
String uid = tManager.getDeviceId();
getSystemServiceは、Activityクラスのメソッドです。getDeviceID()は、電話が使用する無線(GSMまたはCDMA)に応じて、デバイスのMDNまたはMEIDを返します。
各デバイスは、ここで一意の値を返す必要があります(電話であると想定)。これは、SIMスロットまたはCDMA無線を備えたAndroidデバイスで機能します。あなたは自分でAndroid搭載の電子レンジを使っています;-)
Dave Webbが言及しているように、Android開発者ブログにはこれをカバーする記事があります。
Googleの担当者と話し合って、いくつかの項目についてさらに説明を求めました。前述のブログの投稿に記載されていない、私が見つけたものは次のとおりです。
Googleの推奨事項に基づいて、必要に応じてANDROID_IDをシードとして使用し、必要に応じてTelephonyManager.getDeviceId()にフォールバックして、デバイスごとに一意のUUIDを生成するクラスを実装しました。失敗した場合は、ランダムに生成された一意のUUIDを使用しましたアプリの再起動後も保持されます(アプリの再インストールは不可)。
import android.content.Context;
import android.content.SharedPreferences;
import android.provider.Settings.Secure;
import android.telephony.TelephonyManager;
import java.io.UnsupportedEncodingException;
import java.util.UUID;
public class DeviceUuidFactory {
protected static final String PREFS_FILE = "device_id.xml";
protected static final String PREFS_DEVICE_ID = "device_id";
protected 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) {
}
このコードは、非表示のAndroid APIを使用してデバイスのシリアル番号を返します。
String deviceId = Settings.System.getString(getContentResolver(),
Settings.System.ANDROID_ID);
ただし、Android IDが一意の識別子になることは保証されていません。
getContentResolver
が戻ってくることnull
です。ただし、質問を開いてコードを投稿する間は価値があります。
これについては、Android開発者のブログに優れた投稿があります。
TelephonyManager.getDeviceId()
タブレットなどの電話以外のAndroidデバイスではREAD_PHONE_STATE
機能せず、許可が必要であり、すべての電話で確実に機能するわけではないため、使用しないことをお勧めします。
代わりに、次のいずれかを使用できます。
この記事では、それぞれの長所と短所について説明しているので、読むのに最適です。
デバイスに固有であり、デバイスの寿命が一定である単純な番号(工場出荷時のリセットまたはハッキングを除く)の場合は、Settings.Secure.ANDROID_IDを使用します。
String id = Secure.getString(getContentResolver(), Secure.ANDROID_ID);
利用可能な場合にデバイスのシリアル番号(「システム設定/バージョン情報/ステータス」に表示されているもの)を使用してAndroid IDにフォールバックするには:
String serialNumber = Build.SERIAL != Build.UNKNOWN ? Build.SERIAL : Secure.getString(getContentResolver(), Secure.ANDROID_ID);
IMEIは優れていますが、携帯電話を備えたAndroidデバイスでのみ機能します。タブレットなど、スマートフォンを持たないAndroidデバイスのサポートも検討する必要があります。
クラスメンバー、BT MAC、WLAN MAC、またはそれ以上-これらすべての組み合わせをビルドするなど、いくつかの選択肢があります。
これらの詳細については、ブログの記事で説明しています。http://www.pocketmagic.net/?p = 1662を参照して ください。
以来何の答えはここに完璧に言及していない、失敗プルーフシステムアップデートを通じてPERSISTENTの両方で、すべてのデバイスに存在するID(主としてGoogleからの個別のソリューションが存在しないという事実のために)、私はある方法を掲示することにしました2つの使用可能な識別子を組み合わせることによる次善の策、および実行時にそれらの間で選択するチェック。
コードの前に、3つの事実:
TelephonyManager.getDeviceId()
(akaIMEI)は、非GSM、3G、LTEなどのデバイスではうまく機能しないか、まったく機能しませんが、関連するハードウェアが存在する場合、SIMが挿入されていない場合やSIMスロットが存在しない場合でも、常に一意のIDを返します(一部のOEMはこれを行っています)。
Gingerbread(Android 2.3)android.os.Build.SERIAL
は、IMEIを提供しない、つまりAndroidポリシーに従って前述のハードウェアが存在しないデバイスに存在する必要があるためです。
事実(2.)により、これら2つの一意の識別子の少なくとも1つは常に存在し、SERIAL は IMEIと同時に存在できます。
注:事実(1.)および(2.)はGoogleの声明に基づいています
解決
上記の事実により、IMEIにバインドされたハードウェアがあるかどうかを確認することで一意の識別子を常に持つことができ、既存のSERIALが有効かどうかを確認できないため、ない場合はSERIALにフォールバックします。次の静的クラスは、そのような存在を確認し、IMEIまたはSERIALを使用するための2つのメソッドを示しています。
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;
}
}
の使用についてアドバイスしgetCleartextID_HARDCHECK
ます。反射が環境に定着しない場合は、getCleartextID_SIMCHECK
代わりにメソッドを使用しますが、特定のSIM存在のニーズに適合させる必要があることを考慮してください。
PS:OEMはSERIALをGoogleのポリシー(同じSERIALの複数のデバイス)に対してなんとかバグアウトしていることに注意してください。また、Googleは大手OEMで少なくとも1つの既知のケースがある(非公開で、どのブランドかわからない)と述べています。それはどちらかです、私はサムスンを推測しています)。
免責事項:これは、一意のデバイスIDを取得するという元の質問に答えますが、OPは、APPに一意のIDが必要であると述べて、あいまいさをもたらしました。そのようなシナリオでAndroid_IDの方が優れている場合でも、たとえば、2つの異なるROMインストール(同じROMでもかまいません)を介したアプリのTitanium Backupの後では機能しません。私のソリューションは、フラッシュまたは工場出荷時のリセットに依存しない永続性を維持し、ハック/ハードウェアの改造を通じてIMEIまたはシリアルの改ざんが発生した場合にのみ失敗します。
上記のすべてのアプローチには問題があります。Google i / oで、Reto Meierは、インストール全体でユーザーを追跡するほとんどの開発者のニーズを満たす必要がある、これに取り組む方法に対する強力な回答をリリースしました。
このアプローチにより、匿名の安全なユーザーIDが提供されます。このユーザーIDは、さまざまなデバイス(タブレットを含む、プライマリGoogleアカウントに基づく)間、および同じデバイス上のインストール間でユーザーに対して永続的です。基本的なアプローチは、ランダムなユーザーIDを生成し、これをアプリの共有設定に保存することです。次に、Googleのバックアップエージェントを使用して、Googleアカウントにリンクされた共有設定をクラウドに保存します。
完全なアプローチを見てみましょう。最初に、Androidバックアップサービスを使用してSharedPreferencesのバックアップを作成する必要があります。次のリンクからアプリを登録することから始めます:http : //developer.android.com/google/backup/signup.html
Googleから、マニフェストに追加する必要があるバックアップサービスキーが提供されます。次のように、アプリケーションにBackupAgentを使用するように指示する必要もあります。
<application android:label="MyApplication"
android:backupAgent="MyBackupAgent">
...
<meta-data android:name="com.google.android.backup.api_key"
android:value="your_backup_service_key" />
</application>
次に、バックアップエージェントを作成し、sharedpreferencesにヘルパーエージェントを使用するように指示する必要があります。
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);
}
}
バックアップを完了するには、メインアクティビティでBackupManagerのインスタンスを作成する必要があります。
BackupManager backupManager = new BackupManager(context);
最後に、まだ存在していない場合はユーザーIDを作成し、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;
}
このUser_IDは、ユーザーがデバイスを切り替えた場合でも、インストール全体で保持されます。
このアプローチの詳細については、こちらのRetoの講演を参照してください。http://www.google.com/events/io/2011/sessions/android-protips-advanced-topics-for-expert-android-app-developers.html
そして、バックアップエージェントを実装する方法の詳細についてはこちらをデベロッパーサイトを参照してください。http://developer.android.com/guide/topics/data/backup.html バックアップがするように私は、特にテストに下部のセクションをお勧めします瞬間的には発生しないため、テストするにはバックアップを強制する必要があります。
もう1つの方法は、権限をまったく持たないアプリで/ sys / class / android_usb / android0 / iSerialを使用することです。
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で行うには、FileInputStreamを使用してiSerialファイルを開き、文字を読み取ります。すべてのデバイスにこのファイルがあるわけではないので、例外ハンドラでラップするようにしてください。
少なくとも次のデバイスは、このファイルを誰でも読み取り可能であることがわかっています。
また、ここで私のブログの記事を見ることができます:http://insitusec.blogspot.com/2013/01/leaking-android-hardware-serial-number.html私は、他のファイルが情報のために利用可能であるかを議論するところ。
文字列としてのAndroid OSデバイスの一意のデバイスID。
String deviceId;
final TelephonyManager mTelephony = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
if (mTelephony.getDeviceId() != null){
deviceId = mTelephony.getDeviceId();
}
else{
deviceId = Secure.getString(getApplicationContext().getContentResolver(), Secure.ANDROID_ID);
}
しかし、私はGoogleが提案するこの方法を強くお勧めします::
Build.SERIAL
完全に信頼できるわけではありませんが、最も簡単な方法です 空にするか、別の値を返す場合があるため、です(証明1、証明2、デバイスの設定に表示される)をです。
デバイスのメーカーとAndroidのバージョンに応じてその数を取得する方法はいくつかあるため、1つの要点で見つけられる可能性のあるすべてのソリューションをコンパイルすることにしました。これを簡略化したバージョンを次に示します。
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;
}
私はこの質問が古いことを知っていますが、1行のコードで行うことができます
String deviceID = Build.SERIAL;
上記の@emmbyによって投稿されたサンプルクラスは、優れた出発点であることがわかりました。しかし、他のポスターで言及されているように、いくつかの欠点があります。主なものは、UUIDを不必要にXMLファイルに永続化し、その後常にこのファイルから取得することです。これにより、クラスは簡単にハッキングされます。ルート化された電話を持っている人は誰でもXMLファイルを編集して、自分に新しいUUIDを与えることができます。
絶対に必要な場合(つまり、ランダムに生成されたUUIDを使用する場合)のみXMLに永続化するようにコードを更新し、@ Brill Pappinの回答に従ってロジックをリファクタリングしました。
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;
}
はい。これはデバイスハードウェアのシリアル番号であり、一意です。したがって、APIレベル2.3以降では、android.os.Build.ANDROID_IDを使用して取得できます。2.3未満のAPIレベルでは、TelephonyManager.getDeviceID()を使用します。
あなたはこれを読むことができますhttp://android-developers.blogspot.in/2011/03/identifying-app-installations.html