【问题标题】:How to implement C2DM in android?如何在android中实现C2DM?
【发布时间】:2011-06-25 08:35:55
【问题描述】:

我正在搜索如何使用 C2DM 发送通知。我发现了一些东西并使用它可以生成Registration Key 以及Authentication Key

但在那之后,在ServerSimulator 类(服务器端代码)中,我得到了 401 错误(401 未经授权)。现在我手动传递了用户名和密码,并在我的 Android 设备中同步了它们。我得到和以前一样的错误。

当我点击发送消息按钮时,我遇到了这个问题..

我被这个查询卡住了。有没有人设法做到这一点?

public class ServerSimulator extends Activity 
{
    private SharedPreferences prefManager;
    private final static String AUTH = "authentication";

    private static final String UPDATE_CLIENT_AUTH = "Update-Client-Auth";

    public static final String PARAM_REGISTRATION_ID = "registration_id";

    public static final String PARAM_DELAY_WHILE_IDLE = "delay_while_idle";

    public static final String PARAM_COLLAPSE_KEY = "collapse_key";

    private static final String UTF8 = "UTF-8";

    // Registration is currently hardcoded
    private final static String YOUR_REGISTRATION_STRING = "APA91bFkxmtIj5XiBU-Cze64s0gXNb7OmiWWZg-qLKibpLsVXaWq1X7hoRV9Ld9COYXirZAgkYegZBdBfUGt3lgtuhNJopvHB0KJ5ZyJ6Kt_HYRrZhgdJ1Y";

