Identifying App Installations

 

30 MARCH 2011

Identifying App Installations

[The contents of this post grew out ofan internal discussion featuring many of the usual suspects who’ve been authorsin this space. — Tim Bray]

In the Android group, from time to timewe hear complaints from developers about problems they’re having coming up withreliable, stable, unique device identifiers. This worries us, because we thinkthat tracking such identifiers isn’t a good idea, and that there are betterways to achieve developers’ goals.

Tracking Installations


It is very common, and perfectly reasonable, for a developer to want to trackindividual installations of their apps. It sounds plausible just to call
 TelephonyManager.getDeviceId() and use that value to identify theinstallation. There are problems with this: First, it doesn’t work reliably(see below). Second, when it does work, that value survives device wipes(“Factory resets”) and thus you could end up making a nasty mistake when one ofyour customers wipes their device and passes it on to another person.

To track installations, you could forexample use a UUID as an identifier, and simply create anew one the first time an app runs after installation. Here is a sketch of aclass named “Installation” with one static method Installation.id(Contextcontext). You couldimagine writing more installation-specific data into the INSTALLATION file.

public class Installation {
    private static String sID = null;
    private static final String INSTALLATION = "INSTALLATION";

    public synchronized static String id(Context context) {
        if (sID == null) {  
            Fileinstallation = new File(context.getFilesDir(), INSTALLATION);
            try {
                if (!installation.exists())
                   writeInstallationFile(installation);
                sID = readInstallationFile(installation);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
        return sID;
    }

    private static String readInstallationFile(File installation) throws IOException {
        RandomAccessFile f = new RandomAccessFile(installation, "r");
        byte[] bytes = new byte[(int) f.length()];
        f.readFully(bytes);
        f.close();
        return new String(bytes);
    }

    private static void writeInstallationFile(File installation) throws IOException {
        FileOutputStream out = new FileOutputStream(installation);
        String id = UUID.randomUUID().toString();
        out.write(id.getBytes());
        out.close();
    }
}

Identifying Devices

Suppose you feel that for the needs ofyour application, you need an actual hardware device identifier. This turns outto be a tricky problem.

In the past, when every Android devicewas a phone, things were simpler: TelephonyManager.getDeviceId()is required to return (depending on thenetwork technology) the IMEI, MEID, or ESN of the phone, which is unique tothat piece of hardware.

However, there are problems with thisapproach:

·        Non-phones: Wifi-only devices or music players that don’t havetelephony hardware just don’t have this kind of unique identifier.

·        Persistence: On devices which do have this, itpersists across device data wipes and factory resets. It’s not clear at all if,in this situation, your app should regard this as the same device.

·        Privilege:It requires READ_PHONE_STATE permission, which is irritating if youdon’t otherwise use or need telephony.

·        Bugs: We have seen a few instances of production phones forwhich the implementation is buggy and returns garbage, for example zeros orasterisks.

Mac Address

It may be possible to retrieve a Macaddress from a device’s WiFi or Bluetooth hardware. We do not recommend usingthis as a unique identifier. To start with, not all devices have WiFi. Also, ifthe WiFi is not turned on, the hardware may not report the Mac address.

Serial Number

Since Android 2.3 (“Gingerbread”) thisis available via android.os.Build.SERIAL.Devices without telephony are required to report a unique device ID here; somephones may do so also.

ANDROID_ID

More specifically, Settings.Secure.ANDROID_ID.This is a 64-bit quantity that is generated and stored when the device firstboots. It is reset when the device is wiped.

ANDROID_ID seems a good choice for aunique device identifier. There are downsides: First, it is not 100% reliableon releases of Android prior to 2.2 (“Froyo”). Also, there has been at leastone widely-observed bug in a popular handset from a major manufacturer, whereevery instance has the same ANDROID_ID.

Conclusion

For the vast majority of applications,the requirement is to identify a particular installation, not a physicaldevice. Fortunately, doing so is straightforward.

There are many good reasons for avoidingthe attempt to identify a particular device. For those who want to try, thebest approach is probably the use of ANDROID_ID on anything reasonably modern,with some fallback heuristics for legacy devices.

Posted by Tim Bray at 1:08 PM

Labels: Best Practices

NewerPost OlderPost Home

 

§ Identifying App Installations

§ In-app Billing Launched onAndroid Market

§ In-App Billing on AndroidMarket: Ready for Testin...

§ Memory Analysis for AndroidApplications

§ Application Stats on AndroidMarket

§ Android 3.0 HardwareAcceleration

§ Renderscript Part 2

§ Fragments For All

 

你可能感兴趣的:(Identifying App Installations)