32

I am using ACTION_MY_PACKAGE_REPLACED to receive when my app is updated or resinstalled. My problem is that the event is never triggered (I tried Eclipse and real device). This is what I do:

Manifest:

<receiver android:name=".MyEventReceiver" >
    <intent-filter android:priority="1000" >
        <action android:name="android.intent.action.ACTION_MY_PACKAGE_REPLACED" />
    </intent-filter>
</receiver>

Code:

public class MyEventReceiver extends BroadcastReceiver
{  
   @Override public void onReceive(Context context, Intent intent)
   {  
      if ("android.intent.action.ACTION_MY_PACKAGE_REPLACED".equals(intent.getAction())) 
      {  //Restart services
      }
   }      
}

This code is simple, in real one I used other events like BOOT_COMPLETED and others, and they work but ACTION_MY_PACKAGE_REPLACED. Thanks.

Ton
  • 9,235
  • 15
  • 59
  • 103
  • 7
    You have two problems. Your action name is wrong; it shouldn't include the `ACTION_` prefix. Also, `MY_PACKAGE_REPLACED` is for API 12+. – Sam Aug 22 '15 at 02:38

9 Answers9

25

for some reason, a google developer (named "Dianne Hackborn") thinks it is possible to register to the PACKAGE_REPLACED intent of the current app alone (read archived version here, original link here).

however, i can't find any way of doing it correctly, so i've made a compromise: it will use the newest API when available.

Sadly, I can't find out why it can't be debugged, but it does work (you can write to the log if you wish).

here's the code:

manifest:

    <receiver
        android:name=".OnUpgradeBroadcastReceiver"
        android:enabled="@bool/is_at_most_api_11" >
        <intent-filter>
            <action android:name="android.intent.action.PACKAGE_REPLACED" />
            <data android:scheme="package" />
        </intent-filter>
    </receiver>
    <receiver
        android:name=".OnUpgradeBroadcastReceiver"
        android:enabled="@bool/is_at_least_api_12" >
        <intent-filter>
            <action android:name="android.intent.action.MY_PACKAGE_REPLACED" />
        </intent-filter>
    </receiver>

res/values/version_checks.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <item name="is_at_least_api_12" type="bool">false</item>
    <item name="is_at_most_api_11" type="bool">true</item>

</resources>

res/values-v12/version_checks.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <item name="is_at_least_api_12" type="bool">true</item>
    <item name="is_at_most_api_11" type="bool">false</item>

</resources>

OnUpgradeBroadcastReceiver.java

public class OnUpgradeBroadcastReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(final Context context, final Intent intent) {
        if (VERSION.SDK_INT <= VERSION_CODES.HONEYCOMB
                && !context.getPackageName().equals(intent.getData().getSchemeSpecificPart())) {
            android.util.Log.d("AppLog", "other apps were upgraded");
            return;
        }
        android.util.Log.d("AppLog", "current app was upgraded");

EDIT: In today's Android versions, when you should set minSdk to be at least 14, you don't need this, and indeed you should just use MY_PACKAGE_REPLACED and that's it. No need for the booleans etc...

android developer
  • 114,585
  • 152
  • 739
  • 1,270
  • You need to add **android:debuggable="true"** and **android:exported="true"** to your manifest declaration in order to be able to debug the receiver. e.g. `` – Eike Thies Jul 15 '14 at 23:12
  • but it's already debuggable as I've ran it from Eclipse... also I think it's exported since that's how it gets the intent from the system.... Sure that it fixes it? if so, that's weird. – android developer Jul 17 '14 at 11:04
  • 1
    Never knew about `false`, always used the shorter `false` – cprcrack Jan 03 '15 at 21:31
  • 1
    This doesn't work any more because of manifest merge issues: http://stackoverflow.com/questions/24447663/android-manifest-merger-fails-for-receivers-with-same-name-but-different-content – cprcrack Jan 03 '15 at 21:46
  • @cprcrack So you can either stop using the merger, or just put the declaration of the receiver on the main manifest file instead of the library's , right? – android developer Jan 03 '15 at 22:13
  • I need the merger, and the declaration is on the main manifest file (I guess, it's my app's manifest). I just submitted another answer totally based on yours, which was extremely helpful: http://stackoverflow.com/a/27760075/423171 – cprcrack Jan 03 '15 at 22:27
  • I meant putting it only on the main manifest file, which means you wouldn't need to use the merger anyway. – android developer Jan 03 '15 at 23:12
  • @FredrickGauss Right. When this happens I like to use the "Wayback machine" addon/website, which shows me an archived version of the website. I've updated now the link to show the archived version of it. Also, since it's not needed anymore, I've updated the answer. – android developer Nov 18 '19 at 18:36
  • Not getting triggered for me. Can you please check this https://stackoverflow.com/questions/59420253/android-silently-updating-apk-and-then-restart-the-app – eC Droid Dec 20 '19 at 06:58
  • Will the broadcast receiver be called if the application is not running / at the background ? – Louis Jan 06 '21 at 09:14
  • @Louis It should be fine. It's just that if you run from Android Studio, things can get weird. – android developer Jan 06 '21 at 10:00
15

The accepted answer doesn't work any more with Android Studio 1.0+ because of manifest merge issues, as seen here. Totally based on android developer's answer, I fixed the issue with the following implementation:

AndroidManifest.xml:

<receiver android:name=".UpdateReceiver$LegacyUpdateReceiver" android:enabled="@bool/shouldUseActionPackageReplaced" >
    <intent-filter>
        <action android:name="android.intent.action.PACKAGE_REPLACED" />
        <data android:scheme="package" />
    </intent-filter>
</receiver>
<receiver android:name=".UpdateReceiver" android:enabled="@bool/shouldUseActionMyPackageReplaced" >
    <intent-filter>
        <action android:name="android.intent.action.MY_PACKAGE_REPLACED" />
    </intent-filter>
</receiver>

/res/values/resources.xml:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <bool name="shouldUseActionPackageReplaced">true</bool>
    <bool name="shouldUseActionMyPackageReplaced">false</bool>
</resources>

/res/values-v12/resources.xml:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <bool name="shouldUseActionPackageReplaced">false</bool>
    <bool name="shouldUseActionMyPackageReplaced">true</bool>
</resources>

UpdateReceiver.java:

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log;

public class UpdateReceiver extends BroadcastReceiver
{
    public static class LegacyUpdateReceiver extends BroadcastReceiver
    {
        @Override
        public void onReceive(Context context, Intent intent)
        {
            if (intent != null && intent.getData() != null && context.getPackageName().equals(intent.getData().getSchemeSpecificPart()))
            {
                onUpdate(context);
            }
        }
    }

    @Override
    public void onReceive(Context context, Intent intent)
    {
        onUpdate(context);
    }

