Android アプリに一意の ID を使用する必要があり、デバイスのシリアル番号が適切な候補になると考えました。アプリで Android デバイスのシリアル番号を取得するにはどうすればよいですか?
18 に答える
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が言及しているように、AndroidDeveloperBlogにはこれをカバーする記事があります。
私はGoogleの誰かと話をして、いくつかの項目についてさらに説明を求めました。前述のブログ投稿に記載されていないことを私が発見したのは次のとおりです。
- ANDROID_IDが推奨されるソリューションです。ANDROID_IDは、Android<=2.1または>=2.3のバージョンで完全に信頼できます。投稿で言及されている問題があるのは2.2だけです。
- いくつかのメーカーのいくつかのデバイスは、2.2のANDROID_IDバグの影響を受けます。
- 私が判断できた限りでは、影響を受けるすべてのデバイスのANDROID_IDは同じで、9774d56d682e549cです。これは、エミュレータによって報告されたのと同じデバイスIDです。
- Googleは、OEMが多くまたはほとんどのデバイスの問題にパッチを適用していると考えていますが、少なくとも2011年4月の初めの時点で、ANDROID_IDが壊れているデバイスを見つけるのは非常に簡単であることを確認できました。
Googleの推奨事項に基づいて、デバイスごとに一意のUUIDを生成するクラスを実装しました。必要に応じて、シードとしてANDROID_IDを使用し、必要に応じてTelephonyManager.getDeviceId()にフォールバックします。それが失敗した場合は、ランダムに生成された一意の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) {
}
このコードは、非表示のAndroidAPIを使用してデバイスのシリアル番号を返します。
String deviceId = Settings.System.getString(getContentResolver(),
Settings.System.ANDROID_ID);
ただし、Android ID が一意の識別子になることは保証されていません。
Android Developer's Blog には、これについて議論している優れた投稿があります。
TelephonyManager.getDeviceId()
タブレットなどの携帯電話ではない Android デバイスでは動作せず、許可が必要であり、READ_PHONE_STATE
すべての携帯電話で確実に動作するとは限らないため、使用しないことをお勧めします。
代わりに、次のいずれかを使用できます。
- Macアドレス
- シリアルナンバー
- ANDROID_ID
この投稿では、それぞれの長所と短所について説明しており、読む価値があるので、どちらが使用に最適かを判断できます.
デバイスに固有であり、そのライフタイム (工場出荷時設定へのリセットやハッキングを除く) の間一定である単純な番号については、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 を参照してください。
上記のすべてのアプローチには問題があります。Google i/o で、Reto Meier は、これにアプローチする方法に対する強力な回答をリリースしました。これは、インストール間でユーザーを追跡するというほとんどの開発者のニーズを満たすはずです。
このアプローチにより、匿名で安全なユーザー ID が得られます。このユーザー ID は、さまざまなデバイス (プライマリ Google アカウントに基づくタブレットを含む) および同じデバイスにインストールされたユーザーに対して永続的です。基本的なアプローチは、ランダムなユーザー ID を生成し、これをアプリの共有設定に保存することです。次に、Google のバックアップ エージェントを使用して、Google アカウントにリンクされた共有設定をクラウドに保存します。
完全なアプローチを見てみましょう。まず、Android Backup Service を使用して 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>
次に、バックアップ エージェントを作成し、共有設定にヘルパー エージェントを使用するように指示する必要があります。
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 ファイルを開き、文字を読み取るだけです。すべてのデバイスがこのファイルを持っているわけではないため、必ず例外ハンドラーでラップしてください。
少なくとも次のデバイスは、このファイルを誰でも読み取り可能であることがわかっています。
- ギャラクシー ネクサス
- ネクサス S
- モトローラ Xoom 3g
- 東芝 AT300
- HTC One V
- ミニ MK802
- サムスン ギャラクシー S II
ここで私のブログ投稿を見ることもできます。
@haserman が言うように:
TelephonyManager tManager = (TelephonyManager)myActivity.getSystemService(Context.TELEPHONY_SERVICE);
String uid = tManager.getDeviceId();
ただし、マニフェスト ファイルにアクセス許可を含める必要があります。
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
文字列としての 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が提案するこの方法を強くお勧めします::
上記の @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;
}