I am implementing gcm notifications in my application. Because I use my code to generate lot of application with different package names I cannot use standard mypackage.GCMIntentService name. When generating applications I do changes only in Manifest and change imports of my R class. So I impelented my own BroadcastReceiver
public class GCMReceiver extends GCMBroadcastReceiver {
@Override
protected String getGCMIntentServiceClassName(Context context) {
return GCMIntentService.class.getName();
}
}
to return name of GCMIntentService regardless of package name.
Here is my manifest:
<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>
Everything works fine, I can register, unregister, receive messages. But when application is not runnig no GCMIntentService.onMessage is not called. Am I missing something in my manifest? Why system did not start service?
GCMIntentService
/GCMBroadcastReceiver
for Android GCM (using Eclipse ADT)Note: You are advised to verify that you can receive messages through GCM before making the following changes. To implement GCM in Android app using the application's default package name, see GCM: Getting Started.
To change package name of your app (e.g., new package name = com.example.newpackage
),
In AndroidManifest.xml
, update the package name in permission
and uses-permission
for C2D_MESSAGE
:
<permission android:name="com.example.newpackage.permission.C2D_MESSAGE" android:protectionLevel="signature" />
<uses-permission android:name="com.example.newpackage.permission.C2D_MESSAGE" />
In AndroidManifest.xml
, update the package name in category
of the 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
If your app's package name is com.example.newpackage
, your GCMIntentService
must be called com.example.newpackage.GCMIntentService
. If not,
Create a new class that extends
GCMBroadcastReceiver
and override 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
}
}
this is based on Google's documentation on GCMBroadcastReceiver:
By default, the
GCMBaseIntentService
class belongs to the application main package and is namedDEFAULT_INTENT_SERVICE_CLASS_NAME
. To use a new class, thegetGCMIntentServiceClassName(Context)
must be overridden.
In AndroidManifest.xml
, update the name of the receiver
:
<receiver
android:name="com.example.oldpackage.MyBroadcastReceiver"
... >
</receiver>
In AndroidManifest.xml
, update the name of the service
:
<service android:name="com.example.oldpackage.MyIntentService" />
GCMBroadcastReceiver
If your changed the package/class name of GCMBroadcastReceiver
:
In AndroidManifest.xml
, update the name of the receiver
:
<receiver
android:name="com.example.oldpackage.NewBroadcastReceiver"
... >
</receiver>
Verify that in AndroidManifest.xml
, the package name should appear at least 4 times:
In manifest
:
<manifest ...
package="com.example.newpackage" ...
In permission
:
<permission android:name="com.example.newpackage.permission.C2D_MESSAGE" android:protectionLevel="signature" />
In uses-permission
:
<uses-permission android:name="com.example.newpackage.permission.C2D_MESSAGE" />
In category
within intent-filter
within receiver
for the GCM broadcast receiver:
<category android:name="com.example.newpackage" />
If you changed your package name, uninstall the old app on your device/emulator before testing.
onRegistered()
) has changed.If you received your registration ID in onRegistered()
, you should see something like this in LogCat (tag GCMBroadcastReceiver
):
GCMBroadcastReceiver onReceive: com.google.android.c2dm.intent.REGISTRATION
GCMBroadcastReceiver GCM IntentService class: com.example.oldpackage.MyIntentService
Verify that the package/class name of the intent service is correct.
If you override getGCMIntentServiceClassName(Context)
in your own GCMBroadcastReceiver
, you should see something like this in LogCat (tag GCMRegistrar
):
GCMRegistrar Setting the name of retry receiver class to com.example.oldpackage.MyBroadcastReceiver
Verify that the package/class name of the broadcast receiver is correct.
You should put GCMIntentService class into your root application package. Here org.rferl
<service
android:name=".GCMIntentService"
android:enabled="true" />
and receiver
<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>
Because I use my code to generate lot of application with different package names I cannot use standard mypackage.GCMIntentService name.
I'm not sure whether you ask for a runtime or a build time solution. The other answers are runtime solutions so I thought I add some information on possibilites during build time.
In AndroidManifest, you can use the variable $PACKAGE_NAME
(available by default) which will refer to the package name you specified in the attribute package
in the manifest
root element.
The value of this package
attribute needs not be a hard coded string but can also be set dynamically via resource reference like so:
<manifest package="@string/app_package" ...>
...
<service
android:name="$PACKAGE_NAME.service.GCMIntentService"
android:enabled="true" />
...
</manifest>
Note .service
is just a subpackage that I included to show how you specify these. Of course, this solution would work only if your applications follow general rules like putting Service classes in a .service
subpackage.
Also note, that you can actually leave the root package off completely. It will be expanded by Android:
<manifest package="@string/app_package" ...>
...
<service
android:name=".service.GCMIntentService"
android:enabled="true" />
...
</manifest>
In effect, same as above.
If you are looking for a more flexible way to replace values in an AndroidManifest (or different files), you might want to have a look at the Ant Replace task (http://ant.apache.org/manual/Tasks/replace.html) or Resource Filtering (http://maven.apache.org/plugins/maven-resources-plugin/examples/filter.html) with Maven.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With