3

I am working on an app in which I want to identify uniquely each device. I can't take imei because some tablets does not support call so in those cases it will be null. I can't take wifi/bluetooth mac address because when it is off then it returns null.

I can't take android _id because on reset phone it changes as well as when there a device with multiple profiles then each profile have a different android_id so this is also not a unique to identify a device.

What is the best way to identify a physical device not user.

Edit

I have already read this Is there a unique Android device ID? but I could not find my answer.

Community
  • 1
  • 1
N Sharma
  • 33,489
  • 95
  • 256
  • 444
  • 3
    Possible duplicate of [Is there a unique Android device ID?](http://stackoverflow.com/questions/2785485/is-there-a-unique-android-device-id) – RogueBaneling Jan 19 '16 at 17:04
  • @RogueBaneling I have already read that thread. I could not find answer there which I am looking. – N Sharma Jan 19 '16 at 17:32

5 Answers5

0

I Would suggest using a mac address maybe, and the hash it.

You can look at this answer, but it still requires a sim.

You can get the Mac Address like that:

WifiManager manager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
WifiInfo info = manager.getConnectionInfo();
String address = info.getMacAddress();

and then do an md5 hash on it.

I think it will work ok.

Don't forget to add

<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>

in your manifest.

Community
  • 1
  • 1
Shahar
  • 3,692
  • 4
  • 25
  • 47
  • This require wifi should be on. if it is off then it returns null.. I already mentioned this in the question – N Sharma Jan 19 '16 at 17:31
0

On my side, I'm using the code below. It actually identifies the hardware, not the user or any profile.

I think it's fine for what you need despite the use of the IMEI number as it is considered optional:

public static String getUniqueId(Context ctx) {
    final TelephonyManager tm = (TelephonyManager)ctx.getSystemService(Context.TELEPHONY_SERVICE);
    String id = tm.getDeviceId();

    if (id == null) {
        id = Build.SERIAL;
    }

    return DigestHelper.getSHADigest(id); // I'm using a SHA for convenience, and for not being able to reverse it, but you can do anything needed with this String.
}

This code requires the following permission in your Manifest: <uses-permission android:name="android.permission.READ_PHONE_STATE" />.

This works for me with no compatibility issue: Build.SERIAL was added with API 9, and is useful for tablets or other devices that do not have an IMEI. With APIs lower than 9, all devices were phones, so they all had IMEIs (and are you still supporting API levels lower than 9, really?). So there's no risk to end up with a null ID or a NoClassDefFoundError.

As a sidenote, Build.SERIAL is supposed to be unique "if available". I never met an actual device that does neither have an IMEI nor this serial number so I never had any problem with that "if available" thing.

Shlublu
  • 10,917
  • 4
  • 51
  • 70
  • Doesn't `Build.SERIAL` change ? – N Sharma Jan 19 '16 at 17:39
  • @Williams It is not supposed to change as a hardware serial number. What I know for a fact is that I never received complaints from clients who seen their device suddently not recognized, as I never had troubles due to some mix-ups. This is what makes me using this. Now I would prefer seeing this written in the API spec. – Shlublu Jan 19 '16 at 19:59
0

Most of the users will have a Google account linked to the android device (only in rare cases they won't). You can get the exact gmail email address (which would, of course, be unique) using AccountPicker without requiring to add any permissions to get accounts.

And use a combination of the email and phone model or manufacturer or serial number as the unique id for the device. (Possible that user may use two devices but very low possibility of all his devices being the same)

Your app needs to include the Google Play Services but it doesn't need any permissions.

This whole process will fail on older versions of Android (2.2+ is required), or if Google Play is not available so you should consider that case.

Sample code from the source:

private static final int REQUEST_CODE_EMAIL = 1;
    private TextView email = (TextView) findViewById(R.id.email);

    // ...

    try {
        Intent intent = AccountPicker.newChooseAccountIntent(null, null,
                new String[] { GoogleAuthUtil.GOOGLE_ACCOUNT_TYPE }, false, null, null, null, null);
        startActivityForResult(intent, REQUEST_CODE_EMAIL);
    } catch (ActivityNotFoundException e) {
        // TODO
    }

    // ...

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        if (requestCode == REQUEST_CODE_EMAIL && resultCode == RESULT_OK) {
            String accountName = data.getStringExtra(AccountManager.KEY_ACCOUNT_NAME);
            email.setText(accountName);
        }
    }

Source of the above information is : This Answer on SO - to a similar but slightly different question asked in the past.

This Post - also has some nice approaches that would serve your purpose.

Community
  • 1
  • 1
Viral Patel
  • 32,418
  • 18
  • 82
  • 110
0

This is a very important and interesting question, so would like to answer it in detail.

There are several ways of detecting an Android device uniquely, but the problem is that most of them are unreliable due to various reasons.

i) IMEI

This is by far the most common method used, but is only available for phones and needs this unnecessary permission android.permission.READ_PHONE_STATE

ii) Android ID

This can also get altered upon factory reset or if the device is rooted. Not a very reliable way for uniqueness.

iii) WLAN and Bluetooth MAC address

This requires devices to have these features and have take permissions like android.permission.ACCESS_WIFI_STATE and android.permission.BLUETOOTH. This will also not work if the wifi or bluetooth is turned off.

iv) Phone number or Email ID

This is the least reliable way to determine uniqueness and should not be a method of choice, if not entirely necessary.

So whats the way out now, Pseudo Unique ID. You can create your own "almost unique ID" from the device without any extra permissions.

Sounds good? Let's move on to the method directly.

/**
 * 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!
    // http://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!
    // http://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();
}

It takes various factors into consideration while generating a pseudo unique ID for any Android device. But this is not perfect.

There can be collisions of these IDs, but it will be rare, very very rare. So technically, this is something you can rely on for most use cases.

Aritra Roy
  • 15,355
  • 10
  • 73
  • 107
0

A simple approach which comes to my mind would be using a registry server.

Using this approach all your users are required to register their app (i.e. equivalently their device) to a registry service. And then the registry server in turn assign them an unique token which should be used subsequently in the app.

frogatto
  • 28,539
  • 11
  • 83
  • 129