    public static void onUpdate(Context context)
    {
        Log.d("LOG", "Current app updated");
    }
}
Community
  • 1
  • 1
cprcrack
  • 17,118
  • 7
  • 88
  • 91
  • what's different here exactly than what I've written? Have you just added "getApplicationContext" ? Also, if you've found a bug on Android-Studio (or Android), you should post about it here: https://code.google.com/p/android/issues/list – android developer Jan 03 '15 at 23:09
  • 3
    It's not a bug, it's just that the new manifest merger does not support what you are doing. And what's different, you say? You cannot use the same class for two different receivers. So if you look at my code I used an inner static class in one of the receivers, thus complying with the new manifest merger and at the same time avoiding to java files for the same task. Other than that everything is equivalent, of course, and I just added it because answers in StackOverflow should be self-contained. – cprcrack Jan 03 '15 at 23:25
  • Also, please follow the links I provided if you are interested in learning why your solution doesn't work right now on Android Studio. Similarly, please take a look at the code or even try first your code and then mine in Android Studio 1.0+ if you are still unable to see what's different, because I'm aware I can't explain it in more detail. – cprcrack Jan 03 '15 at 23:27
  • To me it seems that because you had to perform additional steps, it's a bug (because without merging it would have worked). If you don't wish to publish the bug report by yourself, can you please share a minimized sample that shows the issue? I can post it for you. – android developer Jan 04 '15 at 10:15
  • You can see a sample and the error given posted by somebody else in one of the links I already provided on the answer! Copying it again for you here... http://stackoverflow.com/q/24447663/423171 – cprcrack Jan 04 '15 at 10:30
  • I meant a full project, that I can import and see that it occurs. Something I can also upload to Google groups. – android developer Jan 04 '15 at 13:16
  • You have all the sources you need to create a project by yourself. In fact it's in your own answer where the "bug" is shown, you just have to compile it with the last version of Android Studio and gradle plugin. I think this conversation is highly unnecessary, I posted a pretty clear, motivated answer that fixes your now broken answer. If you want to do something else about it, it's you who should make that effort. – cprcrack Jan 04 '15 at 13:27
  • I'm sorry you feel this way. It's just that I've never used the merging feature because of all the issues I've seen that occurred when using it. Didn't try it again recently so I was hoping you could share your project to show how things should be done, and to show the issue itself which I can report about. I really didn't mean to make you upset. Sorry. – android developer Jan 04 '15 at 19:50
  • I didn't want to sound rude. It's just that I don't understand the reasons behind your requests. I didn't have to "use the merging feature" explicitly, there's nothing special about my setup. I already showed you in my answer how things should be done now, basically don't use the same `android:name` for two `` elements. And the issue is quite clearly described in the questions I linked. You only have to copy the 4 files provided in your answer and compile it to reproduce it. – cprcrack Jan 05 '15 at 13:30
  • ok, I hope to find the time to work on this, and also update you on my findings. – android developer Jan 05 '15 at 14:08
  • I've tried to read an old post I've made about manifest merging (here: http://stackoverflow.com/q/10976635) , but now I've noticed that they've changed it completely (here: http://tools.android.com/tech-docs/new-build-system/user-guide/manifest-merger ). Which of the methods did you use and how? Also, I've noticed that now Android-Studio doesn't allow me to have the receivers the way I tried, as it says that there are 2 with the same signature: "Error:... duplicated with element declared at AndroidManifest.xml" – android developer Jan 05 '15 at 23:48
  • Yes, that's what I told you. I haven't use any particular method, just set everything by default. So you now understand my answer? – cprcrack Jan 06 '15 at 00:03
  • Yes, but I don't know how you did the merging. Did you use the new way of merging or the old way? What exactly did you do? EDIT: I've now tried it out, without even reading the huge webpage I've given, and it seems like it's automatic... This seems odd... So now it works... But the problem wasn't the merger. The problem was the duplication. Even if you don't use a library, you will have this issue. Google must have changed the rules of how to put those components on the manifest. – android developer Jan 06 '15 at 00:10
  • I thought you meant that the merger was the problem, which is why I've also written that I should post about it on the bug tracker.... – android developer Jan 06 '15 at 06:15
  • Well, the error apparently comes from the manifest merger according to the question I linked. So my guess is that the merging process or whatever you call it works even with just one manifest. – cprcrack Jan 07 '15 at 11:00
  • i am not getting this right ??? seems like there is an issue with mypackagereplaced – Amit Hooda Apr 08 '16 at 11:47
  • 1
    TL;DR. How this answer differ to marked as correct? – msangel Dec 22 '16 at 17:59
  • On my android Nougat, this answer is not work. For Lollipop, it work as charm. Any opinion? Thanks. – Kyaw Min Thu L Aug 07 '17 at 03:16
12

Getting information from all the users I could solve my situation this way. All of them were right, with little points to notice:

In manifest:

    <receiver android:name=".MyEventReceiver" >
        <intent-filter android:priority="1000" >
            <!--other actions I need-->
            <action android:name="android.intent.action.PACKAGE_REPLACED" />
            <data android:scheme="package"/>
        </intent-filter>
    </receiver>

And code:

public class MyEventReceiver extends BroadcastReceiver
{     
    @Override public void onReceive(Context context, Intent intent)
    {  
       if(Intent.ACTION_PACKAGE_REPLACED.equals(intent.getAction())) 
       {   if(intent.getData().getSchemeSpecificPart().equals(context.getPackageName()))
           {  //Restart services.
           }
       }
    }      
}

In my Android release (2.3 Gingerbread) I was not able to use MY_PACKAGE_REPLACED but we solved using PACKAGE_REPLACED (will advise of any app been replaced) but asking if it is ours with:

 if(intent.getData().getSchemeSpecificPart().equals(context.getPackageName()))
 {
 }

Thanks to all

Sami Eltamawy
  • 9,874
  • 8
  • 48
  • 66
Ton
  • 9,235
  • 15
  • 59
  • 103
8

I just want to add my own two pence worth here, because I had problems getting this to work and debugging it .. I am using a Lollipop device:

This is the code I used:

    <receiver android:name=".services.OnUpdateReceiver">
        <intent-filter>
            <action android:name="android.intent.action.MY_PACKAGE_REPLACED" />
        </intent-filter>
    </receiver>    

To debug it, you need to make sure you have installed the update on your phone, just via Eclipse debug is fine, and opened the app at least one time, then you can simply edit your debug configuration:

eclipse > run > debug configurations > launch action (do nothing) > then F11 like normal

I confirmed it worked by writing a small file to the SD card

Steven Elliott
  • 3,214
  • 5
  • 29
  • 40
  • 7
    this answer is correct! MY_PACKAGE_REPLACED was not working before for me, but I _REMOVED_ which was there after trying PACKAGE_REPLACED before – Boy Oct 30 '15 at 13:33
  • Yes, did the same, removed the scheme thing and it SEEMS to work (on my devices at least) – Ben Aug 19 '18 at 10:31
3

Simple Manifest working in all version :

    <receiver
        android:name=".Receiver"
        android:enabled="true"
        android:exported="true" >
        <intent-filter>
            <action android:name="android.intent.action.PACKAGE_REPLACED" />
            <data android:scheme="package"/>
        </intent-filter>
        <intent-filter>
            <action android:name="android.intent.action.MY_PACKAGE_REPLACED" />
        </intent-filter>
    </receiver>
  • 1
    but this will cause your app to wake up every time ANY (other) app is replaced on devices with API 12 or greater – Gavriel Jul 05 '15 at 08:39
2

Are you trying it on a API>=12 device/emulator? This broadcast will not be sent on prior cases as it is API 12. If you need your app to receive this for Pre-ICS and the old honey comb devices,

try:

if (intent.getAction().equals(Intent.ACTION_PACKAGE_REPLACED)) {
  if (!intent.getData().getSchemeSpecificPart()
       .equals(context.getPackageName())) {
    return;
  }
}
Edison
  • 5,961
  • 4
  • 23
  • 39
  • Thanks. Well, I Also tried ACTION_PACKAGE_REPLACED but nothing is triggered either. And yes, Emulator and Device are GingerBread. Any other hint? – Ton Oct 01 '12 at 02:17
  • Have you add the receiver? as and I use this for several of my applications and they work well on all android devices >1.5 – Edison Oct 01 '12 at 03:36
1

Actually, your app will start twice when you install your apk. Once for each receiver that you have set.

When you are Listening to android.intent.action.PACKAGE_REPLACED then you need to check for the package-name in the intent.getData()

Note that intent.getData() will be Null when it is from android.intent.action.MY_PACKAGE_REPLACED

I think using one of them is enough.

Suraj Rao
  • 29,388
  • 11
  • 94
  • 103
  • "Actually, your app will start twice when you install your apk. Once for each receiver that you have set." -> can you provide the source of this information ? – Louis Jan 06 '21 at 09:19
0

I ran into this problem when I was building and installing my app from Android Studio.

  • When doing normal build & run (without debugging), I fixed the problem by turning off Instant Run.
  • When doing a build & run with debugging, I couldn't find a way to fix the problem.
Sam
  • 40,644
  • 36
  • 176
  • 219
-4

You need to add data scheme to the intent filter like below

<receiver android:name=".MyEventReceiver" >
    <intent-filter android:priority="1000" >
        <action android:name="android.intent.action.ACTION_MY_PACKAGE_REPLACED" />
        <data android:scheme="package"/>
    </intent-filter>
</receiver>
Rasel
  • 15,499
  • 6
  • 40
  • 50
  • 8
    According to the [documentation](http://developer.android.com/reference/android/content/Intent.html#ACTION_MY_PACKAGE_REPLACED), the value of the constant `ACTION_MY_PACKAGE_REPLACED` is `android.intent.action.MY_PACKAGE_REPLACED` without the `ACTION_` part. – MaxChinni Sep 19 '13 at 18:03
  • you should use Intent.ACTION_MY_PACKAGE_REPLACED which equates to "android.intent.action.MY_PACKAGE_REPLACED" – FabioC Jul 06 '16 at 06:58