Android C2DM學習——客戶端代碼開發

一.基礎知識

    在前一部分中,我們從整體上快速介紹並實現了下Android C2DM的Push功能,在接下來的部分裏,我們先來回顧一下C2DM相關的整體上的知識,然後具體介紹說明實現的過程。

    在前面的C2DM框架說明中,我們已經知道,要實現Android的C2DM推送功能,需要涉及到三個功能實體:

    1. Android設備:推送消息的接收端,在上面會運行我們的客戶端程序

    2. 第三方服務器:這是我們自己控制的服務器,推送消息的發送端,利用C2DM服務器發送我們要推送的消息

    3. C2DM服務器:這是Google已經實現好的服務器,接收我們服務器的數據並把他們發送給對應的Android設備

    這三個功能實體部分,其中C2DM服務器是谷歌開發並且已經實現好的,我們只需按其要求的格式與其進行交互即可。我們自己要開發的爲另兩個實體部分:Android設備上運行的客戶端程序的開發和實現第三方服務器上的功能。

    並且在整個完整的C2DM推送過程中,要涉及到一些驗證用的信息:

    1. Sender ID:這是我們前面說過的在這裏註冊的賬號,這個Sender ID主要用來當Android設備上的客戶端程序向C2DM服務器註冊的時候驗證其有使用C2DM服務的權限。

    2. Application ID:使用C2DM功能的完整應用程序名,主要用來確保接收到的Push信息綁定到正確的應用程序。

    3. Registration ID:這是Android設備上的客戶端程序向C2DM服務器註冊成功後返回的ID,然後客戶端程序需要把這個ID發送給第三方服務器,然後第三方服務器使用這個ID值來向這個設備推送信息。

    4. Google User Account:需要在Android設備上登錄的谷歌賬戶,因爲C2DM服務是通過已經建立連接的谷歌後臺服務來找到對應消息要推送的設備。這個賬戶驗證信息只要在設備上登陸即可,不需要在客戶端程序中出現。

    5. Sender Auth Token:這是第一個Sender ID對應的使用C2DM服務的權限,在第三方服務器的程序中向Google申請,並且向C2DM服務器發送要推送的消息時要附帶這個信息。

    這5個和驗證相關的信息中,前4個在Android設備上的客戶端程序中都有相關,第三方服務器上的程序要使用第3個和第5個驗證信息。

    最後我們再從整體上來看下Cloud-To-Device Message的主要處理過程,更概括的話可以分爲三個步驟:

    1. 使能C2DM功能:第一步爲Android設備上的客戶端程序向C2DM服務器註冊,允許接收C2DM的推送消息。

    2. 發送推送消息:第二步爲第三方服務器通過C2DM服務器向Android設備發送推送信息。

    3.  接收推送信息:第三步爲Android設備上的客戶端程序接收來自C2DM服務器的推送消息。

    其中第一步和第三步是在Android設備上的客戶端程序中實現,第二步是在第三方服務器上實現。

     我們知道完整的C2DM推送功能要涉及Android設備客戶端和第三方服務器兩方面程序的開發,下面我們首先來具體學習客戶端部分的代碼開發。

