【问题标题】:ACTION_MY_PACKAGE_REPLACED not received未收到 ACTION_MY_PACKAGE_REPLACED
【发布时间】:2012-10-01 01:56:48
【问题描述】:

我正在使用 ACTION_MY_PACKAGE_REPLACED 来接收我的应用程序更新或重新安装的时间。 我的问题是该事件从未被触发(我尝试了 Eclipse 和真实设备)。 我就是这样做的:

清单:

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

代码:

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

这段代码很简单,实际上我使用了其他事件,例如 BOOT_COMPLETED 和其他事件,它们可以工作,但 ACTION_MY_PACKAGE_REPLACED。 谢谢。

【问题讨论】:

  • 你有两个问题。您的操作名称错误;它不应包含 ACTION_ 前缀。此外,MY_PACKAGE_REPLACED 适用于 API 12+。

标签: android broadcastreceiver


【解决方案1】:

出于某种原因,一位谷歌开发人员(名为“Dianne Hackborn”)认为可以单独注册当前应用的 PACKAGE_REPLACED Intent(阅读存档版本here,原始链接here)。

但是,我找不到任何正确的方法,所以我做出了妥协:它将在可用时使用最新的 API。

遗憾的是,我不知道为什么它不能被调试,但它确实有效(如果你愿意,你可以写入日志)。

代码如下:

清单:

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

编辑:在今天的 Android 版本中,当你应该将 minSdk 设置为至少 14 时,你不需要这个,实际上你应该只使用 MY_PACKAGE_REPLACED 就可以了。不需要布尔值等...

【讨论】:

  • 您需要将 android:debuggable="true"android:exported="true" 添加到清单声明中,以便能够调试接收器。例如&lt;receiver android:debuggable="true" android:exported="true" android:name=".OnUpgradeBroadcastReceiver"&gt;
  • 但它已经可以调试了,因为我已经从 Eclipse 运行它...我认为它是导出的,因为它是从系统获取意图的方式...。确定它修复了吗?如果是这样,那就奇怪了。
  • 从来不知道&lt;item name="x" type="bool"&gt;false&lt;/item&gt;,一直用较短的&lt;bool name="x"&gt;false&lt;/bool&gt;
  • 由于清单合并问题,这不再起作用:stackoverflow.com/questions/24447663/…
  • @cprcrack 所以你可以停止使用合并,或者只是将接收者的声明放在主清单文件而不是库的 ,对吗?
【解决方案2】:

由于清单合并问题,accepted answer 不再适用于 Android Studio 1.0+,如 here 所示。完全基于android developer's answer,我通过以下实现解决了这个问题:

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

【讨论】:

  • 这里和我写的有什么不同?您刚刚添加了“getApplicationContext”吗?此外,如果您在 Android-Studio(或 Android)上发现了错误,您应该在此处发布:code.google.com/p/android/issues/list
  • 不是bug,只是新的manifest合并不支持你的操作。你说有什么不同?您不能对两个不同的接收器使用相同的类。因此,如果您查看我的代码,我在其中一个接收器中使用了内部静态类,从而符合新的清单合并,同时避免使用 java 文件执行相同的任务。当然,除此之外一切都是等价的,我只是添加了它,因为 StackOverflow 中的答案应该是自包含的。
  • 另外,如果您有兴趣了解为什么您的解决方案现在无法在 Android Studio 上运行,请点击我提供的链接。同样,如果您仍然看不到有什么不同,请查看代码,或者甚至先尝试您的代码,然后在 Android Studio 1.0+ 中尝试我的代码,因为我知道我无法更详细地解释它。跨度>
  • 在我看来,因为您必须执行额外的步骤,所以这是一个错误(因为如果不合并它就可以工作)。如果您不想自己发布错误报告,您能否分享一个显示问题的最小化示例?我可以发给你。
  • TL;博士。此答案与标记为正确有何不同?
【解决方案3】:

从所有用户那里获取信息我可以通过这种方式解决我的问题。 他们都是对的,没有什么需要注意的地方:

在清单中:

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

和代码:

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

在我的 Android 版本 (2.3 Gingerbread) 中,我无法使用 MY_PACKAGE_REPLACED,但我们使用 PACKAGE_REPLACED 解决了问题(将告知任何应用已被替换)但询问它是否是我们的:

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

谢谢大家

【讨论】:

    【解决方案4】:

    我只想在这里添加我自己的两便士价值,因为我在让它工作和调试它时遇到了问题。我使用的是棒棒糖设备:

    这是我使用的代码:

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

    要调试它,你需要确保你已经在手机上安装了更新,只需通过Eclipse调试就可以了,并且至少打开了一次应用程序,然后你可以简单地编辑你的调试配置:

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

    我通过将一个小文件写入 SD 卡确认它可以工作

    【讨论】:

    • 这个答案是正确的! MY_PACKAGE_REPLACED 以前对我不起作用,但我 REMOVED 在尝试 PACKAGE_REPLACED 之后就在那里
    • 是的,做了同样的事情,删除了方案,它似乎可以工作(至少在我的设备上)
    【解决方案5】:

    简单清单适用于所有版本:

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

    【讨论】:

    • 但这会导致您的应用在每次在 API 12 或更高版本的设备上替换任何(其他)应用时唤醒
    【解决方案6】:

    您是否在 API>=12 设备/模拟器上尝试它?此广播不会在以前的情况下发送,因为它是 API 12。如果您需要您的应用为 Pre-ICS 和旧的蜂巢设备接收此广播,

    尝试:

    if (intent.getAction().equals(Intent.ACTION_PACKAGE_REPLACED)) {
      if (!intent.getData().getSchemeSpecificPart()
           .equals(context.getPackageName())) {
        return;
      }
    }
    

    【讨论】:

    • 谢谢。好吧,我也试过 ACTION_PACKAGE_REPLACED 但也没有触发任何东西。是的,模拟器和设备是 GingerBread。还有其他提示吗?
    • 你添加接收方了吗?作为 我在我的几个应用程序中使用它,它们在所有 android 设备上都能正常工作>1.5跨度>
    【解决方案7】:

    实际上,您的应用会在您安装 apk 时启动两次。 为您设置的每个接收器一次。

    当您在收听android.intent.action.PACKAGE_REPLACED 时,您需要检查intent.getData() 中的包名

    请注意,intent.getData() 来自 android.intent.action.MY_PACKAGE_REPLACED

    我认为使用其中之一就足够了。

    【讨论】:

    • "实际上,当您安装您的 apk 时,您的应用会启动两次。您设置的每个接收器都会启动一次。" -> 你能提供这些信息的来源吗?
    【解决方案8】:

    我在从 Android Studio 构建和安装应用时遇到了这个问题。

    • 在进行正常构建和运行(不进行调试)时,我通过关闭 Instant Run 解决了这个问题。
    • 在使用调试进行构建和运行时,我找不到解决问题的方法。

    【讨论】:

      【解决方案9】:

      您需要向 Intent 过滤器添加数据方案,如下所示

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

      【讨论】:

      • 根据documentation,常量ACTION_MY_PACKAGE_REPLACED的值为android.intent.action.MY_PACKAGE_REPLACED,没有ACTION_部分。
      • 你应该使用 Intent.ACTION_MY_PACKAGE_REPLACED 相当于“android.intent.action.MY_PACKAGE_REPLACED”
      猜你喜欢
      • 2011-08-02
      • 2020-08-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-01-01
      相关资源
      最近更新 更多