Google Cloud Messaging (GCM) with local device groups on Android gives HTTP 401 error code

I am trying to get Google Cloud Messaging (GCM) to work on Android with local device groups, as described in https://developers.google.com/cloud-messaging/android/client-device-group . p>

I enabled the following services in the web console ( https://console.developers.google.com ):

  • Google Cloud Messaging for Android
  • Google Cloud Pub / Sub
  • Google+ API

I also created the following credentials:

  • API key (with the specified package name and SHA-1 certificate key)
  • OAuth 2.0 Client Identifiers (Web Application)

My Android code is as follows (error handling, etc. has been removed):

String account = ACCOUNT_NAME; // Eg " johndoe@google.com " String scope = "audience:server:client_id:" + WEB_APPLICATION_CLIENT_ID; String token = GoogleAuthUtil.getToken(context, account, scope); // Token is successfully found here :-) URL url = new URL("https://android.googleapis.com/gcm/notification"); HttpURLConnection connection = (HttpURLConnection) url.openConnection(); connection.setRequestMethod("POST"); connection.setDoOutput(true); connection.setDoInput(true); connection.setRequestProperty("project_id", NUMERICAL_PROJECT_ID); connection.setRequestProperty("Content-Type", "application/json"); connection.setRequestProperty("Accept", "application/json"); connection.connect(); JSONObject requestBody = new JSONObject(); requestBody.put("operation", "add"); requestBody.put("notification_key_name", "foobar"); requestBody.put("registration_ids", new JSONArray(Arrays.asList(new String[]{"42", "44"}))); requestBody.put("id_token", token); OutputStream os = connection.getOutputStream(); os.write(requestBody.toString().getBytes("UTF-8")); os.close(); // connection.getResponseCode() is now 401 

The submitted JSON for https://android.googleapis.com/gcm/notification looks something like this:

 { "operation": "add", "notification_key_name": "foobar", "registration_ids": ["42","44"], "id_token": "[veeeeeery long string]" } 

Response Content:

 <HTML> <HEAD> <TITLE>Unauthorized</TITLE> </HEAD> <BODY BGCOLOR="#FFFFFF" TEXT="#000000"> <H1>Unauthorized</H1> <H2>Error 401</H2> </BODY> </HTML> 

What am I doing wrong?

+2
source share
3 answers

Found a trick: you are using a google account to take id_token, you only need to use the email as notification_key_name. Therefore, if you use foo@gmail.com , you need to use this address as name_of_i_i_i_i_i_.

+2
source

Here is an example based on the correct answer greywolf82. The correct code should follow these principles (error handling, etc. Has been deleted):

 /////////////////////////////////////////////////////////////////////////// // Working example on how to create a locally (client-side) managed // // device group for Google Cloud Messaging. // // // // Thanks to greywolf82 for adding the final piece. // // Please vote on his answer. Thank you! // /////////////////////////////////////////////////////////////////////////// // Get token: String account = ACCOUNT_NAME; // Eg " johndoe@gmail.com " String scope = "audience:server:client_id:" + WEB_APPLICATION_CLIENT_ID; String idToken = GoogleAuthUtil.getToken(context, account, scope); // Get registration id: InstanceID instanceID = InstanceID.getInstance(this); String registration_id = instanceID.getToken( getString(R.string.gcm_defaultSenderId), GoogleCloudMessaging.INSTANCE_ID_SCOPE, null); // Set up HTTP connection: URL url = new URL("https://android.googleapis.com/gcm/googlenotification"); HttpURLConnection connection = (HttpURLConnection) url.openConnection(); connection.setRequestMethod("POST"); connection.setDoOutput(true); connection.setDoInput(true); connection.setRequestProperty("project_id", NUMERICAL_PROJECT_ID); connection.setRequestProperty("Content-Type", "application/json"); connection.setRequestProperty("Accept", "application/json"); connection.connect(); JSONObject requestBody = new JSONObject(); requestBody.put("operation", "add"); requestBody.put("notification_key_name", ACCOUNT_NAME); // You *must* use the email! requestBody.put("registration_ids", new JSONArray(Arrays.asList(new String[]{registration_id}))); requestBody.put("id_token", idToken); // Submit request body OutputStream os = connection.getOutputStream(); os.write(requestBody.toString().getBytes("UTF-8")); os.close(); // connection.getResponseCode() is now 200 :-) // Now read the server response contents from connection.getInputStream() 

The submitted JSON for https://android.googleapis.com/gcm/notification looks something like this:

 { "operation": "add", "notification_key_name": " johndoe@gmail.com ", "registration_ids": ["very long string here"], "id_token": "another very long string" } 

Response Content:

 { "notification_key": "your notification key is here --- voilΓ‘!" } 
+2
source

Here's how to do it using SERVER_API_KEY (not the best practice, but the best I've come up with):

