5

我正在我的应用程序中实现 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

4 回答 4

15

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

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


包裹名字

要更改应用程序的包名称(例如,新包名称 = 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
        }
    }
    

    这是基于谷歌关于 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" />
      
  • 如果您更改了软件包名称,请在测试前卸载设备/模拟器上的旧应用程序。

  • 如果您更改了包名称,请注意(您在 中收到的onRegistered())注册 ID 已更改。
  • 如果您在 中收到您的注册 ID onRegistered(),您应该在 LogCat (tag) 中看到类似这样的内容GCMBroadcastReceiver

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

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

  • 如果您getGCMIntentServiceClassName(Context)在自己的中覆盖GCMBroadcastReceiver,您应该在 LogCat (tag) 中看到类似的内容GCMRegistrar

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

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

  • 当您的服务器向 GCM 服务器发送消息时,请检查 HTTP 状态代码和 HTTP 响应是否有错误。
  • 如果你很绝望:
    • 检查 LogCat 是否有错误。
    • 尝试重新启动您的设备/模拟器。
    • 尝试在设备/模拟器上卸载您的应用程序。
    • 尝试重新启动 Eclipse。
    • 尝试清理并重新构建项目。
    • 尝试更新 ADT(下拉菜单 → 窗口 → Android SDK 管理器 → 安装包)。
    • 尝试更新 Eclipse(下拉菜单 → 帮助 → 检查更新)。
    • 尝试重新启动计算机。
    • 睡个好觉,或者祈祷。
于 2013-01-20T12:29:18.757 回答
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子包中)时才有效。

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

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

实际上,和上面一样。

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

于 2013-07-31T20:22:18.617 回答
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>
于 2012-08-23T11:34:50.193 回答
0

The gcm broadcast receiver (GCMBroadcastReceiver.class) calls intent service class (GCMIntentService.class) from application root directory. You cannot use "org.rferl.service.GCMIntentService" right now. You should override getGCMIntentServiceClassName method from GCMBroadcastReceiver, that returns name of your GCMIntentService class. How to do that, here

于 2012-08-26T11:35:05.603 回答