Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 723
Ton Avatar asked Oct 01 '12 01:10

Ton


6 Answers

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

like image 55
android developer Avatar answered Nov 14 '22 00:11

android developer


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");
    }
}
like image 36
cprcrack Avatar answered Nov 14 '22 00:11

cprcrack


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

like image 12
Ton Avatar answered Nov 13 '22 22:11

Ton


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

like image 8
Steven Elliott Avatar answered Nov 13 '22 23:11

Steven Elliott


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>
like image 3
Bouchehboun Saad Avatar answered Nov 14 '22 00:11

Bouchehboun Saad


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;
  }
}
like image 2
Edison Avatar answered Nov 13 '22 22:11

Edison