簡體   English   中英

在Android上具有本地設備組的Google Cloud Messaging(GCM)給出了HTTP錯誤代碼401

[英]Google Cloud Messaging (GCM) with local device groups on Android gives HTTP Error code 401

我正在嘗試讓https://developers.google.com/cloud-messaging/android/client-device-group上所述的Google Cloud Messaging(GCM)在Android上與本地設備組一起使用。

我已在網絡控制台( https://console.developers.google.com )中啟用了以下服務:

  • 適用於Android的Google Cloud Messaging
  • Google Cloud Pub / Sub
  • Google+ API

我還創建了以下憑據:

  • API密鑰(具有指定的程序包名稱和SHA-1證書密鑰打印)
  • OAuth 2.0客戶端ID(Web應用程序)

我的Android代碼如下所示(錯誤處理等已被刪除):

String account = ACCOUNT_NAME; // E.g. "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

提交到https://android.googleapis.com/gcm/notification的 JSON看起來像這樣:

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

響應內容為:

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

我究竟做錯了什么?

找到了竅門:您正在使用Google帳戶獲取id_token,您需要完全使用電子郵件作為notification_key_name。 因此,如果您使用的是foo@gmail.com,則需要將此地址用作notification_key_name。

這是根據greywolf82正確答案得出的結論。 正確的代碼應遵循以下原則(錯誤處理等已被剝離):

///////////////////////////////////////////////////////////////////////////
// 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; // E.g. "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()

提交到https://android.googleapis.com/gcm/notification的 JSON看起來像這樣:

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

響應內容為:

{
  "notification_key": "your notification key is here --- voilá!"
}

這是使用SERVER_API_KEY來完成的(不是最佳實踐,但是我已經達到了最好的水平):

首先,獲取一個應用程序實例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. :-)

接下來,獲取消息傳遞ID令牌:

String account = ACCOUNT_NAME; // E.g. "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. :-)

現在到魔術部分。 使用實例ID作為成員創建一個新的設備組:

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");

此時,變量“ notificationKey”保存了通知密鑰,該通知密鑰是向該設備組發送消息時必須使用的接收者。

發送這樣的消息(從上面使用“ notificationKey”值作為參數作為接收者):

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();
}

如果不使用服務器API密鑰,則無法成功完成此操作。 可能值得在https://http.googleapis.com/gcm/googlenotification端點上使用不同的Authorization標頭值進行調查。

希望這是有道理的。 玩得開心。 :-)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM