2012-03-20 117 views
1

我已經編寫了一個使用C2DM的應用程序。我可以註冊設備併發送消息,但是我收到的設備突然未註冊,因此停止接收消息。我認爲我可以用下面的代碼來處理這個問題,但是看起來沒有收到「未註冊」的意圖(這沒有被確認,但是設備沒有被重新註冊)。c2dm設備自動註銷

我的問題是這是正常的設備是未註冊的藍色?如果是,則發送到設備的「取消註冊」消息?如何在不中斷服務的情況下處理此問題?其他人是否也遇到過這種情況?我可以通過讓用戶在應用程序中按下一個按鈕來重新註冊來處理這個問題,但除非必須,否則我不想這樣做。也考慮過在服務器上保存設備的狀態(註冊,未註冊),然後定期檢查應用程序是否仍在註冊。

任何幫助,將不勝感激!

public class MyC2dmReceiver extends BroadcastReceiver { 
private static String KEY = "c2dmPref"; 
private static String REGISTRATION_KEY = "registrationKey"; 
SharedPreferences prefs; 

private Context context; 

@Override 
public void onReceive(Context context, Intent intent) { 
    this.context = context; 
    if (intent.getAction().equals(
      "com.google.android.c2dm.intent.REGISTRATION")) { 
     handleRegistration(context, intent); 
    } else if (intent.getAction().equals(
      "com.google.android.c2dm.intent.RECEIVE")) { 
     handleMessage(context, intent); 
    } 
} 

private void handleRegistration(Context context, Intent intent) { 
    final SharedPreferences sharedPrefs = Util.getSharedPreferences(this.context); 
    String email = sharedPrefs.getString(Util.ACCOUNT_NAME, "");// 

    prefs = context.getSharedPreferences(KEY, Context.MODE_PRIVATE); 
    //String email = prefs.getString("email_for_c2dm", "");// 
    String registration = intent.getStringExtra("registration_id"); 
    if (intent.getStringExtra("error") != null) { 
     // Registration failed, should try again later. 
     Log.d("c2dm", "registration failed"); 
     String error = intent.getStringExtra("error"); 
     if (error == "SERVICE_NOT_AVAILABLE") { 
      Log.d("c2dm", "SERVICE_NOT_AVAILABLE"); 
     } else if (error == "ACCOUNT_MISSING") { 
      Log.d("c2dm", "ACCOUNT_MISSING"); 
     } else if (error == "AUTHENTICATION_FAILED") { 
      Log.d("c2dm", "AUTHENTICATION_FAILED"); 
     } else if (error == "TOO_MANY_REGISTRATIONS") { 
      Log.d("c2dm", "TOO_MANY_REGISTRATIONS"); 
     } else if (error == "INVALID_SENDER") { 
      Log.d("c2dm", "INVALID_SENDER"); 
     } else if (error == "PHONE_REGISTRATION_ERROR") { 
      Log.d("c2dm", "PHONE_REGISTRATION_ERROR"); 
     } 
} else if (intent.getStringExtra("unregistered") != null) { 
     // unregistration done, new messages from the authorized sender will 
     // be rejected 
     Log.d("c2dm", "unregistered"); 
     SharedPreferences c2dmPrefs=context.getSharedPreferences(KEY,  Context.MODE_PRIVATE); 
     c2dmPrefs.edit().putString("registrationKey", ""); 
     c2dmPrefs.edit().commit(); 
        //RegisterDevice launches the registration intent to get a new regKey 
     RegisterDevice register=new  RegisterDevice(FirefighterLog.getInstance()); 
} else if (registration != null) { 
     Log.d("c2dm", registration); 
     updateServerRegId(registration)) //sends regID to server and stores 
      Editor editor = context.getSharedPreferences(KEY, 
        Context.MODE_PRIVATE).edit(); 
      editor.putString(REGISTRATION_KEY, registration); 
      editor.commit(); 
      Toast.makeText(context, "Device registered successfully", 
        Toast.LENGTH_LONG); 
     } 

注意:updateServerRegId()將新的regID發送到服務器,並覆蓋它是否已經存在。我正在使用RequestFactory並將它作爲實體發送給appengine。

Android清單:

<uses-permission android:name="com.xxx.someapp.permission.C2D_MESSAGE" /> 
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" /> 
    <permission android:name="com.xxx.someapp.permission.C2D_MESSAGE" 
       android:protectionLevel="signature" /> 

