我正在我的应用程序中实现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。我在清单中遗漏了什么吗?为什么系统没有启动服务?
答案 0 :(得分:14)
GCMIntentService
/ GCMBroadcastReceiver
的程序包/类名称(使用Eclipse ADT)注意:建议您在进行以下更改之前验证是否可以通过GCM接收消息。要使用应用的默认包名称在Android应用中实施GCM,请参阅GCM: Getting Started。
更改应用的套餐名称(例如,新套餐名称= com.example.newpackage
),
在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
如果您更改了软件包名称,请在测试前卸载设备/模拟器上的旧应用程序。
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
验证广播接收器的包/类名是否正确。
答案 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