First enter the application instance id:

 InstanceID instanceID = InstanceID.getInstance(this); String token = instanceID.getToken(getString(R.string.gcm_defaultSenderId), GoogleCloudMessaging.INSTANCE_ID_SCOPE, null); // Variable "token" now has the instance id. :-) 

Next, get the messaging identifier token:

 String account = ACCOUNT_NAME; // Eg " johndoe@google.com " String scope = "audience:server:client_id:" + WEB_APPLICATION_CLIENT_ID; String idToken = GoogleAuthUtil.getToken(context, account, scope); // Variable "idToken" now hods the messaging id token. :-) 

Now to the magic part. Create a new device group with an instance ID as a member:

 URL url = new URL("https://gcm-http.googleapis.com/gcm/notification"); // <-- Use this URL! HttpURLConnection connection = (HttpURLConnection) url.openConnection(); connection.setRequestMethod("POST"); connection.setDoOutput(true); connection.setDoInput(true); connection.setRequestProperty("Authorization", "key=" + SERVER_API_KEY); // <--- Auth! connection.setRequestProperty("project_id", NUMERICAL_PROJECT_ID); connection.setRequestProperty("Content-Type", "application/json"); connection.setRequestProperty("Accept", "application/json"); connection.connect(); JSONObject requestBody = new JSONObject(); requestBody.put("operation", "create"); // <--- Not "add" requestBody.put("notification_key_name", "foobar"); requestBody.put("registration_ids", new JSONArray(Arrays.asList(new String[]{token}))); // <--- Instance Id token here! requestBody.put("id_token", idToken); OutputStream os = connection.getOutputStream(); os.write(requestBody.toString().getBytes("UTF-8")); os.close(); InputStream is = connection.getInputStream(); String responseString = new Scanner(is, "UTF-8").useDelimiter("\\A").next(); is.close(); JSONObject response = new JSONObject(responseString); Log.d(TAG, "Server response:\n" + response.toString(4)); String notificationKey = response.getString("notification_key"); 

At this point, the "notificationKey" variable contains the notification key, which is the recipient that should be used when sending messages to this device group.

Send a message like this (use the value of "notificationKey" as the recipient parameter at the top):

 private void sendMessage(String recipient) throws IOException, JSONException { Log.i(TAG, "Sending message to: " + recipient); URL url = new URL("https://gcm-http.googleapis.com/gcm/send"); HttpURLConnection connection = (HttpURLConnection) url.openConnection(); connection.setRequestMethod("POST"); connection.setDoOutput(true); connection.setDoInput(true); Log.d(TAG, "Opening connection to " + url.toString()); connection.setRequestProperty("Authorization", "key=" + SERVER_API_KEY); connection.setRequestProperty("Content-Type", "application/json"); connection.setRequestProperty("Accept", "application/json"); connection.connect(); JSONObject requestBody = new JSONObject(); requestBody.put("to", recipient); JSONObject requestData = new JSONObject(); requestData.put("hello", "Hello World!"); requestData.put("hellodata", "42"); requestBody.put("data", requestData); Log.d(TAG, "Request body:\n" + requestBody.toString(4)); OutputStream os = connection.getOutputStream(); os.write(requestBody.toString().getBytes("UTF-8")); os.close(); Log.d(TAG, "Response code: " + connection.getResponseCode()); InputStream is = connection.getInputStream(); String responseString = new Scanner(is, "UTF-8").useDelimiter("\\A").next(); is.close(); } 

I could not do this without using the server API key. It might be worth exploring with different authorization header values ​​on the endpoint https://http.googleapis.com/gcm/googlenotification .

Hope this makes sense. Have some fun. :-)

0
source

Source: https://habr.com/ru/post/1204200/


All Articles