GCM与自定义广播接收器

时间:2012-08-23 10:15:18

标签: android broadcastreceiver google-cloud-messaging

我正在我的应用程序中实现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。我在清单中遗漏了什么吗?为什么系统没有启动服务?

4 个答案:

答案 0 :(得分:14)

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

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


包名称

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

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

    C2D_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的{​​{1}}中的包名:

    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

    这基于Google's documentation on GCMBroadcastReceiver

      

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

  • 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 } } 的名称:

    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中验证包名称应至少出现4次:

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

      AndroidManifest.xml
    • 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" /> 内的category内{GC}广播接收器中的intent-filter

      receiver
  • 如果您更改了软件包名称,请在测试前卸载设备/模拟器上的旧应用程序。

  • 如果您更改了包裹名称,请注意注册ID(您在onRegistered()中收到的)已更改。
  • 如果您在onRegistered()收到了注册ID,则应在LogCat(代码<category android:name="com.example.newpackage" /> )中看到类似内容:

    GCMBroadcastReceiver

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

  • 如果您在自己的GCMBroadcastReceiver onReceive: com.google.android.c2dm.intent.REGISTRATION GCMBroadcastReceiver GCM IntentService class: com.example.oldpackage.MyIntentService 中覆盖getGCMIntentServiceClassName(Context),则应在LogCat(代码GCMBroadcastReceiver)中看到类似内容:

    GCMRegistrar

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

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

答案 1 :(得分: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>

答案 2 :(得分:2)

  

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

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


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

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

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

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

另请注意,您实际上可以完全关闭root包。它将由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)或资源过滤({{3与Maven合作。

答案 3 :(得分:0)

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