【问题标题】:GCM with custom broadcastreceiver带有自定义广播接收器的 GCM
【发布时间】:2012-08-18 20:08:11
【问题描述】:

我正在我的应用程序中实现 gcm 通知。因为我使用我的代码生成许多具有不同包名称的应用程序,所以我不能使用标准的 mypackage.GCMIntentService 名称。在生成应用程序时,我只在 Manifest 中进行更改并更改我的 R 类的导入。所以我实现了自己的 BroadcastReceiver

public class GCMReceiver extends GCMBroadcastReceiver {
  @Override
  protected String getGCMIntentServiceClassName(Context context) {
    return GCMIntentService.class.getName();
  }
}

返回 GCMIntentService 的名称,而不考虑包名称。

这是我的清单:

    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.GET_ACCOUNTS" />
    <uses-permission android:name="android.permission.WAKE_LOCK" />

    <uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
    <permission
        android:name="org.rferl.permission.C2D_MESSAGE"
        android:protectionLevel="signature" />

    <uses-permission android:name="org.rferl.permission.C2D_MESSAGE" />


    <service
        android:name="org.rferl.service.GCMIntentService"
        android:enabled="true" />


   <receiver
        android:name="org.rferl.GCMReceiver"
        android:enabled="true"
        android:permission="com.google.android.c2dm.permission.SEND" >
        <intent-filter>

            <!-- Receives the actual messages. -->
            <action android:name="com.google.android.c2dm.intent.RECEIVE" />
            <!-- Receives the registration id. -->
            <action android:name="com.google.android.c2dm.intent.REGISTRATION" />

            <category android:name="org.rferl" />
        </intent-filter>
    </receiver>

一切正常,我可以注册、注销、接收消息。但是当应用程序没有运行时,不会调用 GCMIntentService.onMessage。我的清单中是否缺少某些内容?为什么系统没有启动服务?

【问题讨论】:

  • 我也遇到了同样的问题?你的问题现在解决了吗?请从我的帐户中查看我的最新问题并相应地指导我。谢谢

标签: android broadcastreceiver google-cloud-messaging


【解决方案1】:

为 Android GCM 更改应用程序/GCMIntentService/GCMBroadcastReceiver 的包/类名称(使用 Eclipse ADT)

注意建议您在进行以下更改之前验证您是否可以通过 GCM 接收消息。要使用应用的默认包名称在 Android 应用中实现 GCM,请参阅GCM: Getting Started


包名

更改应用的包名(例如,新包名 = com.example.newpackage),

  • 在包资源管理器中,右键单击项目 → Android 工具 → 重命名应用程序包。
    这会自动方便地更新包名称。
  • AndroidManifest.xml 中,更新permissionuses-permissionC2D_MESSAGE 的包名称:

    <permission android:name="com.example.newpackage.permission.C2D_MESSAGE" android:protectionLevel="signature" />
    <uses-permission android:name="com.example.newpackage.permission.C2D_MESSAGE" />
    
  • AndroidManifest.xml中,更新category中的包名receiver

    <receiver
        android:name="com.example.oldpackage.GCMBroadcastReceiver"
        android:permission="com.google.android.c2dm.permission.SEND" >  <!-- Not this one!! -->
        <intent-filter>
            <action android:name="com.google.android.c2dm.intent.RECEIVE" />
            <action android:name="com.google.android.c2dm.intent.REGISTRATION" />
    
            <category android:name="com.example.newpackage" />  <!-- This one!! -->
        </intent-filter>
    </receiver>
    

GCMIntentService 的名称

如果您的应用程序包名称为com.example.newpackage,则您的GCMIntentService 必须称为com.example.newpackage.GCMIntentService。如果没有,

  • 创建一个 extends GCMBroadcastReceiver 并覆盖 getGCMIntentServiceClassName() 的新类:

    public class MyBroadcastReceiver extends GCMBroadcastReceiver
    {
        @Override
        protected String getGCMIntentServiceClassName(Context context)
        {
            return MyIntentService.class.getName(); // Don't hard-code like "com.example.oldpackage.MyIntentService", see http://stackoverflow.com/a/936696/1402846
        }
    }
    

    这是基于Google's documentation on GCMBroadcastReceiver:

    默认情况下,GCMBaseIntentService 类属于应用程序主包,命名为DEFAULT_INTENT_SERVICE_CLASS_NAME。要使用新类,getGCMIntentServiceClassName(Context) 必须被覆盖。

  • AndroidManifest.xml 中,更新receiver 的名称:

    <receiver
        android:name="com.example.oldpackage.MyBroadcastReceiver"
        ... >
    </receiver>
    
  • AndroidManifest.xml 中,更新service 的名称:

    <service android:name="com.example.oldpackage.MyIntentService" />
    

GCMBroadcastReceiver 的名称

如果您更改了 GCMBroadcastReceiver 的包/类名称:

  • AndroidManifest.xml 中,更新receiver 的名称:

    <receiver
        android:name="com.example.oldpackage.NewBroadcastReceiver"
        ... >
    </receiver>
    

