5

My android application will be preinstalled. And I want to keep tracking of preinstalled apps.

For this purpose I need somehow to save a key or a flag (which means that app is preinstalled). I will add this key to each request to my back-end and will analyze it. I have an issue with that. An issue is about update from Google Play.

The standart workflow is the following:

1) I give to a manufacturer a special version of my application, which saves a key somehow (in Shared Prefs for example).

2) Manufacturer sell device with the app (special, modified).

3) When User get it, there definetly be next version of the app (standart, without special code) in the Google Play, so user perhaps update it without any launching (the worst case).

4) I lost my tracking possibility. (new apk fully removing never launched old one which was special)

To solve it I was listening a system broadcast ON_BOOT_COMPLETE, but its not working properly on Android 3.1+.

Have you any ideas how can I do that?

Community
  • 1
  • 1
TsimoX
  • 447
  • 5
  • 14
  • That should be fairly straightforward. 1) Add broadcast listener for [Intent.ACTION_MY_PACKAGE_REPLACED](https://developer.android.com/reference/android/content/Intent.html#ACTION_MY_PACKAGE_REPLACED) 2) Check if your package is a system app, [ApplicationInfo.FLAG_SYSTEM](https://developer.android.com/reference/android/content/pm/ApplicationInfo.html#FLAG_SYSTEM) 3) Viola! – ozbek Nov 15 '13 at 02:43
  • 1
    I don't think this will work - the intent is sent to the new application, not the old one. Furthermore, it only gets sent if the app was in a started state: `This intent is sent directly to the application, but only if the application was upgraded while it was in started state (not in a stopped state).` – ajh158 Nov 17 '13 at 02:36
  • could your application know that on such devices it is supposed to be preinstalled ? (and therefore behave as such, without actually altering the app) – njzk2 Nov 20 '13 at 21:21

4 Answers4

5

Can you install an additional .apk that only has a service? Then that service can have the key, etc. and it can listen for when your app starts and send the tracking info. Then it won't matter if your app gets upgraded; the service will still be the same.

ajh158
  • 1,477
  • 1
  • 13
  • 32
  • Glad it makes sense to you! I was thinking it would also make it easier to maintain - you can check the service code into a separate repo, then if you have to deliver an updated version you could change. It sounds like the way you have it now, you will have to make changes, then take the changes out - then later if a change is needed you will have to put them back in. Maybe you can sell it to your boss that way - less cost, less risk over time. – ajh158 Nov 21 '13 at 15:09
  • I'm not a big fan of this ether. It does not "solve" the application "design" problem... I would simply check if the app is a system one, and use local storage that will persist accross updates. – shkschneider Nov 21 '13 at 15:39
3

There are some ways to know if application is system application or not. Like by checking installed directory of application or check FLAG_SYSTEM for the application.

Method 1 : - Check location of application

public static boolean applicationIsSystemApp(Context mContext, String packageName) {

    try {
        ApplicationInfo applicationInfo = mContext.getPackageManager().getApplicationInfo(packageName, 0);        
        String appLocation = applicationInfo.publicSourceDir; 
        // OR String appLocation = applicationInfo.sourceDir;  
        // Both returns the same
        // if package is pre-installed then output will be /system/app/application_name.apk
        // if package is installed by user then output will be /data/app/application_name.apk

        // Check if package is system app 
        if (appLocation != null && appLocation.startsWith("/system/app/")) {
            return true; 
        }
    } catch (NameNotFoundException e) {
        e.printStackTrace(); // TODO Can handle as your logic
    }
    return false; 
}

Method 2 : - Check FLAG_SYSTEM of application

public static boolean applicationIsSystemApp(Context mContext, String packageName) {

    try {
        ApplicationInfo applicationInfo = mContext.getPackageManager().getApplicationInfo(packageName, 0);   
        // FLAG_SYSTEM is only set to system applications, 
        // this will work even if application is installed in external storage

        // Check if package is system app 
        if ((applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
            return true; 
        }
    } catch (NameNotFoundException e) {
        e.printStackTrace(); // TODO Can handle as your logic
    }
    return false; 
}

And call this method as

if (applicationIsSystemApp(getApplicationContext(), "com.example.mysystemapp")) {
     // Application is system app
} else {
     // Application has been installed as 3rd Party app
}
Pankaj Kumar
  • 81,967
  • 29
  • 167
  • 186
1

There is a property sourceDir in ApplicationInfo class. You can use it to distinguish the system app version and the upgraded one.

System app will start with "/system/app" and upgraded app will start with "/data/app"

Try something like this

try {
            ApplicationInfo appInfo = this.getPackageManager().getApplicationInfo("com.example.san", 0);
            boolean isSystemApp = false;
            if(appInfo.sourceDir.startsWith("/system/app")){ // You can use "contains" too
                isSystemApp = true;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

Note: I didnt test it.. Hope it works

San
  • 5,567
  • 2
  • 26
  • 28
1

One proven solution is to pre-install an APK that on have the permission: RECEIVE_BOOT_COMPLETED

Then on the very first boot - you make a quick notation that you are a PREINSTALLED to whatever persistent storage you use, preferably add a token file.

You look for this token file on all your later APK versions to determine if the running copy originates from a device which had it pre-installed or not.

This solves the mayor issues:

1) Then its OK if the user updates you APK to the latest version, you can still read this token.

2) You don't have to maintain a separate APK on google play for the pre-installed community

3) You don't have to hustle with the OEM to install multiple APK when you actually only have one App.

gemigis
  • 186
  • 4