2011-06-09 94 views
1

我無法使C2DM的發送部分正常工作。我在OutputStream中得到IOException out = conn.getOutputStream();C2DM,IO發送消息時發生異常

public void sendMessage() throws IOException{  
       String key = readFileAsString("acct/"+to+"/key"); 

       StringBuilder postDataBuilder = new StringBuilder(); 
       postDataBuilder.append("registration_id").append("=").append(key); 
       postDataBuilder.append("&").append("collapse_key").append("=").append("0"); 
       postDataBuilder.append("&").append("data.payload").append("=").append(URLEncoder.encode(to+"--"+"acct/"+to+"/1", UTF8)); 
       byte[] postData = postDataBuilder.toString().getBytes(UTF8); 

       URL url = new URL("https://android.apis.google.com/c2dm/send"); 

       HttpURLConnection conn = (HttpURLConnection) url.openConnection(); 
       conn.setDoOutput(true); 
       conn.setUseCaches(false); 
       conn.setRequestMethod("POST"); 
       conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); 
       conn.setRequestProperty("Content-Length", Integer.toString(postData.length));     
       conn.setRequestProperty("Authorization", "GoogleLogin auth=" + cl); 

      //------------------ 
       OutputStream out = conn.getOutputStream(); 
      //-------------------------- 
       out.write(postData); 
       out.close(); 

       int sw =conn.getResponseCode(); 
       System.out.println(""+sw); 
       switch (sw) { 
        case 200: 
         System.out.println("Success, but check for errors in the body"); 
         break; 
        case 503: 
         System.out.println("Service unavailable"); 
         break; 
        case 401: 
         System.out.println(" Invalid authentication token"); 
         break; 
       } 

      } 

謝謝!

+0

什麼是IOException發出的消息?或者它沒有消息? – 2011-06-09 17:59:47

+1

如果您發佈了實際的錯誤消息和堆棧跟蹤,這將有助於找出問題。 – 2011-06-09 18:00:35

+0

它只從catch中顯示「Communication Server問題」(IOException e) \t { \t System.err.println(「通信服務器問題」); \t System.exit(1); \t}。 SendMessage對象位於另一個類中的try-catch內。 – Misca 2011-06-09 18:12:49

回答

3

解決您收到的錯誤消息最常用的解決方案是定義自定義主機名驗證。您面臨的主要問題是Google的Android網址返回的域名是* .google.com。不幸的是,這會導致一些問題,因爲Android SDK位於android.apis.google.com。 JVM默認不會驗證這個組合(* .sdk.google.com是可以接受的)。

這裏是你如何創建自己的主機名驗證的例子:

URL url = new URL("https://android.apis.google.com/c2dm/send"); 

    HostnameVerifier hVerifier = new HostnameVerifier() { 
     public boolean verify(String hostname, SSLSession 
       session) { 
      return true; 
     } 
    }; 

    HttpsURLConnection conn = (HttpsURLConnection) url.openConnection(); 
    conn.setHostnameVerifier(hVerifier); 

如果你改變你的代碼,類似上述的東西,你提到的錯誤應該糾正。

編輯
這裏是一些測試代碼,在我的開發環境中完全有效。剛剛更新了您的應用程序特定信息的身份驗證信息以運行:

public class C2DMTest { 


    public static void main(String... args) throws Exception { 
     String auth = authorize(); 
     if (auth == null) { 
      System.out.println("No authorization returned"); 
      System.exit(1); 
     } 
     sendMessage(auth); 
    } 

    /** 
    * Perform an authorization request to access Google's C2DM 
    * API. 
    * 
    * @return The retrieved authorization request. 
    */ 
    private static String authorize() throws Exception { 
     String accountType = "GOOGLE"; 
     String service = "ac2dm"; 

     String source = "replace-me"; 
     String email = "replace-me"; 
     String passwd = "replace-me"; 


     StringBuilder params = new StringBuilder(); 
     params.append("accountType=").append(accountType) 
       .append("&Email=").append(URLEncoder.encode(email, UTF8)) 
       .append("&Passwd=").append(URLEncoder.encode(passwd, UTF8)) 
       .append("&service=").append(service) 
       .append("&source=").append(source); 
     byte[] postData = params.toString().getBytes(UTF8); 

     URL url = new URL("https://www.google.com/accounts/ClientLogin"); 
     HttpURLConnection conn = (HttpURLConnection) url.openConnection(); 
     conn.setDoOutput(true); 
     conn.setDoInput(true); 
     conn.setRequestMethod("POST"); 
     conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); 
     conn.setRequestProperty("Content-Length", Integer.toString(postData.length)); 

