Android C2DM 实现消息推送
来源:互联网 发布:cbox网络官网下载 编辑:程序博客网 时间:2024/05/22 13:05
- 博客分类:
- Android
AndroidC2DMDemo
com.google.android.c2dm
C2DMBroadcastReceiver
- /*
- */
- package com.google.android.c2dm;
- import android.app.Activity;
- import android.content.BroadcastReceiver;
- import android.content.Context;
- import android.content.Intent;
- /**
- * Helper class to handle BroadcastReciver behavior.
- * - can only run for a limited amount of time - it must start a real service
- * for longer activity
- * - must get the power lock, must make sure it's released when all done.
- *
- */
- public class C2DMBroadcastReceiver extends BroadcastReceiver {
- @Override
- public final void onReceive(Context context, Intent intent) {
- // To keep things in one place.
- C2DMBaseReceiver.runIntentInService(context, intent);
- setResult(Activity.RESULT_OK, null /* data */, null /* extra */);
- }
- }
C2DMBaseReceiver
- /*
- * Copyright 2010 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- package com.google.android.c2dm;
- import java.io.IOException;
- import android.app.AlarmManager;
- import android.app.IntentService;
- import android.app.PendingIntent;
- import android.content.Context;
- import android.content.Intent;
- import android.os.PowerManager;
- import android.util.Log;
- /**
- * Base class for C2D message receiver. Includes constants for the
- * strings used in the protocol.
- */
- public abstract class C2DMBaseReceiver extends IntentService {
- private static final String C2DM_RETRY = "com.google.android.c2dm.intent.RETRY";
- public static final String REGISTRATION_CALLBACK_INTENT = "com.google.android.c2dm.intent.REGISTRATION";
- private static final String C2DM_INTENT = "com.google.android.c2dm.intent.RECEIVE";
- // Logging tag
- private static final String TAG = "C2DM";
- // Extras in the registration callback intents.
- public static final String EXTRA_UNREGISTERED = "unregistered";
- public static final String EXTRA_ERROR = "error";
- public static final String EXTRA_REGISTRATION_ID = "registration_id";
- public static final String ERR_SERVICE_NOT_AVAILABLE = "SERVICE_NOT_AVAILABLE";
- public static final String ERR_ACCOUNT_MISSING = "ACCOUNT_MISSING";
- public static final String ERR_AUTHENTICATION_FAILED = "AUTHENTICATION_FAILED";
- public static final String ERR_TOO_MANY_REGISTRATIONS = "TOO_MANY_REGISTRATIONS";
- public static final String ERR_INVALID_PARAMETERS = "INVALID_PARAMETERS";
- public static final String ERR_INVALID_SENDER = "INVALID_SENDER";
- public static final String ERR_PHONE_REGISTRATION_ERROR = "PHONE_REGISTRATION_ERROR";
- // wakelock
- private static final String WAKELOCK_KEY = "C2DM_LIB";
- private static PowerManager.WakeLock mWakeLock;
- private final String senderId;
- /**
- * The C2DMReceiver class must create a no-arg constructor and pass the
- * sender id to be used for registration.
- */
- public C2DMBaseReceiver(String senderId) {
- // senderId is used as base name for threads, etc.
- super(senderId);
- this.senderId = senderId;
- }
- /**
- * Called when a cloud message has been received.
- */
- protected abstract void onMessage(Context context, Intent intent);
- /**
- * Called on registration error. Override to provide better
- * error messages.
- *
- * This is called in the context of a Service - no dialog or UI.
- */
- public abstract void onError(Context context, String errorId);
- /**
- * Called when a registration token has been received.
- */
- public void onRegistered(Context context, String registrationId) throws IOException {
- // registrationId will also be saved
- }
- /**
- * Called when the device has been unregistered.
- */
- public void onUnregistered(Context context) {
- }
- @Override
- public final void onHandleIntent(Intent intent) {
- try {
- Context context = getApplicationContext();
- if (intent.getAction().equals(REGISTRATION_CALLBACK_INTENT)) {
- handleRegistration(context, intent);
- } else if (intent.getAction().equals(C2DM_INTENT)) {
- onMessage(context, intent);
- } else if (intent.getAction().equals(C2DM_RETRY)) {
- C2DMessaging.register(context, senderId);
- }
- } finally {
- // Release the power lock, so phone can get back to sleep.
- // The lock is reference counted by default, so multiple
- // messages are ok.
- // If the onMessage() needs to spawn a thread or do something else,
- // it should use it's own lock.
- mWakeLock.release();
- }
- }
- /**
- * Called from the broadcast receiver.
- * Will process the received intent, call handleMessage(), registered(), etc.
- * in background threads, with a wake lock, while keeping the service
- * alive.
- */
- static void runIntentInService(Context context, Intent intent) {
- if (mWakeLock == null) {
- // This is called from BroadcastReceiver, there is no init.
- PowerManager pm =
- (PowerManager) context.getSystemService(Context.POWER_SERVICE);
- mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
- WAKELOCK_KEY);
- }
- mWakeLock.acquire();
- // Use a naming convention, similar with how permissions and intents are
- // used. Alternatives are introspection or an ugly use of statics.
- String receiver = context.getPackageName() + ".C2DMReceiver";
- intent.setClassName(context, receiver);
- context.startService(intent);
- }
- private void handleRegistration(final Context context, Intent intent) {
- final String registrationId = intent.getStringExtra(EXTRA_REGISTRATION_ID);
- String error = intent.getStringExtra(EXTRA_ERROR);
- String removed = intent.getStringExtra(EXTRA_UNREGISTERED);
- if (Log.isLoggable(TAG, Log.DEBUG)) {
- Log.d(TAG, "dmControl: registrationId = " + registrationId +
- ", error = " + error + ", removed = " + removed);
- }
- if (removed != null) {
- // Remember we are unregistered
- C2DMessaging.clearRegistrationId(context);
- onUnregistered(context);
- return;
- } else if (error != null) {
- // we are not registered, can try again
- C2DMessaging.clearRegistrationId(context);
- // Registration failed
- Log.e(TAG, "Registration error " + error);
- onError(context, error);
- if ("SERVICE_NOT_AVAILABLE".equals(error)) {
- long backoffTimeMs = C2DMessaging.getBackoff(context);
- Log.d(TAG, "Scheduling registration retry, backoff = " + backoffTimeMs);
- Intent retryIntent = new Intent(C2DM_RETRY);
- PendingIntent retryPIntent = PendingIntent.getBroadcast(context,
- 0 /*requestCode*/, retryIntent, 0 /*flags*/);
- AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
- am.set(AlarmManager.ELAPSED_REALTIME,
- backoffTimeMs, retryPIntent);
- // Next retry should wait longer.
- backoffTimeMs *= 2;
- C2DMessaging.setBackoff(context, backoffTimeMs);
- }
- } else {
- try {
- onRegistered(context, registrationId);
- C2DMessaging.setRegistrationId(context, registrationId);
- } catch (IOException ex) {
- Log.e(TAG, "Registration error " + ex.getMessage());
- }
- }
- }
- }
C2DMessaging
- /*
- * Copyright 2010 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- package com.google.android.c2dm;
- import android.app.PendingIntent;
- import android.content.Context;
- import android.content.Intent;
- import android.content.SharedPreferences;
- import android.content.SharedPreferences.Editor;
- /**
- * Utilities for device registration.
- *
- * Will keep track of the registration token in a private preference.
- */
- public class C2DMessaging {
- public static final String EXTRA_SENDER = "sender";
- public static final String EXTRA_APPLICATION_PENDING_INTENT = "app";
- public static final String REQUEST_UNREGISTRATION_INTENT = "com.google.android.c2dm.intent.UNREGISTER";
- public static final String REQUEST_REGISTRATION_INTENT = "com.google.android.c2dm.intent.REGISTER";
- public static final String LAST_REGISTRATION_CHANGE = "last_registration_change";
- public static final String BACKOFF = "backoff";
- public static final String GSF_PACKAGE = "com.google.android.gsf";
- // package
- static final String PREFERENCE = "com.google.android.c2dm";
- private static final long DEFAULT_BACKOFF = 30000;
- /**
- * Initiate c2d messaging registration for the current application
- */
- public static void register(Context context,
- String senderId) {
- Intent registrationIntent = new Intent(REQUEST_REGISTRATION_INTENT);
- registrationIntent.setPackage(GSF_PACKAGE);
- registrationIntent.putExtra(EXTRA_APPLICATION_PENDING_INTENT,
- PendingIntent.getBroadcast(context, 0, new Intent(), 0));
- registrationIntent.putExtra(EXTRA_SENDER, senderId);
- context.startService(registrationIntent);
- // TODO: if intent not found, notification on need to have GSF
- }
- /**
- * Unregister the application. New messages will be blocked by server.
- */
- public static void unregister(Context context) {
- Intent regIntent = new Intent(REQUEST_UNREGISTRATION_INTENT);
- regIntent.setPackage(GSF_PACKAGE);
- regIntent.putExtra(EXTRA_APPLICATION_PENDING_INTENT, PendingIntent.getBroadcast(context,
- 0, new Intent(), 0));
- context.startService(regIntent);
- }
- /**
- * Return the current registration id.
- *
- * If result is empty, the registration has failed.
- *
- * @return registration id, or empty string if the registration is not complete.
- */
- public static String getRegistrationId(Context context) {
- final SharedPreferences prefs = context.getSharedPreferences(
- PREFERENCE,
- Context.MODE_PRIVATE);
- String registrationId = prefs.getString("dm_registration", "");
- return registrationId;
- }
- public static long getLastRegistrationChange(Context context) {
- final SharedPreferences prefs = context.getSharedPreferences(
- PREFERENCE,
- Context.MODE_PRIVATE);
- return prefs.getLong(LAST_REGISTRATION_CHANGE, 0);
- }
- static long getBackoff(Context context) {
- final SharedPreferences prefs = context.getSharedPreferences(
- PREFERENCE,
- Context.MODE_PRIVATE);
- return prefs.getLong(BACKOFF, DEFAULT_BACKOFF);
- }
- static void setBackoff(Context context, long backoff) {
- final SharedPreferences prefs = context.getSharedPreferences(
- PREFERENCE,
- Context.MODE_PRIVATE);
- Editor editor = prefs.edit();
- editor.putLong(BACKOFF, backoff);
- editor.commit();
- }
- // package
- static void clearRegistrationId(Context context) {
- final SharedPreferences prefs = context.getSharedPreferences(
- PREFERENCE,
- Context.MODE_PRIVATE);
- Editor editor = prefs.edit();
- editor.putString("dm_registration", "");
- editor.putLong(LAST_REGISTRATION_CHANGE, System.currentTimeMillis());
- editor.commit();
- }
- // package
- static void setRegistrationId(Context context, String registrationId) {
- final SharedPreferences prefs = context.getSharedPreferences(
- PREFERENCE,
- Context.MODE_PRIVATE);
- Editor editor = prefs.edit();
- editor.putString("dm_registration", registrationId);
- editor.commit();
- }
- }
org.wp.activity
AndroidC2DMDemo
- package org.wp.activity;
- import com.google.android.c2dm.C2DMessaging;
- import android.app.Activity;
- import android.os.Bundle;
- import android.util.Log;
- public class AndroidC2DMDemo extends Activity {
- private static final String TAG = "AndroidC2DMDemo";
- public static final String SENDER_ID = "wp.android.c2dm.demo@gmail.com";
- public static final String MESSAGE_KEY = "onewayonelife";
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
- Log.i(TAG, "start");
- C2DMessaging.register(this, SENDER_ID);
- }
- }
C2DMReceiver
- package org.wp.activity;
- import java.io.IOException;
- import android.app.Notification;
- import android.app.NotificationManager;
- import android.app.PendingIntent;
- import android.content.Context;
- import android.content.Intent;
- import android.os.Bundle;
- import android.util.Log;
- import com.google.android.c2dm.C2DMBaseReceiver;
- public class C2DMReceiver extends C2DMBaseReceiver {
- private static final String TAG = "C2DMReceiver";
- public C2DMReceiver() {
- super(AndroidC2DMDemo.SENDER_ID);
- }
- @Override
- public void onRegistered(Context context, String registrationId)
- throws IOException {
- Log.i(TAG, "registrationId:" + registrationId);
- }
- @Override
- public void onUnregistered(Context context) {
- }
- @Override
- protected void onMessage(Context context, Intent intent) {
- Bundle extras = intent.getExtras();
- if (extras != null) {
- String msg = extras.getString(AndroidC2DMDemo.MESSAGE_KEY);
- NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
- PendingIntent contentIntent = PendingIntent.getActivity(this, 0, new Intent(this, AndroidC2DMDemo.class), 0);
- Notification notification = new Notification(R.drawable.icon, msg, System.currentTimeMillis());
- notification.setLatestEventInfo(this, getString(R.string.app_name), msg, contentIntent);
- notification.flags |= Notification.FLAG_AUTO_CANCEL;
- notificationManager.notify(0, notification);
- }
- }
- @Override
- public void onError(Context context, String errorId) {
- }
- }
AndroidManifest.xml
- <?xml version="1.0" encoding="utf-8"?>
- <manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="org.wp.activity" android:versionCode="1" android:versionName="1.0">
- <application android:icon="@drawable/icon" android:label="@string/app_name">
- <activity android:name=".AndroidC2DMDemo" android:label="@string/app_name">
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity>
- <!-- In order to use the c2dm library, an application must declare a class
- with the name C2DMReceiver, in its own package,
- extending com.google.android.c2dm.C2DMBaseReceiver
- It must also include this section in the manifest. -->
- <service android:name=".C2DMReceiver" />
- <!-- Only C2DM servers can send messages for the app. If permission is
- not set - any other app can generate it -->
- <receiver android:name="com.google.android.c2dm.C2DMBroadcastReceiver"
- android:permission="com.google.android.c2dm.permission.SEND">
- <!-- Receive the actual message -->
- <intent-filter>
- <action android:name="com.google.android.c2dm.intent.RECEIVE" />
- <category android:name="org.wp.activity" />
- </intent-filter>
- <!-- Receive the registration id -->
- <intent-filter>
- <action android:name="com.google.android.c2dm.intent.REGISTRATION" />
- <category android:name="org.wp.activity" />
- </intent-filter>
- </receiver>
- </application>
- <uses-sdk android:minSdkVersion="8" />
- <!-- Only this application can receive the messages and registration result -->
- <permission android:name="org.wp.activity.permission.C2D_MESSAGE"
- android:protectionLevel="signature" />
- <uses-permission android:name="org.wp.activity.permission.C2D_MESSAGE" />
- <!-- This app has permission to register and receive message -->
- <uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
- <!-- Send the registration id to the server -->
- <uses-permission android:name="android.permission.INTERNET" />
- <!-- App must have this permission to use the library -->
- <uses-permission android:name="android.permission.WAKE_LOCK" />
- <uses-permission android:name="android.permission.GET_ACCOUNTS" />
- <uses-permission android:name="android.permission.USE_CREDENTIALS" />
- </manifest>
AndroidC2DMServerDemo
AndroidC2DMServer
- package org.wp.activity;
- import java.io.BufferedReader;
- import java.io.InputStreamReader;
- import java.io.OutputStream;
- import java.net.HttpURLConnection;
- import java.net.URL;
- import java.util.Date;
- import java.util.HashMap;
- import java.util.Map;
- public class AndroidC2DMServer {
- private static String clientLoginUrl = "https://www.google.com/accounts/ClientLogin";
- // 因为使用https的方式会提示出错,因此使用http的方式
- private static String pushUrl = "http://android.apis.google.com/c2dm/send";
- private static String registrationId = "APA91bHeWVX8t0hE-mhks0539soI9JaNFcU1r0_BEtDShnMy0lDDF3U2nR5NxC8F18y_oqj3nbzE3Pn9PpcilYRsK09lnsAaFhRcVCfS0zaztHt6BRXveHey73ipRBeJzpdd9xegxwsQih1B-Dr9Pj903tiorIZbcQ";
- public static void main(String args[]) {
- // 获取注册使用C2DM服务的用户账号的ClientLogin权限Auth值
- String auth = getAuthToken(clientLoginUrl, getClientLoginParams());
- if (auth != null && !"".equals(auth)) {
- // 按格式给C2DM服务器发送要Push的数据
- Map<String, String> data = new HashMap<String, String>();
- data.put("onewayonelife", "onewayonelife!" + new Date());
- sendPushMessage(pushUrl, getPushParams(registrationId, "wp", data, true), auth);
- }
- }
- public static String getClientLoginParams() {
- StringBuilder clsb = new StringBuilder();
- /** accountType 请求授权的帐户类型 **/
- clsb.append("accountType=HOSTED_OR_GOOGLE");
- /** Email 邮箱账号 **/
- clsb.append("&Email=wp.android.c2dm.demo@gmail.com");
- /** Passwd 邮箱账号密码 **/
- clsb.append("&Passwd=wpandroidc2dmdemo");
- /** service 请求授权的服务名称,C2DM服务的值为ac2dm **/
- clsb.append("&service=ac2dm");
- /** source 用来表示我们应用的字符串,类似companyName-applicationName-versionID **/
- clsb.append("&source=wp-c2dmdemo-1.0");
- return clsb.toString();
- }
- public static String getAuthToken(final String url, final String params) {
- String auth = null;
- try {
- byte[] postData = params.getBytes();
- URL requestUrl = new URL(url);
- HttpURLConnection connection = (HttpURLConnection) requestUrl.openConnection();
- // 上传数据,需要将setDoOutput方法的参数值设为true
- connection.setDoOutput(true);
- // Post请求不能使用缓存
- connection.setUseCaches(false);
- connection.setRequestMethod("POST");
- connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
- connection.setRequestProperty("Content-Length", Integer.toString(postData.length));
- connection.setRequestProperty("Charset", "UTF-8");
- OutputStream out = connection.getOutputStream();
- // 写入POST数据
- out.write(postData);
- out.flush();
- out.close();
- // 请求成功
- if (connection.getResponseCode() == 200) {
- BufferedReader br = new BufferedReader(new InputStreamReader(
- connection.getInputStream()));
- String responseLine;
- StringBuilder sb = new StringBuilder();
- while ((responseLine = br.readLine()) != null) {
- sb.append(responseLine);
- }
- auth = sb.substring(sb.indexOf("Auth=") + 5);
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- return auth;
- }
- public static String getPushParams(String registration_id, String collapse_key,
- Map<String, String> data, boolean delay_while_idle) {
- StringBuilder phsb = new StringBuilder();
- /** registration_id Android应用程序注册获得的id **/
- phsb.append("registration_id=" + registration_id);
- /** collapse_key 用一个任意的字符串来标识一组类似的信息
- * 当设备由离线状态重新上线以后,只有最后一条消息被发送到客户端
- * 这是为了避免当设备重新上线后有太多的信息发送到手机 **/
- phsb.append("&collapse_key=" + collapse_key);
- /** data.<key> 推送的信息,以键值对形式保存
- * 将会被包含在intent当中发送到android应用程序
- * 对于个数上并没有限制,只是在数据总大小上有要求 **/
- for (String key : data.keySet()) {
- phsb.append("&data." + key + "=" + data.get(key));
- }
- /** delay_while_idle 如果包含这个值
- * 表示不会在设备处于闲置状态的时候就立即发送推送消息
- * 服务器会等待设备变为活动状态的时候发送
- * 并且只有collapse_key标识的最后一条信息才会被发送 **/
- if (delay_while_idle)
- phsb.append("&delay_while_idle=0");
- return phsb.toString();
- }
- public static void sendPushMessage(final String url, final String params, final String auth) {
- try {
- byte[] postData = params.getBytes();
- URL requestUrl = new URL(url);
- HttpURLConnection connection = (HttpURLConnection) requestUrl.openConnection();
- // 上传数据,需要将setDoOutput方法的参数值设为true
- connection.setDoOutput(true);
- // Post请求不能使用缓存
- connection.setUseCaches(false);
- connection.setRequestMethod("POST");
- connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
- connection.setRequestProperty("Content-Length", Integer.toString(postData.length));
- connection.setRequestProperty("Charset", "UTF-8");
- connection.setRequestProperty("Authorization", "GoogleLogin auth=" + auth);
- OutputStream out = connection.getOutputStream();
- out.write(postData);
- out.flush();
- out.close();
- int responseCode = connection.getResponseCode();
- if (responseCode == 200) {
- BufferedReader br = new BufferedReader(new InputStreamReader(
- connection.getInputStream()));
- String responseLine;
- StringBuilder sb = new StringBuilder();
- while ((responseLine = br.readLine()) != null) {
- sb.append(responseLine);
- }
- if (sb.toString().startsWith("id=")) {
- System.out.println("推送信息发送成功!");
- }
- } else if (responseCode == 503) {
- System.out.println("Indicates that the server is temporarily unavailable (i.e., because of timeouts, etc ). Sender must retry later, honoring any Retry-After header included in the response. Application servers must implement exponential back off. Senders that create problems risk being blacklisted.");
- } else if (responseCode == 401) {
- System.out.println("Indicates that the ClientLogin AUTH_TOKEN used to validate the sender is invalid.");
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- }
- Android C2DM 实现消息推送
- Android C2DM学习 --云端推送
- android消息推送实现
- Android C2DM学习——云端推送
- Android C2DM学习——云端推送
- Android C2DM学习——云端推送
- Android C2DM学习——云端推送
- Android C2DM学习——云端推送
- Android C2DM学习——云端推送
- Android C2DM学习——云端推送
- Android C2DM学习——云端推送
- Android C2DM学习——云端推送
- Android C2DM学习——云端推送
- Android C2DM学习——云端推送
- Android百度云推送实现消息推送
- android中实现消息推送
- android中实现消息推送
- Android之消息推送实现
- 获取ios系统中已安装程序(MobileInstallation方式)
- makefile教程subst
- 水仙花数
- javascript 模板 引擎
- gawk
- Android C2DM 实现消息推送
- 中国地区2012年第三季度网络安全威胁报告
- 单一职责(SRP) --- 设计模式原则
- 三种常用数据库(Oracle、MySQL、SQLServer)的分页
- Apache 虚拟主机 VirtualHost 配置
- 为自己而转,弱校,加油!!——弱校ACM奋斗史
- 函数名与数组名
- Hyper-V 组件架构(1)—总体架构
- VC++2012编程演练数据结构《5》堆栈实现解析任意计算表达式