二.客戶端開發說明

    客戶端要實現兩個步驟,使能C2DM功能和接收推送消息。

    使能C2DM功能,即客戶端程序向Google的C2DM服務器註冊C2DM服務,使程序允許接收推送消息,過程包含以下三個步驟:

    1. 首先客戶端程序需要向C2DM服務器啓動註冊需要的registration Intent。

    這個registration Intent(com.google.android.c2dm.intent.REGISTER)需要包含兩個內容信息:一個是Sender ID;另一個是Application ID;即我們上面說到的驗證信息的前兩個。

    2. 如果註冊成功,C2DM服務器會廣播一個com.google.android.c2dm.intent. REGISTRATION Intent,我們的客戶端程序需要響應並接收這個Intent,並且從其中獲取註冊成功返回的Registration ID。

    爲了後面的使用,客戶端程序需要保存這個Registration ID。因爲Google可能不定時更新Registration ID值,並通過REGISTRATION Intent進行告知,因此我們的程序需要能進行對應的響應,獲取新的Registration ID值並更新保存。

    3. 爲了完成註冊過程,最後一步是我們的客戶端程序需要把獲得的Registration ID值發送給我們的第三方服務器,並且一般來說第三方服務器要把Registration ID值保存在數據庫中。

    客戶端程序也可以發送com.google.android.c2dm.intent.UNREGISTER Intent取消註冊,從而不再接收C2DM服務器發送的推送信息。

    Android設備接收推送信息的過程包含以下三個步驟:

    1. Android系統獲取C2DM服務器推送過來的信息,並且從信息內容中提取鍵值對數據。

    2. Android系統向對應的客戶端程序發送com.google.android.c2dm.intent.RECEIVE Intent並在其中包含鍵值對數據。

    3. 客戶端程序響應RECEIVE Intent並從中提取出鍵值對數據,最後根據之前就和發送數據的第三方服務器端商量好的鍵值,提取對應的數據。

    前面介紹了很多相關知識,接下來我們重新實現一下客戶端的代碼。

三.實例開發

    爲了能繼續使用之前的Sender ID郵箱及已經註冊好的應用程序名等信息,我們還是創建一樣名爲AndroidC2DMDemo的工程。先刪除原來的工程或者把Eclipse切換到另一個Workspace下。

    創建AndroidC2DMDemo工程,並且包名爲com.ichliebephone.c2dm,Min SDK Version選擇8。

    爲了使用C2DM服務,客戶端程序要進行兩部分處理,

    1. 在Manifest.xml文件中聲明和C2DM相關的權限。

    2. 在Java代碼中實現C2DM相關的功能,如前面說的:

        a)和C2DM註冊相關的代碼

        b)接收C2DM服務器推送信息相關的代碼

    下面我們先來實現Java代碼部分。

    新建一個類C2DMRegistration,用來實現C2DM註冊相關功能。

public class C2DMRegistration {