     //------------------ 
     OutputStream out = conn.getOutputStream(); 
     //-------------------------- 
     out.write(postData); 
     out.close(); 

     int sw = conn.getResponseCode(); 
     System.out.println("" + sw); 

     switch (sw) { 
      case 503: 
       System.out.println("Service unavailable"); 
       break; 
      case 401: 
       System.out.println(" Invalid authentication token"); 
       break; 
      default: 
       ByteArrayOutputStream baos = new ByteArrayOutputStream(); 
       InputStream in = conn.getInputStream(); 
       byte[] bytes = new byte[100]; 
       int len = -1; 
       while ((len = in.read(bytes)) != -1) { 
        baos.write(bytes, 0, len); 
       } 
       in.close(); 
       String input = baos.toString(); 
       Map<String, String> res = parseResponse(input); 
       return res.get("Auth"); 
     } 
     return null; 
    } 

    /** 
    * Parses a response string into a usable data map. 
    * 
    * @param response The response from Google 
    * @return A Map representation. 
    */ 
    private static Map<String, String> parseResponse(String response) { 
     Map<String, String> map = new HashMap<String, String>(); 
     if (response != null) { 
      String[] lines = response.split("\n"); 
      for (String line : lines) { 
       String[] parts = line.split("="); 
       if (parts.length == 2) { 
        map.put(parts[0], parts[1]); 
       } 
      } 
     } 
     return map; 
    } 

    private static String UTF8 = "UTF-8"; 


    /** 
    * Send message to mobile device. 
    * 
    * @param cl Google API auth code. 
    */ 
    public static void sendMessage(String cl) throws IOException { 
     String key = "invalid"; 

     StringBuilder postDataBuilder = new StringBuilder(); 
     postDataBuilder.append("registration_id").append("=").append(key); 
     postDataBuilder.append("&").append("collapse_key").append("=").append("0"); 
     postDataBuilder.append("&").append("data.payload").append("=").append(URLEncoder.encode("test-content", UTF8)); 
     byte[] postData = postDataBuilder.toString().getBytes(UTF8); 

     URL url = new URL("https://android.apis.google.com/c2dm/send"); 

     HostnameVerifier hVerifier = new HostnameVerifier() { 
      public boolean verify(String hostname, SSLSession 
        session) { 
       return true; 
      } 
     }; 

     HttpsURLConnection conn = (HttpsURLConnection) url.openConnection(); 
     conn.setHostnameVerifier(hVerifier); 
     conn.setDoOutput(true); 
     conn.setUseCaches(false); 
     conn.setRequestMethod("POST"); 
     conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); 
     conn.setRequestProperty("Content-Length", Integer.toString(postData.length)); 
     conn.setRequestProperty("Authorization", "GoogleLogin auth="+cl); 

     //------------------ 
     OutputStream out = conn.getOutputStream(); 
     //-------------------------- 
     out.write(postData); 
     out.close(); 

     int sw = conn.getResponseCode(); 
     System.out.println("" + sw); 
     switch (sw) { 
      case 200: 
       System.out.println("Success, but check for errors in the body"); 
       break; 
      case 503: 
       System.out.println("Service unavailable"); 
       break; 
      case 401: 
       System.out.println(" Invalid authentication token"); 
       break; 
     } 

    } 
} 
+0

我找不到HttpsURLConnection的setHostnameVerifier方法。必須緊密合作。 – Misca 2011-06-09 19:24:58

+0

你在看'HttpURLConnection'還是'HttpsURLConnection'?我已經驗證了Java 1.4及更高版本中存在'setHostnameVerifier'。 – 2011-06-09 19:31:50

+0

在HttpURLConnection。 HttpsURLConnection似乎已被棄用 – Misca 2011-06-09 19:37:25