72

I noticed that an alarm is disabled when the application which sets this alarm has been upgraded. Is that true ?

Until now, I used the SharedPreferences with a FIRST_RUN key in order to know if it's the first run of my application. If I don't find this key, I enable the alarm and set FIRST_RUN to false, else I do nothing.

But I noticed also that these preferences remain intact between app upgrade !

So after an upgrade, the FIRST_RUN key is already false, so I do nothing while my alarm need to be enabled.

How to handle such case ?

Thanks in advance

tbruyelle
  • 12,895
  • 9
  • 60
  • 74

4 Answers4

93

Solution by Daniel Lew :

Need a receiver with the following lines in manifest :

<receiver android:name=".OnUpgradeReceiver">
  <intent-filter>
    <action android:name="android.intent.action.PACKAGE_REPLACED" />
    <data android:scheme="package" android:path="your.app.package" />
  </intent-filter>
</receiver>

android:path is used in order to prevent OnUpgradeReceiver to be triggered by any upgrade of any application.

tbruyelle
  • 12,895
  • 9
  • 60
  • 74
  • 7
    The path part is only used if the scheme refers to a hierarchical URI. In the case of "package" which does not refer to a hierarchical URI, you cannot pass a path string. However, will attach your application package to the URI ("package:your.app.package") so you don't need to pass a path anyway. – toc777 Apr 09 '12 at 17:37
  • 1
    Does the app need special permissions to listen to PACKAGE_REPLACED? – AlikElzin-kilaka Nov 28 '12 at 12:34
  • 1
    No the app doesn't need special permission – tbruyelle Nov 28 '12 at 13:35
  • android:path was exactly what I was looking for! Thanks! – praneetloke Jan 20 '13 at 19:53
  • if i want to restart my app in this case, I need a separate app for this receiver, right? – Ron Jul 01 '13 at 15:05
  • will it also work for a new install? or I'll have to handle that separately using sharedprefs or something? – Viral Patel Jan 25 '16 at 07:48
  • 1
    is there a way to debug "onReceive" method with this action? – Ninja Coding May 30 '16 at 17:29
  • After testing under Android 4.2, I confirm none of the above solutions properly filter the Intent to your app only: if you specify the scheme only, you get every Intent. If you specify both scheme and path, you get every Intent too because the URI is not hierarchical. The only thing that works is using ssp instead of path, which requires API 19. So better use MY_PACKAGE_REPLACED (API 12+) or nothing. Recommended read: https://chris.orr.me.uk/android-ssp-data-intent-filter/ – BladeCoder Feb 08 '17 at 17:49
63

I've never tried this myself, but what about creating a BroadcastReceiver that listens to the ACTION_PACKAGE_REPLACED Intent?

I've thought about trying this before, but I'm not sure if there's a chicken-and-egg problem with it or not (e.g., does the Intent get sent before the new upgraded application can receive it?). Worth a try, though.

Dan Lew
  • 85,990
  • 32
  • 182
  • 176
  • 1
    Yes it works ! Thanks Daniel, actually the intent is sent just after the upgrade so my receiver is able to catch it. I'm just wondering now if my receiver will be triggered at each upgrade of any application ? – tbruyelle Jan 25 '10 at 17:55
  • 1
    It will trigger each time you upgrade, however in the docs it says that you can look at the Intent's data and it will tell you the name of the package. Therefore, you can use intent filters to filter out all package replacements that aren't your own. – Dan Lew Jan 25 '10 at 17:58
  • 1
    Does the app need special permissions to listen to PACKAGE_REPLACED? – AlikElzin-kilaka Nov 28 '12 at 12:33
  • 38
    As of API 12 you can use MY_PACKAGE_REPLACED: http://developer.android.com/reference/android/content/Intent.html#ACTION_MY_PACKAGE_REPLACED – Maks Feb 14 '13 at 02:58
  • 2
    Please do not use this anymore. It will launch your app process for every upgrade of every app, which is extremely inefficient. The only way to filter an Intent with this action to restrict it to your app is by using the ssp attribute which is only available on API 19+, so I recommend MY_PACKAGE_REPLACED only. – BladeCoder Feb 08 '17 at 18:03
  • If your using API level 12 and above you can use the MY_PACKAGE_REPLACED for your own app. https://developer.android.com/reference/android/content/Intent.html#ACTION_MY_PACKAGE_REPLACED – Danuofr Jul 25 '17 at 22:22
23

Simply, listen to the android.intent.action.MY_PACKAGE_REPLACED ... This INTENT will notify you if a new version of your application has been installed over an existing one

Note: This intent can is available starting from API 12

Sami Eltamawy
  • 9,874
  • 8
  • 48
  • 66
  • 1
    This should be the only recommended solution. There is no way to properly filter android.intent.action.PACKAGE_REPLACED for the local app only before API 19, and having this Intent triggering your app launch for every app install is hugely inefficient. – BladeCoder Feb 08 '17 at 17:58
21

For the Android API level 12 and above, you need to register BroadcastReceiver with action ACTION_MY_PACKAGE_REPLACED

<receiver android:name=".MyBroadcastReceiver">
  <intent-filter>
    <action android:name="android.intent.action.MY_PACKAGE_REPLACED" />
  </intent-filter>
</receiver>
Rajkiran
  • 15,845
  • 24
  • 74
  • 114
armansimonyan13
  • 956
  • 9
  • 15
  • This is the right answer if you're supporting modern Android OSes. For most apps (Gingerbread is at 1% at this point of market share), using MY_PACKAGE_REPLACED simplifies the broadcast receiver code. – Chantell Osejo Jan 20 '17 at 22:12