疑难解答

  • 验证在AndroidManifest.xml中,包名至少出现4次:

    • manifest:

      <manifest ...
          package="com.example.newpackage" ...
      
    • permission:

      <permission android:name="com.example.newpackage.permission.C2D_MESSAGE" android:protectionLevel="signature" />
      
    • uses-permission:

      <uses-permission android:name="com.example.newpackage.permission.C2D_MESSAGE" />
      
    • 对于 GCM 广播接收器,在 categoryintent-filterreceiver 内:

      <category android:name="com.example.newpackage" />
      
  • 如果您更改了软件包名称,请在测试前卸载设备/模拟器上的旧应用。

  • 如果您更改了软件包名称,请注意注册 ID(您在 onRegistered() 中收到的)已更改。
  • 如果您在onRegistered() 中收到您的注册ID,您应该会在LogCat 中看到类似的内容(标签GCMBroadcastReceiver):

    GCMBroadcastReceiver        onReceive: com.google.android.c2dm.intent.REGISTRATION
    GCMBroadcastReceiver        GCM IntentService class: com.example.oldpackage.MyIntentService
    

    验证意图服务的包/类名是否正确。

  • 如果您在自己的 GCMBroadcastReceiver 中覆盖 getGCMIntentServiceClassName(Context),您应该会在 LogCat 中看到类似这样的内容(标签 GCMRegistrar):

    GCMRegistrar        Setting the name of retry receiver class to com.example.oldpackage.MyBroadcastReceiver
    

    验证广播接收器的包/类名是否正确。

  • 当您的服务器向 GCM 服务器发送消息时,请检查 HTTP 状态代码和 HTTP 响应是否有错误。
  • 如果你绝望了:
    • 检查 LogCat 是否有错误。
    • 尝试重新启动您的设备/模拟器。
    • 尝试在设备/模拟器上卸载您的应用。
    • 尝试重新启动 Eclipse。
    • 尝试清理并重新构建项目。
    • 尝试更新 ADT(下拉菜单 → 窗口 → Android SDK 管理器 → 安装包)。
    • 尝试更新 Eclipse(下拉菜单 → 帮助 → 检查更新)。
    • 尝试重新启动计算机。
    • 睡个好觉,或者祈祷。

【讨论】:

    【解决方案2】:

    您应该将 GCMIntentService 类放入您的根应用程序包中。 这里是 org.rferl

    <service
        android:name=".GCMIntentService"
        android:enabled="true" />
    

    和接收者

       <receiver
                android:name="com.google.android.gcm.GCMBroadcastReceiver"
                android:permission="com.google.android.c2dm.permission.SEND" >
                <intent-filter>
    
                    <!-- Receives the actual messages. -->
                    <action android:name="com.google.android.c2dm.intent.RECEIVE" />
                    <!-- Receives the registration id. -->
                    <action android:name="com.google.android.c2dm.intent.REGISTRATION" />
    
                    <category android:name="com.EgoSecure.ma" />
                </intent-filter>
            </receiver>
    

    【讨论】:

    • 这是不可能的,因为使用源代码作为基础来生成许多应用程序 - 它们必须具有不同的包名称,我在清单中进行了更改。因此,如果我生成例如 org.rferl.en 的应用程序,那么我需要为许多类更改包结构更改导入等等......我还写道,当应用程序运行时一切正常,我可以接收消息。只有系统在应用未运行时不调用接收器或启动服务。
    • 如果您使用 Android 3.0 或 > ,您必须为“停止”的应用程序设置标志
    • 你是对的,停止的应用程序也会被用户杀死。所以我在测试期间杀了它。我无法正确测试它,因为服务器人员来自其他公司。当我手动杀死它时,来自谷歌的样本也不起作用。但是当我启动它并关闭手机时,一切正常。但是如何将此标志放在清单文件中?如果出现问题,我通常会杀死手机上的应用程序,并且在我启动它们之前我无法接收消息。有点奇怪的行为。
    • 标志应该添加到你的广播意图中——“包括停止的包”。但是如果你没有从服务器接收到 gcm 数据,这对你没有帮助。
    • 这不是我的本意。这个调用我的接收器的 Intent 提供 GCM 服务。所以我无法控制更新,以编程方式创建它。
    【解决方案3】:

    因为我使用我的代码生成大量具有不同包名称的应用程序,所以我不能使用标准 mypackage.GCMIntentService 名称。

    我不确定您要求的是运行时解决方案还是构建时解决方案。其他答案是运行时解决方案,所以我想我在构建期间添加了一些关于可能性的信息。


    在 AndroidManifest 中,您可以使用变量 $PACKAGE_NAME(默认可用),它将引用您在 manifest 根元素中的属性 package 中指定的包名称。

    package 属性的值不必是硬编码字符串,也可以通过资源引用动态设置,如下所示:

    <manifest package="@string/app_package" ...>
        ...
        <service
            android:name="$PACKAGE_NAME.service.GCMIntentService"
            android:enabled="true" />
        ...
    </manifest>
    

    注意.service 只是我包含的一个子包,用于展示您如何指定这些。当然,只有当您的应用程序遵循一般规则(例如将服务类放入 .service 子包中)时,此解决方案才有效。

    另外请注意,您实际上可以完全关闭根包。它将被 Android 扩展:

    <manifest package="@string/app_package" ...>
        ...
        <service
            android:name=".service.GCMIntentService"
            android:enabled="true" />
        ...
    </manifest>
    

    效果同上。

    如果您正在寻找一种更灵活的方法来替换 AndroidManifest(或不同文件)中的值,您可能需要查看 Ant 替换任务 (http://ant.apache.org/manual/Tasks/replace.html) 或资源过滤 (http://maven.apache.org/plugins/maven-resources-plugin/examples/filter.html)马文。

    【讨论】:

      【解决方案4】:

      gcm 广播接收器 (GCMBroadcastReceiver.class) 从应用程序根目录调用意图服务类 (GCMIntentService.class)。您现在不能使用“org.rferl.service.GCMIntentService”。您应该覆盖 GCMBroadcastReceiver 中的 getGCMIntentServiceClassName 方法,该方法返回您的 GCMIntentService 类的名称。怎么做,here

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2016-03-24
        • 2015-06-28
        • 1970-01-01
        • 2018-04-25
        • 2012-06-10
        • 1970-01-01
        • 2017-06-19
        相关资源
        最近更新 更多