	//註冊C2DM服務
	public static void register(Context context, String senderID){
		Intent registrationIntent = new Intent("com.google.android.c2dm.intent.REGISTER");
		registrationIntent.putExtra("app", PendingIntent.getBroadcast(context, 0, new Intent(), 0)); // boilerplate
		registrationIntent.putExtra("sender", senderID);
		context.startService(registrationIntent);
	}
	//取消C2DM服務
	public static void unregister(Context context){
		Intent unregIntent = new Intent("com.google.android.c2dm.intent.UNREGISTER");
		unregIntent.putExtra("app", PendingIntent.getBroadcast(context, 0, new Intent(), 0));
		context.startService(unregIntent);
	}
	//保存註冊成功獲得的registration_id值
	static void setRegistraionID(Context context, String registrationId){
        final SharedPreferences prefs = context.getSharedPreferences(
                "c2dm_preference",
                Context.MODE_PRIVATE);
        Editor editor = prefs.edit();
        editor.putString("dm_registration", registrationId);
        editor.commit();
	}
	//獲取保存的registration_id值
	public static String getRegistrationID(Context context){
        final SharedPreferences prefs = context.getSharedPreferences(
        		"c2dm_preference",
                Context.MODE_PRIVATE);
        String registrationId = prefs.getString("dm_registration", "");
        return registrationId;
	}
    //當取消C2DM服務時,清空之前保存着的registration_id值
    static void clearRegistrationId(Context context) {
        final SharedPreferences prefs = context.getSharedPreferences(
        		"c2dm_preference",
                Context.MODE_PRIVATE);
        Editor editor = prefs.edit();
        editor.putString("dm_registration", "");
        editor.commit();
}
    //當SERVICE_NOT_AVAILABLE時,需要回退一定時間後重新啓動註冊
    //獲取當前的回退等待時間
    static long getBackoff(Context context) {
        final SharedPreferences prefs = context.getSharedPreferences(
        		"c2dm_preference",
                Context.MODE_PRIVATE);
        //默認回退等待時間爲30000微秒
        return prefs.getLong("back_off", 30000);
    }
    //設置回退等待時間
    static void setBackoff(Context context, long backoff) {
        final SharedPreferences prefs = context.getSharedPreferences(
        		"c2dm_preference",
                Context.MODE_PRIVATE);
        Editor editor = prefs.edit();
        editor.putLong("back_off", backoff);
        editor.commit();
    }
}

    這個類主要實現了下向C2DM服務器發起和取消註冊,並且本地保存、清除和獲取註冊成功獲得的registration_id值,同時還有一個和重新啓動註冊相關的回退時間值的設置與獲取。

    其中註冊方法很簡單,就是發送一個com.google.android.c2dm.intent.REGISTER的Intent,其中包含兩個參數,一個是在C2DM網頁上註冊的Sender ID郵箱,另一個是程序的ID值。

    取消註冊的方法就是發送一個帶有程序ID值的com.google.android.c2dm.intent.UNREGISTER這樣的Intent。

    並且使用Perference鍵值對的方式保存獲取的registration_id值。

    接着再新建一個類C2DMReceiver,用來處理接收到的C2DM服務器的數據。

    客戶端程序會接收到C2DM服務器的兩種類型數據,並且這兩種類型的數據都是通過Intent的方式來處理的。一種類型是向C2DM服務器註冊後的回調數據,這時Intent對應的Action爲com.google.android.c2dm.intent.REGISTRATION;另一種類型是C2DM正式的推送數據,此時Intent對應的Action爲com.google.android.c2dm.intent.RECEIVE。

    因爲C2DMReceiver主要是用來接收Intent,因此需要擴展自BroadcastReceiver。對應的onReceive方法主要就是判斷接收C2DM的兩種類型數據:

