Ethan
Ethan

Reputation: 103

GCM Notification Receiver/Token Registration

EDIT: Figured it out -- see answer below

I'm attempting to generate registration tokens, store them in a server, and then use the tokens to send push notifications. At this point, I've successfully sent and stored registration tokens and am sending notifications from a web API, but they aren't arriving to my device. I was wondering if/what I should replace R.string.gcm_defaultSenderId with (i.e. the sender key from GCM?) I'm including my code for token registration as well as my notification listener below.

public class GCMRegistrationIntentService extends IntentService {

//Constants for success and errors
public static final String REGISTRATION_SUCCESS = "RegistrationSuccess";
public static final String REGISTRATION_ERROR = "RegistrationError";

private Context context;
private String sessionGUID = "";
private String userGUID = "";

//Class constructor
public GCMRegistrationIntentService() {
    super("");
}

@Override
protected void onHandleIntent(Intent intent) {
    context = getApplicationContext();
    sessionGUID = RequestQueueSingleton.getInstance(context).getSessionGUID();
    userGUID = RequestQueueSingleton.getInstance(context).getUserGUID();
    //Registering gcm to the device
    registerGCM();

}

//Registers the device to Google Cloud messaging and calls makeAPICall to send the registration
//token to the server
private void registerGCM() {
    //Registration complete intent initially null
    Intent registrationComplete;

    //declare a token, try to find it with a successful registration
    String token;
    try {
        //Creating an instanceid
        InstanceID instanceID = InstanceID.getInstance(this);

        //Getting the token from the instance id
        token = instanceID.getToken(getString(R.string.gcm_defaultSenderId),
                GoogleCloudMessaging.INSTANCE_ID_SCOPE, null);

        //Display the token, need to send to server
        Log.w("GCMRegIntentService", "token:" + token);

        String android_id = Settings.Secure.getString(context.getContentResolver(),
                Settings.Secure.ANDROID_ID);
        int osTypeCode = Constants.OST_ANDROID;
        JSONObject parms = new JSONObject();
        try {
            parms.put("deviceID", android_id);
            parms.put("OSTypeCode", osTypeCode);
            parms.put("token", token);
        } catch (JSONException e) {
            e.printStackTrace();
        }

        Transporter oTransporter = new Transporter(Constants.TransporterSubjectUSER,
                Constants.REGISTER_NOTIFICATION_TOKEN, "", parms, userGUID, sessionGUID);
        oTransporter.makeAPICall(getApplicationContext(), "");

        //on registration complete. creating intent with success
        registrationComplete = new Intent(REGISTRATION_SUCCESS);

        //Putting the token to the intent
        registrationComplete.putExtra("token", token);
    } catch (Exception e) {
        //If any error occurred
        Log.w("GCMRegIntentService", "Registration error");
        registrationComplete = new Intent(REGISTRATION_ERROR);
    }

    //Sending the broadcast that registration is completed
    LocalBroadcastManager.getInstance(this).sendBroadcast(registrationComplete);

}
}

