发送消息时C2DM,IOException

时间:2011-06-09 17:01:13

标签: java android

我无法让C2DM的发送部分工作。我在OutputStream out = conn.getOutputStream();

得到IOException
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;
                 }

            }

谢谢!

1 个答案:

答案 0 :(得分: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;
        }

    }
}