@Override
	public void onReceive(Context context, Intent intent) {
		// TODO Auto-generated method stub
		if(intent.getAction().equals("com.google.android.c2dm.intent.REGISTRATION")){
			//如果是註冊返回的Intent
			handleRegistration(context, intent);
		}else if(intent.getAction().equals("com.google.android.c2dm.intent.RECEIVE")){
			//如果是接收到C2DM推送消息的Intent
			handleMessage(context, intent);
		}
	}

     當是接收到註冊返回的Intent時,就調用handleRegistration方法:

	//註冊後的回調處理
	private void handleRegistration(final Context context, Intent intent){
		//如果是註冊成功,則Intent中包含"registration_id"鍵對應的值
        final String registrationId = intent.getStringExtra("registration_id");
        //如果是註冊失敗,則Intent中包含"error"鍵對應的值
        String error = intent.getStringExtra("error");
        //如果是取消註冊,則Intent中包含"unregistered"鍵對應的值
        String removed = intent.getStringExtra("unregistered");
        //打印出接收到的registraton_id,爲了調試是查看
        Log.v(TAG, "handleRegistration");
        Log.v(TAG, "dmControl: registrationId = " + registrationId +
                ", error = " + error + ", removed = " + removed);
        //
        if(removed != null){
        	//如果存在"unregistered"鍵對應的值,則表示是取消註冊
        	onUnregistrated(context);
        	return;
        }else if(error != null){
        	//如果存在"error"鍵對應的值,則表示註冊失敗
        	onError(context, error);
        	return;
        }else{
        	//如果以上兩種情況都不存在,則表示註冊成功了
        	onRegistrated(context, registrationId);
        }
        
	}

     通過獲取註冊後返回的Intent中數據,來判斷是註冊失敗(error鍵值存儲的內容不爲空)、取消註冊(unregistered鍵值存儲的內容不爲空)還是註冊成功(registration_id鍵值存儲的內容不爲空)。

    當是取消註冊時,調用onUnregistrated方法進行處理:

	//取消註冊後的處理函數
	private void onUnregistrated(Context context){
		Log.v(TAG, "C2DMReceiver Unregister");
		//取消註冊的話,同時也清除保存着的registrationId值
    	C2DMRegistration.clearRegistrationId(context);
	}

    主要就是清除之前保存在本地的registrationId值

    當是註冊失敗時,調用onError方法進行處理:

	//出錯的處理函數
	private void onError(Context context, String errorId){
		Log.v(TAG, "C2DMReceiver Error with the reason: " + errorId);
		//首先清除保存着的registrationId值
		C2DMRegistration.clearRegistrationId(context);
		//判斷出錯的原因,一共有六種原因:SERVICE_NOT_AVAILABLE,ACCOUNT_MISSING,AUTHENTICATION_FAILED,
		//TOO_MANY_REGISTRATIONS,INVALID_SENDER,PHONE_REGISTRATION_ERROR
		if("SERVICE_NOT_AVAILABLE".equals(errorId)){
			//只有SERVICE_NOT_AVAILABLE這個是C2DM服務器沒有響應的原因,可以等待一段時間後重新發送註冊請求
			//其他原因都是屬於客戶端設備沒有處理好的原因
			long backoffTimeMs = C2DMRegistration.getBackoff(context);
			Intent retryIntent = new Intent("com.google.android.c2dm.intent.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);
            // 下一次重試時等待更長的時間
            backoffTimeMs *= 2;
            C2DMRegistration.setBackoff(context, backoffTimeMs);
		}
		
		
	}

    如果是註冊失敗,可以從Intent中獲取”error”鍵值對應數據,根據這個數據值可以查看失敗的原因。失敗的原因有:

    1. SERVICE_NOT_AVAILABLE:Google的服務器未響應。客戶端程序可以等待一段時間重新嘗試。

    2. ACCOUNT_MISSING:Android設備上缺少Google賬戶。在Android設備上登錄一個Google賬戶後再重新嘗試。

    3. INVALID_SENDER:Sender ID郵箱C2DM服務器不認識。這個需要把Sender ID郵箱號在C2DM網頁上進行註冊。

    4. PHONE_REGISTRATION_ERROR:當前Android設備不支持C2DM服務。使用2.2及以上版本Android系統來重新嘗試。

    除了以上四個常見的原因外還有AUTHENTICATION_FAILED和TOO_MANY_REGISTRATIONS原因。

    SERVICE_NOT_AVAILABLE是C2DM服務器臨時沒有響應,可以在代碼中進行重新嘗試註冊。其他都是設備端的原因,都不是可以在代碼中解決的。

    註冊的回調中除了以上兩個結果外,就是註冊成功返回registration_id的結果了,調用onRegistrated方法:

	//註冊成功後的處理函數
	private void onRegistrated(Context context, String registrationId){
		Log.v(TAG, "C2DMReceiver Register with the registrationId = " + registrationId);
		//註冊成功的話,保存獲取的registrationId值
		C2DMRegistration.setRegistraionID(context, registrationId);
		//然後把registrationId值發送給我們自己的第三方服務器
	}

    註冊成功後可以把registration_id值保存在本地。同時重要的是還要發送給我們自己的第三方服務器。發送的方式可以使用HTTP POST的方式等。當把registration_id值發送給了第三方服務器後,完整的註冊過程纔算完成,之後第三方服務器就可以使用這個registration_id來給我們的客戶端程序推送消息了。

 

     C2DM服務器正式的推送消息也在這個類裏進行處理。當接收到推送的消息時,就調用handleMessage方法:

	//接收到C2DM推送信息的回調處理
	private void handleMessage(Context context, Intent intent){
		onMessage(context, intent);
	}

在這個方法裏調用了onMessage回調方法:

	//接收到推送消息後的處理函數
	private void onMessage(Context context, Intent intent){
		Log.v(TAG, "C2DMReceiver Message");
		Bundle extras = intent.getExtras();
		if(extras!=null){
			//根據鍵值,提取對應的消息內容
			String msg = (String)extras.get(AndroidC2DMDemo.MESSAGE_KEY_ONE);
			Log.v(TAG, "The received msg = "+msg);
//			//在標題欄上顯示通知
			NotificationManager notificationManager = (NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE);
			Notification notification = new Notification(R.drawable.icon, msg, System.currentTimeMillis());
			PendingIntent contentIntent = PendingIntent.getActivity(context, 0, new Intent(context, AndroidC2DMDemo.class), 0);
			notification.setLatestEventInfo(context, context.getString(R.string.app_name), msg, contentIntent);
			notificationManager.notify(0, notification);			
		}
	}

    前面說過,Android設備接收推送消息有三個步驟,不過前兩步都已經在Android2.2及之後的系統中處理,我們的客戶端程序只要處理第三步:即從com.google.android.c2dm.intent.RECEIVE Intent中提取鍵值對數據。鍵值是應該和第三方服務器端商量好的。獲取鍵值對應的數據方式很簡單。爲了方便查看,下面的代碼是把獲取的數據在通知欄處顯示出來。

    處理C2DM數據的C2DMReceiver的完整代碼爲:

public class C2DMReceiver extends BroadcastReceiver{
	//
	private static final String TAG="C2DMReceiver";
	//
	@Override
	public void onReceive(Context context, Intent intent) {
		// TODO Auto-generated method stub
		if(intent.getAction().equals("com.google.android.c2dm.intent.REGISTRATION")){
			//如果是註冊返回的Intent
			handleRegistration(context, intent);
		}else if(intent.getAction().equals("com.google.android.c2dm.intent.RECEIVE")){
			//如果是接收到C2DM推送消息的Intent
			handleMessage(context, intent);
		}
	}
	//註冊後的回調處理
	private void handleRegistration(final Context context, Intent intent){
		//如果是註冊成功,則Intent中包含"registration_id"鍵對應的值
        final String registrationId = intent.getStringExtra("registration_id");
        //如果是註冊失敗,則Intent中包含"error"鍵對應的值
        String error = intent.getStringExtra("error");
        //如果是取消註冊,則Intent中包含"unregistered"鍵對應的值
        String removed = intent.getStringExtra("unregistered");
        //打印出接收到的registraton_id,爲了調試是查看
        Log.v(TAG, "handleRegistration");
        Log.v(TAG, "dmControl: registrationId = " + registrationId +
                ", error = " + error + ", removed = " + removed);
        //
        if(removed != null){
        	//如果存在"unregistered"鍵對應的值,則表示是取消註冊
        	onUnregistrated(context);
        	return;
        }else if(error != null){
        	//如果存在"error"鍵對應的值,則表示註冊失敗
        	onError(context, error);
        	return;
        }else{
        	//如果以上兩種情況都不存在,則表示註冊成功了
        	onRegistrated(context, registrationId);
        }
        
	}
	//接收到C2DM推送信息的回調處理
	private void handleMessage(Context context, Intent intent){
		onMessage(context, intent);
	}
	//和C2DM推送信息相關的具體處理函數
	//註冊成功後的處理函數
	private void onRegistrated(Context context, String registrationId){
		Log.v(TAG, "C2DMReceiver Register with the registrationId = " + registrationId);
		//註冊成功的話,保存獲取的registrationId值
		C2DMRegistration.setRegistraionID(context, registrationId);
		//然後把registrationId值發送給我們自己的第三方服務器
	}
	//取消註冊後的處理函數
	private void onUnregistrated(Context context){
		Log.v(TAG, "C2DMReceiver Unregister");
		//取消註冊的話,同時也清除保存着的registrationId值
    	C2DMRegistration.clearRegistrationId(context);
	}
	//出錯的處理函數
	private void onError(Context context, String errorId){
		Log.v(TAG, "C2DMReceiver Error with the reason: " + errorId);
		//首先清除保存着的registrationId值
		C2DMRegistration.clearRegistrationId(context);
		//判斷出錯的原因,一共有六種原因:SERVICE_NOT_AVAILABLE,ACCOUNT_MISSING,AUTHENTICATION_FAILED,
		//TOO_MANY_REGISTRATIONS,INVALID_SENDER,PHONE_REGISTRATION_ERROR
		if("SERVICE_NOT_AVAILABLE".equals(errorId)){
			//只有SERVICE_NOT_AVAILABLE這個是C2DM服務器沒有響應的原因,可以等待一段時間後重新發送註冊請求
			//其他原因都是屬於客戶端設備沒有處理好的原因
		}
		
		
	}
	//接收到推送消息後的處理函數
	private void onMessage(Context context, Intent intent){
		Log.v(TAG, "C2DMReceiver Message");
		Bundle extras = intent.getExtras();
		if(extras!=null){
			//根據鍵值,提取對應的消息內容
			String msg = (String)extras.get(AndroidC2DMDemo.MESSAGE_KEY_ONE);
			Log.v(TAG, "The received msg = "+msg);
//			//在標題欄上顯示通知
			NotificationManager notificationManager = (NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE);
			Notification notification = new Notification(R.drawable.icon, msg, System.currentTimeMillis());
			PendingIntent contentIntent = PendingIntent.getActivity(context, 0, new Intent(context, AndroidC2DMDemo.class), 0);
			notification.setLatestEventInfo(context, context.getString(R.string.app_name), msg, contentIntent);
			notificationManager.notify(0, notification);			
		}
	}
}

    主要就是處理了向C2DM註冊後的數據和正式推送數據的接收。在實際使用中,需要添加向我們自己的服務器發送registration_id值。

    然後還需要在AndroidC2DMDemo中啓動向C2DM服務器註冊:

public class AndroidC2DMDemo extends Activity {
    /** Called when the activity is first created. */
	private static final String TAG = "AndroidC2DMDemo";
	public static final String SENDER_ID = "[email protected]"; //使用C2DM服務的用戶賬戶
	public static final String MESSAGE_KEY_ONE = "msg";   //和服務器商量好的接收消息的鍵值key
	//
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        //
        Log.v(TAG, "Start");
        if(C2DMRegistration.getRegistrationID(this).equals("")){
	        //如果本地沒有保存registration_id值,則向C2DM服務器註冊
        	Log.v(TAG, "Register C2DM");
	        C2DMRegistration.register(this, SENDER_ID);
        }else{
        	//否則說明已經向C2DM服務器註冊過了
        	Log.v(TAG, "C2DM registered");
        }
    }    
}

 

    完成了Java代碼部分,最後還要在Manifest.xml文件中聲明和C2DM相關的權限等信息。

    爲了使用C2DM特性,Manifest.xml需要包含以下幾個部分:

    1.  <uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />

    這個說明程序有註冊和接收C2DM消息的權限

    2.  <uses-permission android:name="android.permission.INTERNET" />

    這個在向第三方服務器發送registration_id值時需要使用

    3.  設置和聲明一個這樣的權限:程序的包名 + ".permission.C2D_MESSAGE,如:   <permission android:name="com.ichliebephone.c2dm.permission.C2D_MESSAGE"

       android:protectionLevel="signature"></permission>