    <receiver android:name=".C2DM.MyC2dmReceiver"  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="com.xxx.someapp" /> 
     </intent-filter> 
     <!-- Receive the registration id --> 
     <intent-filter> 
      <action android:name="com.google.android.c2dm.intent.REGISTRATION" /> 
      <category android:name="com.xxx.someapp" /> 
     </intent-filter> 
    </receiver> 
+0

初次註冊後多久纔會發生這些「註銷」?幾小時,幾天,幾周? – Squonk 2012-03-20 19:01:59

+0

您可以在C2DM接收器定義的位置發佈您的Android清單嗎? – 2012-03-20 19:03:44

+0

@MisterSquonk時間似乎有所不同,但通常是幾周。我沒有足夠的測試來確切地知道。 – Patrick 2012-03-20 23:52:18

回答

2

難道這僅僅是谷歌刷新註冊ID的情況下?從C2DM文檔爲Lifecycle Flow啓用C2DM節...

...

2.如果註冊成功,則C2DM服務器廣播登記意向這就給申請註冊ID。

應用程序應該存儲此ID供以後使用。 請注意,Google可能會定期刷新註冊ID,因此您應該設計您的應用程序,同時瞭解可以多次調用REGISTRATION Intent。您的應用程序需要能夠做出相應的響應。

...

註冊ID持續到程序明確地註銷本身,或直到谷歌刷新您的應用程序的註冊ID。

在文檔中沒有指出帶有「註銷」額外信息的Intent會作爲重新註冊的結果發送。唯一提到的是應用程序顯式取消註冊時。

看着你的代碼,它看起來不完整 - 目前還不清楚你如何處理註冊或重新註冊的可能性(例如Google刷新註冊ID時)。

在回覆我對你問題的評論時,你說這是「通常幾周」。如果你說了幾個小時(或者甚至是幾天),我可能會否認重新註冊導致問題的想法。不過,對Google來說,刷新註冊ID似乎是非常合理的時間段。

只是一個想法。

編輯:只要好爲你高興,updateServerRegId()是否正常工作,並更新了新的registration_id(如果需要的話),那麼我不能看到很多其他的指向手指。

我仍然懷疑這是否是維護無效(過期)註冊ID的情況。只需查看文檔...

每當應用程序服務器嘗試向其發送消息時,應用程序都會收到一個REGISTRATION Intent廣播。但由於各種原因,註冊ID可能不存在或無效:

  • 如果應用程序第一次運行,它還沒有註冊ID。
  • 如果應用程序未註冊,它沒有註冊ID。
  • C2DM服務器定期刷新註冊ID。

假設前兩個不適用,只剩下最後一個。

你在你原來的問題中說:「我得到的設備突然未註冊,因此停止接收消息」。您是否在發送消息到這些設備時查看了200響應中可能出現的錯誤代碼?查看How the Application Server Sends Messages的響應代碼部分,它可以更好地說明發生了什麼。

順便說一句,一個可能毫無關聯的東西(但我想我會提到它)...

if (error == "SERVICE_NOT_AVAILABLE") 

...不要使用==比較Strings,始終使用.equals(...)。如果你一路上遇到錯誤,那麼以這種方式比較錯誤字符串是行不通的,你可能會錯過一些東西。

+0

好的,感謝您發佈該文本。我曾經記得閱讀過這些內容。這聽起來像是發生了什麼,但是我的應用程序被寫入的方式應該在刷新時重新註冊。我將發佈更多的代碼,顯示我如何處理註冊意圖。 – Patrick 2012-03-21 00:42:57

+0

在查看ChromeToPhone源代碼後,我想知道是否需要喚醒。 ChromeToPhone在其Receiver上使用一個。在我的應用程序中,當用戶使用該應用程序時,首次註冊會發生。當刷新發生時,手機可能會睡着,也許接收器在註冊ID被髮送到我的服務器之前被殺死... – Patrick 2012-03-21 01:22:33

+0

對不起,我不知道wakelock,但我真的希望那不是'這種情況 - 我不想讓我的應用以任何方式讓用戶的手機「醒着」,只是基於Google可能刷新註冊ID的模糊可能性。另外,在清單中註冊的'BroadcastReceivers'不需要電話被喚醒來接收消息。無論如何,對不起,雖然我編輯了我的文章的結尾,但我已經用盡了想法 - 不確定它會有幫助,儘管注意到用'=='比較字符串的一點。祝你好運。 – Squonk 2012-03-21 01:38:17