    private SharedPreferences prefs;

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        prefManager = PreferenceManager.getDefaultSharedPreferences(this);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.mymenu, menu);
        return super.onCreateOptionsMenu(menu);
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
        case R.id.menuitem_user:
            Intent intent = new Intent(this, UserPreferences.class);
            startActivity(intent);
            break;
        default:
            break;
        }
        return false;
    }

    public void getAuthentification(View view) {
        SharedPreferences prefs = PreferenceManager
                .getDefaultSharedPreferences(this);

        HttpClient client = new DefaultHttpClient();
        HttpPost post = new HttpPost(
                "https://www.google.com/accounts/ClientLogin");

        try {

            List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(1);
            nameValuePairs.add(new BasicNameValuePair("Email","myEmail id")));
            nameValuePairs.add(new BasicNameValuePair("Passwd","my password")));
            nameValuePairs.add(new BasicNameValuePair("accountType", "GOOGLE"));
            nameValuePairs.add(new BasicNameValuePair("source","Google-cURL-Example"));
            nameValuePairs.add(new BasicNameValuePair("service", "ac2dm"));

            post.setEntity(new UrlEncodedFormEntity(nameValuePairs));
            HttpResponse response = client.execute(post);
            BufferedReader rd = new BufferedReader(new InputStreamReader(
                    response.getEntity().getContent()));

            String line = "";
            while ((line = rd.readLine()) != null) {
                Log.e("HttpResponse", line);
                if (line.startsWith("Auth=")) {
                    Editor edit = prefManager.edit();
                    edit.putString(AUTH, line.substring(5));
                    edit.commit();
                    String s = prefManager.getString(AUTH, "n/a");
                    Toast.makeText(this, s, Toast.LENGTH_LONG).show();
                }

            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void showAuthentification(View view) {
        String s = prefManager.getString(AUTH, "n/a");
        Toast.makeText(this, s, Toast.LENGTH_LONG).show();
    }

    public void sendMessage(View view) {
        try {
            Log.e("Tag", "Started");
            String auth_key = prefManager.getString(AUTH, "n/a");
            // Send a sync message to this Android device.
            StringBuilder postDataBuilder = new StringBuilder();
            postDataBuilder.append(PARAM_REGISTRATION_ID).append("=")
                    .append(YOUR_REGISTRATION_STRING);

            // if (delayWhileIdle) {
            // postDataBuilder.append("&").append(PARAM_DELAY_WHILE_IDLE)
            // .append("=1");
            // }
            postDataBuilder.append("&").append(PARAM_COLLAPSE_KEY).append("=")
                    .append("0");

            postDataBuilder.append("&").append("data.payload").append("=")
                    .append(URLEncoder.encode("Lars war hier", UTF8));

            byte[] postData = postDataBuilder.toString().getBytes(UTF8);

            // Hit the dm URL.

            URL url = new URL("https://android.clients.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;charset=UTF-8");
            conn.setRequestProperty("Content-Length",
                    Integer.toString(postData.length));
            conn.setRequestProperty("Authorization", "GoogleLogin auth="
                    + auth_key);

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

            int responseCode = conn.getResponseCode();

            Log.e("Tag", String.valueOf(responseCode));
            // Validate the response code

            if (responseCode == 401 || responseCode == 403) {
                // The token is too old - return false to retry later, will
                // fetch the token
                // from DB. This happens if the password is changed or token
                // expires. Either admin
                // is updating the token, or Update-Client-Auth was received by
                // another server,
                // and next retry will get the good one from database.
                Log.e("C2DM", "Unauthorized - need token");
            }

            // Check for updated token header
            String updatedAuthToken = conn.getHeaderField(UPDATE_CLIENT_AUTH);
            if (updatedAuthToken != null && !auth_key.equals(updatedAuthToken)) {
                Log.i("C2DM",
                        "Got updated auth token from datamessaging servers: "
                                + updatedAuthToken);
                Editor edit = prefManager.edit();
                edit.putString(AUTH, updatedAuthToken);
            }

            String responseLine = new BufferedReader(new InputStreamReader(
                    conn.getInputStream())).readLine();

            // NOTE: You *MUST* use exponential backoff if you receive a 503
            // response code.
            // Since App Engine's task queue mechanism automatically does this
            // for tasks that
            // return non-success error codes, this is not explicitly
            // implemented here.
            // If we weren't using App Engine, we'd need to manually implement
            // this.
            if (responseLine == null || responseLine.equals("")) {
                Log.i("C2DM", "Got " + responseCode
                        + " response from Google AC2DM endpoint.");
                throw new IOException(
                        "Got empty response from Google AC2DM endpoint.");
            }

            String[] responseParts = responseLine.split("=", 2);
            if (responseParts.length != 2) {
                Log.e("C2DM", "Invalid message from google: " + responseCode
                        + " " + responseLine);
                throw new IOException("Invalid response from Google "
                        + responseCode + " " + responseLine);
            }

            if (responseParts[0].equals("id")) {
                Log.i("Tag", "Successfully sent data message to device: "
                        + responseLine);
            }

            if (responseParts[0].equals("Error")) {
                String err = responseParts[1];
                Log.w("C2DM",
                        "Got error response from Google datamessaging endpoint: "
                                + err);
                // No retry.
                throw new IOException(err);
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}

【问题讨论】:

    标签: android push-notification android-c2dm


    【解决方案1】:

    您目前正在以较旧的方式实施 C2DM。您正在做的方式提供了很多可定制性,但没有多少人需要这种可定制性。有了新的 Google Plugin 2.4 Beta,他们实际上已经开始将其全部集成,这非常好。

    我强烈建议您观看 Google IO Android + AppEngine。他们展示了如何非常简单地将 Android、AppEngine 和 C2DM 集成在一起。您可以创建他们称之为“AppEngine Connected Android Project”的东西。因此,您无需制作 ServerSimulator,而是实际使用可以免费设置的真实服务器。

    http://www.youtube.com/watch?v=M7SxNNC429U

    如果您想移动到另一台服务器,则必须重新编写服务器端代码,然后只需更改它发布到的 URL。很简单。我强烈建议您查看此示例并使用股票代码,因为它可以让您立即使用:

    仅供参考,在注册到真正托管的 appengine 服务器时,代码中目前存在一个错误(因为它在 beta atm 中)(在本地一切正常)。它尝试发送过期的注册令牌。我一直在与谷歌开发人员联系,他们为我提供了修复。让我知道你是否达到了你需要的程度。

    【讨论】:

    • 嗨 spierce7,感谢您的回答。但我不明白你到底想说什么。你能给我示例代码吗?谢谢
    • 嗨 spierce7 - 我现在就是这个时候 - 有没有机会发布你的修复?
    • 他们已经更新了 2.4 测试版(我什至不确定 2.4 GPE 是否仍处于测试阶段)。不管怎样,随着我的更新,我创建了一个新项目,他们给我的更改现已添加到官方项目中。
    猜你喜欢
    • 2011-09-18
    • 2011-05-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-12-28
    • 2018-03-02
    • 2012-07-29
    相关资源
    最近更新 更多