<uses-permission android:name="com.ichliebephone.c2dm.permission.C2D_MESSAGE"/>

    這表明只有這個應用才能接收到對應Push的消息及註冊時返回的結果。

    4.  包含com.google.android.c2dm.intent.RECEIVE 和 com.google.android.c2dm.intent.REGISTRATION這兩個Action的接收器Receiver,並且類別設置爲程序的包名,同時還需要有com.google.android.c2dm.SEND這個權限,如:

        <receiver android:name=".C2DMReceiver"

                 android:permission="com.google.android.c2dm.permission.SEND">

            <!-- 可以接收實際的Push數據 -->

            <intent-filter>

                <action android:name="com.google.android.c2dm.intent.RECEIVE" />

                <category android:name="com.ichliebephone.c2dm" />

            </intent-filter>

            <!-- 可以接收註冊後返回的registration_id -->

            <intent-filter>

                <action android:name="com.google.android.c2dm.intent.REGISTRATION" />

                <category android:name="com.ichliebephone.c2dm" />

            </intent-filter>

        </receiver>

    這表明這個程序能給接收到C2DM服務器發送的數據

    5.  最後還要設置最小SDK版本爲8:<uses-sdk android:minSdkVersion="8" />

    完整的Manifest.xml文件爲:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
      package="com.ichliebephone.c2dm"
      android:versionCode="1"
      android:versionName="1.0">
    <uses-sdk android:minSdkVersion="8" />
	<!-- 設置一個權限,使只有這個應用才能接收到對應Push的消息及註冊時返回的結果  -->
	<permission android:name="com.ichliebephone.c2dm.permission.C2D_MESSAGE"
		android:protectionLevel="signature"></permission>
	<uses-permission android:name="com.ichliebephone.c2dm.permission.C2D_MESSAGE"/>
	<!-- 設置註冊和接收C2DM Push消息的權限 -->
	<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
	<!-- 設置聯網權限,在把registration_id發送給服務器的時候要用 -->
	<uses-permission android:name="android.permission.INTERNET" />
	
    <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>

        <!-- 這個程序能給接收到谷歌C2DM服務器發送的數據,並聲明對應的權限 -->
        <receiver android:name=".C2DMReceiver"
                  android:permission="com.google.android.c2dm.permission.SEND">
            <!-- 可以接收實際的Push數據 -->
            <intent-filter>
                <action android:name="com.google.android.c2dm.intent.RECEIVE" />
                <category android:name="com.ichliebephone.c2dm" />
            </intent-filter>
            <!-- 可以接收註冊後返回的registration_id -->
            <intent-filter>
                <action android:name="com.google.android.c2dm.intent.REGISTRATION" />
                <category android:name="com.ichliebephone.c2dm" />
            </intent-filter>
        </receiver>
        
    </application>
