Ton
Ton

Reputation: 9736

ACTION_MY_PACKAGE_REPLACED not received

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.

Upvotes: 32

Views: 38284

Answers (9)

android developer
android developer

Reputation: 116392

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...

Upvotes: 25

Sam
Sam

Reputation: 42387

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.

Upvotes: 0

Omid Mehdizadeh
Omid Mehdizadeh

Reputation: 73

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.

Upvotes: 1

cprcrack
cprcrack

Reputation: 19139

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");
    }
}

Upvotes: 15

Steven Elliott
Steven Elliott

Reputation: 3224

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

Upvotes: 8

Bouchehboun Saad
Bouchehboun Saad

Reputation: 728

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>

Upvotes: 3

Ton
Ton

Reputation: 9736

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

Upvotes: 12

Rasel
Rasel

Reputation: 15477

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>

Upvotes: -4

Edison
Edison

Reputation: 5971

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;
  }
}

Upvotes: 2

Related Questions