18

for months I've been using a class to generate a UUID that was solid between reintalls. My app is about discounts so I rely on this UUID to limit the number of coupons per device.

protected void getDeviceId(){
    try {
        Context context = cordova.getActivity().getApplicationContext();
        TelephonyManager tm = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);

        String uuid;
        String androidID = Secure.getString(context.getContentResolver(), Secure.ANDROID_ID);
        String deviceID = tm.getDeviceId();
        String simID = tm.getSimSerialNumber();

        if ("9774d56d682e549c".equals(androidID) || androidID == null) {
            androidID = "";
        }

        if (deviceID == null) {
            deviceID = "";
        }

        if (simID == null) {
            simID = "";
        }

        uuid = androidID + deviceID + simID;
        uuid = String.format("%32s", uuid).replace(' ', '0');
        uuid = uuid.substring(0, 32);
        uuid = uuid.replaceAll("(\\w{8})(\\w{4})(\\w{4})(\\w{4})(\\w{12})", "$1-$2-$3-$4-$5");

        this.callbackContext.success(uuid);
    }catch(Exception e ) {
        this.callbackContext.error("Exception occurred: ".concat(e.getMessage()));
    }
}

That's the core of how I generate my uuid. The thing is this weekend someone with an XT1032 and android 5.1 was able to regenerate different UUIDs after each installation of the app, getting free coupons. This method that I use can be tricked somehow? Maybe with a rooted phone? I'm shooting in the blind. I need to be able to create reliable UUIDs between installations.

monxas
  • 2,475
  • 2
  • 20
  • 36

4 Answers4

30

I've used this before and working fine for me.

public String createTransactionID() throws Exception{
    return UUID.randomUUID().toString().replaceAll("-", "").toUpperCase();
}
vidulaJ
  • 1,232
  • 1
  • 16
  • 31
  • this is the easiest way perhaps. – the_unknown_spirit Oct 25 '16 at 10:20
  • But this will stay the same number after you erase the app, install it again and call that function again? – monxas Oct 25 '16 at 10:23
  • I haven't got that so far. Did you get? – vidulaJ Oct 25 '16 at 10:24
  • 3
    I need to generate the same id always. I think this only provides a random chunk? The thing is, When people erase my app, after a reinstall I have to regenerate the same id for the same phone, to be able to identify it. I think this doesn't work like that? – monxas Oct 25 '16 at 10:30
  • Is that what you asked from the question? If so you got to keep some parameters unique. – vidulaJ Oct 25 '16 at 10:32
  • That's what the question is about, to be able to assign an unique id to each phone and keep it constant through installs, that's why Im usnig things like get device id, get sim serial number and so on... – monxas Oct 25 '16 at 10:36
  • 4
    I'm surprised this answer got 19 upvotes without anyone understanding the question of the OP. – Houman Oct 07 '20 at 11:58
  • How is random uniq ? Random means randoms so two can be same.. – Renetik Jul 16 '22 at 01:06
8

Your UUID depends on three of different IDs, all of which are easily changeable. There is no way to be sure whether this is the reason, but looking at the code here:

SSN (SIM serial number) getSimSerialNumber() gets you SSN for the sim card attached. A simple way to generate a different UUID for same device would be simply to insert a different sim card. Which I know is cumbersome, but doable nonetheless.

IMEI/MEID getDeviceId() returns IMEI or MEID. So another way would be to change the IMEI of the device. If you only google "change phone IMEI without root" you will get loads of doable results. Which might be an easier way (if automated).

Android Device ID ANDROID_ID according to docs changes with each time phone is restored. So again user can change UUID just by restoring phone.

Since your UUID is based on a chain of three unique ids fooling the system is as easy as the weakest link in your chain. ANDROID_ID being the strongest link in this chain I'd recommend you to only use it instead. Refer to this link as an alternative.


EDIT:

While ANDROID_ID is still the best way to recognize previous users there have been some updates to its use and uniqueness since Oreo. Visit the #ANDROID_ID page for more details.

A summary of the changes are:

Each ANDROID_ID on apps targeting Android Oreo or later and installed on Android Oreo or later are unique by the user who installed the app, the app's signature (essentially different for different apps but not necessarily) and the device. So while you will still get the same id in most cases, installing the app as a different user will still generate a different ANDROID_ID. These changes are made to protect user's privacy.

There have also been updates on permissions for ANDROID_ID.

Abbas
  • 3,529
  • 5
  • 36
  • 64
  • Yeah, you're right. Do you happen to know if java.util.UUID.randomUUID() would provide the same number between installations on the same device? Other people is pointing me there but I'm not sure they understand my problem. – monxas Oct 25 '16 at 10:54
  • 1
    @monxas using `java.util.UUID.randomUUID()` will generate different UUID each time but the mechanism it uses i.e. check if already exists before generating, ensures a different UUID only when the user has reinstalled the app (on Upgrade it remains the same). Which I think is not what you want (also file can be deleted if the user has root access). – Abbas Oct 25 '16 at 11:05
  • Thanks, I was almost sure it wasn't what I needed. I'll go with android_ID. – monxas Oct 25 '16 at 11:08
  • @monxas I have the same problem as you do. Have you gone down this path to use Android_ID after all? Have you encountered any issues? – Houman Oct 07 '20 at 12:04
  • @Houman while ANDROID_ID is still the best way to recognize users between reinstalls. There have been some updates in its use and uniqueness since Android Oreo: see the above link for `ANDROID_ID` for details. – Abbas Oct 08 '20 at 12:24
  • @Abbas Thank you for the edit. When you say recognise the users between reinstalls, do you mean reinstall of the phone (where Android ID may change through factory reset) or do you mean reinstall of the app? Because I deleted my app and reinstalled it and still have the same Android_ID. Of course as long as it's installed by the same user as you mentioned. – Houman Oct 08 '20 at 13:42
  • Yes, the app reinstall. – Abbas Oct 08 '20 at 14:56
2

I need to be able to create reliable UUIDs between installations.

If that is the only criteria, the proposal in this answer is your best bet. Do note that the ANDROID_ID may change after a factory reset of the device, so it will never be something that cannot trick your app.

Most other "UUIDs" may already change in between app installations as you have noticed.

For more info please read google's Best Practices for Unique Identifiers. It is a must read.

Community
  • 1
  • 1
Tim
  • 41,901
  • 18
  • 127
  • 145
  • The thing is I already used Secure.ANDROID_ID on my code, and somehow someone bypassed it to get a new UUID each time they reinstalled the app. can that android ID be changed when phone is rooted? – monxas Oct 25 '16 at 10:39
  • @monxas Yes Android_id can be changed and it's not fool proof. But it seems to be the best viable option. – Houman Oct 07 '20 at 12:00
1

Beginning with Android 10 google restricts access to all hardware-identifying IDs to System apps or apps that act as a fully fledged mdm controller (afaik). Before you had to ask the user for permission and now you cannot even do that.

More often you want to the app to be paid per device not paid per google account which can be used on a multitude of devices) but it should apply for your coupons too.

Google only advises to use their firebase ID system for anything like that. They will always state security while assuring that you need to use google services for that.

The only way around that I can think of is your own webservice with user account + password (giving a session token or something) but that would be too inconvienient for a coupon app?

FrankKrumnow
  • 501
  • 5
  • 13