I'm having a hard time receiving messages via c2dm. Actually occasionally I receive messages from our server but it's literally just the half of the data. (I'm expecting a 4 digit number and received only the first 2 digits.. o.O"). However recently our broadcast receiver remained absolute silent. Therefore I started to experiment and pushing my own c2dm messages to the google server to see how thing's are doing.
At the bottom of the post you can find an example class how I send and receive c2dm messages. It's all pretty much self-standing so you can plug it into some activity and shoot of C2dmStaticTest.autopilot( yourSenderId, "foo bar", yourServerSideAuthCode, this, this.getPackageName());
Let me outline what is happening:
- Setting up static variables to be used in the BroadcastReceiver
- Registering the broadcast receiver and setting up the actions and category how it would been in the
androidManifest.xml
otherwise. - Sending a registration intent to c2dm server.
Notice: The local inbuilt-broadcast receiver will generate a log message for every received intent! Every time a log message is issued in the class the tag will be "c2dmTest".
When receiving the c2dm answer with the registration_id this will be logged as well and
then a c2dm message will be pushed.
I'm modelling here our server as close as I can to get more control.
As a back-test I also issue a fakeC2DM message miming an actual Intent and testing the broadcast receiver for functionality on the RECEIVE action.
Though I can receive a registration token from the c2dm Server I'm not receiving any messages I pushed to the server. As mentioned in the introduction I observe the same behaviour when our web server is sending messages.
I tried my very best and I'm confident I've implemented the broadcast receiver accordingly and since the server response code for the message sending is always 200/OK I also believe the message is delivered successfully to the server.
However the result is not the expected one but I'm really lacking any ideas what else I can do. Finding passages like "message delivery is not guaranteed" is not encouraging either. I mean right now nothing is delivered at all :C
import java.util.ArrayList;
import java.util.List;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.util.Log;
public class C2dmStaticTest {
private static String RECEIVE = "com.google.android.c2dm.intent.RECEIVE";
private static String REGISTER = "com.google.android.c2dm.intent.REGISTER";
private static String REGISTRATION = "com.google.android.c2dm.intent.REGISTRATION";
private static Context ctx;
private static String packageName;
private static String message;
private static String auth_code;
private static IntentFilter mIntFilt = new IntentFilter();
//@formatter:off
private static BroadcastReceiver mBroadRec = new BroadcastReceiver() {
@Override
public void onReceive( Context context, Intent intent ) {
final String broadcastAction = intent.getAction();
C2dmStaticTest.log("localReceiver onReceive for action: "+ broadcastAction);
if (C2dmStaticTest.REGISTRATION.equals(broadcastAction)) {
//execution continues here upon arrival of registration_id
String registration_id = intent.getStringExtra("registration_id");
C2dmStaticTest.log("registered for c2dm.\n key is: "+registration_id);
C2dmStaticTest.log("==> start real self test");
selfTestC2DM(registration_id, message, auth_code);
C2dmStaticTest.log("<== real self test done");
C2dmStaticTest.log("==> start fake test");
selfTestFake();
C2dmStaticTest.log("<== fake test done");
C2dmStaticTest.log("<~~ bye");
} else if (C2dmStaticTest.RECEIVE.equals(broadcastAction)) {
C2dmStaticTest.log("Received message: " + intent.getStringExtra("message") );
}
}
};
//@formatter:on
public static void autopilot( String sender_id, String message, String auth_code, Context ctx, String packageName ) {
// setup static variables
C2dmStaticTest.ctx = ctx;
C2dmStaticTest.packageName = packageName;
C2dmStaticTest.message = message;
C2dmStaticTest.auth_code = auth_code;
C2dmStaticTest.log("==> register broadcastReceiver");
mIntFilt.addAction("com.google.android.c2dm.intent.RECEIVE");
mIntFilt.addAction("com.google.android.c2dm.intent.REGISTRATION");
mIntFilt.addCategory(packageName);
ctx.registerReceiver(mBroadRec, mIntFilt);
C2dmStaticTest.log("==> register for c2dm");
C2dmStaticTest.registerForC2dm(ctx, sender_id);
// will continue in localBroadCastReceiver on Receive for REGISTRATION
}
private static void registerForC2dm( Context ctx, String sender_id ) {
Intent registrationIntent = new Intent(C2dmStaticTest.REGISTER);
registrationIntent.putExtra("app", PendingIntent.getBroadcast(ctx, 0, new Intent(), 0)); // boilerplate
registrationIntent.putExtra("sender", sender_id);
ctx.startService(registrationIntent);
}
private static void selfTestFake() {
Intent intent = new Intent();
intent.setAction(C2dmStaticTest.RECEIVE);
intent.putExtra("message", "Bender: \"kiss my shiny metal ass!\"");
intent.addCategory(C2dmStaticTest.packageName);
C2dmStaticTest.ctx.sendBroadcast(intent);
}
public static void selfTestC2DM( String registration_id, String message, String auth_code ) {
// create HttpClient
HttpClient mHttpClient = new DefaultHttpClient();
// create HttpPost
final HttpPost post = new HttpPost("https://android.apis.google.com/c2dm/send");
post.addHeader("Content-Type", "application/x-www-form-urlencoded;charset=UTF-8");
post.addHeader("Authorization", "GoogleLogin auth=" + auth_code);
// set payload data ...
final List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>();
nameValuePairs.add(new BasicNameValuePair("registration_id", registration_id));
nameValuePairs.add(new BasicNameValuePair("collapse_key", "foo"));
nameValuePairs.add(new BasicNameValuePair("data.message", message));
// ... and push it in the post
try {
post.setEntity(new UrlEncodedFormEntity(nameValuePairs));
} catch (final Exception e) {
e.printStackTrace(); // never had a problem here
}
// start it!
try {
HttpResponse resp = mHttpClient.execute(post);
if (resp.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
// now the message should be send, not?
C2dmStaticTest.log("Message send.\nServer response: " + resp.getStatusLine().getStatusCode());
} else {
C2dmStaticTest.log("Unexpected Server response.\nServer response: " + resp.getStatusLine().getStatusCode());
}
} catch (final Exception e) {
C2dmStaticTest.log("Unexpected Exception in execute()");
e.printStackTrace();
}
}
public static void log( String message ) {
Log.d("c2dmTest", message);
}
}