</manifest>

    完整的工程目錄爲:

圖1 工程目錄

    最後創建帶有Google API的Android2.2版本及以上的AVD,啓動模擬器,在Accounts & Sync中添加賬戶,就可以運行程序了。

    和前一部分的測試方法類似,運行程序後,會在DDMS中看到獲取的registrationId值:

圖2 獲取的registrationId值

    然後使用獲取的registrationId值利用curl命令模擬第三方服務器向C2DM服務器發送要推送的信息:

圖3 使用curl向C2DM服務器發送推送信息

    然後一會我們就可以在DDMS中看到客戶端程序收到的推送數據:

圖4 獲取到的推送數據

    同時Android模擬器中也會在通知欄上顯示接收到的推送數據:

圖5 模擬器接收到的推送數據

    通過測試結果可知,我們實現了Android的C2DM推送功能。

四. 總結

    以上我們簡單介紹了Android的C2DM推送功能實現過程中,在Android設備上的客戶端部分需要實現的內容,及實際的實現過程。不過因爲只是用來說明實現過程,因此代碼寫的儘量簡單,並且爲了更容易查看,把各種常量字符串等也直接寫在代碼中了。如果在實際使用中,可以參考Google的C2DM例子Chrome To Phone中的代碼,只要包含其com.google.android.c2dm包中的三個文件,並且新建一個擴展C2DMBaseReceiver的子類來處理註冊消息和推送消息的回調即可,其代碼更加茁壯。不過通過以上的介紹說明,我們應該可以更好的理解C2DM客戶端部分的實現了。

    以後我們繼續學習下C2DM服務器部分的實現。


    文章對應的完整代碼例子下載地址:

    http://download.csdn.net/source/3462743

    注:文章參加第二屆 Google 暑期大學生博客分享大賽 - 2011 Android 成長篇 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章