And the listener service:

   public class GCMPushReceiverService extends GcmListenerService {

private static final String TAG = "GCMPushReceiverService";

//with every new message
@Override
public void onMessageReceived(String from, Bundle data){
    System.out.println("WE'VE RECIEVED A MESSAGE");
    String message = data.getString("message");
    Log.d(TAG, "From: " + from);
    Log.d(TAG, "Message: " + message);
    sendNotification(message);
}

private void sendNotification(String message) {
    Intent intent = new Intent(this, LogInPage.class);
    intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
    int requestCode = 0;
    PendingIntent pendingIntent =
            PendingIntent.getActivity(this, requestCode, intent, PendingIntent.FLAG_ONE_SHOT);
    Uri sound = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
    NotificationCompat.Builder noBuilder = new NotificationCompat.Builder(this);
    noBuilder.setContentTitle("title");
    noBuilder.setContentText(message);
    noBuilder.setContentIntent(pendingIntent);
    noBuilder.setSound(sound);
    NotificationManager notificationManager =
            (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
    notificationManager.notify(0, noBuilder.build()); //0 = ID of notification
}
 }

Lastly, as it may be of some assistance, the information transporter/networking class:

public class Transporter {
private String subject;
private String request;
private String key;
private Date lastUpdateDate;
private boolean forceLoad = false;
private Date requestDate;
private Date responseDate;
private int status;
private String statusMsg = "";
private String tempKey = "";

private JSONObject additionalInfo = null;
private JSONObject parameters;

public static String sessionGUID = "";
public static String userGUID = "";

public static String SERVER = Constants.qa_api;

//transporter object to interact with the server, containing information about the request
//made by the user
public  Transporter(String pSubject, String pRequest, String  pKey,
                               JSONObject parms, String userGUID, String sessionGUID)
{
    subject = pSubject;
    request = pRequest;
    key = pKey;
    parameters = parms;
    setUserGUID(userGUID);
    setSessionGUID(sessionGUID);
}

//implements an API call for a given transporter, takes 2 arguments:
//the application context (call getApplicationContext() whenever it's called)
//and a String that represents the field that we are trying to update (if there is one)
//i.e. if we are calling getUserFromSession(), we want the user guid so jsonID = "userGUID"
public void makeAPICall(final Context context, final String jsonID) {

    RequestQueue mRequestQueue =
            RequestQueueSingleton.getInstance(context).getRequestQueue();
    String targetURL = getServerURL() + "/Transporter.aspx";

    StringRequest postRequest = new StringRequest(Request.Method.POST, targetURL,
            new Response.Listener<String>() {
                @Override
                public void onResponse(String response) {
                    String parseXML= parseXML(response);
                    System.out.println("response: " + parseXML);

                    JSONObject lastResponseContent = null;
                    try {
                        lastResponseContent = new JSONObject(parseXML);
                    } catch (JSONException e) {
                        e.printStackTrace();
                    }
                    try {
                        if (lastResponseContent != null && !jsonID.equals("")) {
                            String info = lastResponseContent.getString(jsonID);
                            if (jsonID.equals("userGUID")) {
                                userGUID = info;
                                RequestQueueSingleton.getInstance(context).setUserGUID(userGUID);
                            }
                        }
                        //put other things in here to pull whatever info
                    } catch (JSONException e) {
                        e.printStackTrace();
                    }
                }
            }, new Response.ErrorListener() {
        @Override
        public void onErrorResponse(VolleyError error) {
            error.printStackTrace();
        }
    }) {
        @Override
        public byte[] getBody() throws AuthFailureError {
            String body = getXML(subject,
                    request, "",
                    sessionGUID, userGUID,  null, parameters);
            return body.getBytes();
        }
    };
    postRequest.setTag("POST");
    mRequestQueue.add(postRequest);
}

Upvotes: 1

Views: 349

Answers (2)

Ethan
Ethan

Reputation: 103

So the Volley calls are non-sequential so the first call (to get a userGUID) didn't return before the second call (to register for notifications), so while the token registration was "successful," there was no corresponding user information so it didn't know how/where to send the push notification. To resolve, I made a special case in the makeAPICall class which created another StringRequest which first basically did the normal getUserFromSession but then recursively called MakeAPICall with the new userGUID information. To avoid an infinite loop, I used an if else statement: (if userGUID == null || userGUID.equals("")) then I did the recursive call, so when the first call returned that conditional was always false and it would only make one recursive call. This answer may be a rambling a bit, but the key take away is using onResponse to make another Volley call for sequential requests. See: Volley - serial requests instead of parallel? and Does Volley library handles all the request sequentially

Upvotes: 0

DGLeiva
DGLeiva

Reputation: 111

you need to send a post to the url "https://android.googleapis.com/gcm/send":

private void sendGCM() {

    StringRequest strReq = new StringRequest(Request.Method.POST,
            "https://android.googleapis.com/gcm/send", new Response.Listener<String>() {

        @Override
        public void onResponse(String response) {

        }
    }, new Response.ErrorListener() {

        @Override
        public void onErrorResponse(VolleyError error) {
            NetworkResponse networkResponse = error.networkResponse;
            Log.e(TAG, "Volley error: " + error.getMessage() + ", code: " + networkResponse);
            Toast.makeText(getApplicationContext(), "Volley error: " + error.getMessage(), Toast.LENGTH_SHORT).show();
        }
    }) {

        @Override
        protected Map<String, String> getParams() {
            Map<String, String> params = new HashMap<>();
            params.put("data", "message that you send");
            params.put("to", "token gcm");

            Log.e(TAG, "params: " + params.toString());
            return params;
        }

        @Override
        public Map<String, String> getHeaders() throws AuthFailureError {
            Map<String,String> headers = new HashMap<String, String>();
            headers.put("Content-Type", "application/x-www-form-urlencoded;charset=UTF-8");
            headers.put("Authorization", "key="google key");
            return headers;
        }

    };
}

Upvotes: 0

Related Questions