2013-05-29 90 views
5

我有PHP服務器端和Android客戶端應用程序的系統。 Android通過webservice發送參數,PHP處理GCM端。 PHP發送推送通知,在發送之前,它從DB獲取所有registrationid。問題是,相同的設備可能有兩個或更多的註冊ID。因此,推送通知發送到同一設備兩次或更多次。有沒有解決方案來解決這個問題?Android GCM一個設備有多個註冊ID

回答

2

您只需在數據庫中存儲每個設備的uniq標識。然後,您可以爲每個設備發送一個推送通知。

我從來沒有看到同一設備的多個註冊ID。奇怪的事情。

您是否正確管理註冊ID更新?

+0

謝謝大家,但主要問題不在於更新。在scenerio用戶可能有許多Android設備。由於這3個設備可能有7個註冊ID。我想發送3條推送消息,但GCM將發送7. – iravul

0

我認爲你的問題是你如何從設備獲得註冊ID。 您必須確保它發送一次REGID,並且GCM服務器請求刷新時,您必須將REGID重新發送到您的網絡服務器並存儲它,覆蓋舊的redID。 請參閱this部分android參考。

+0

謝謝所有,但主要問題並不是要更新。在scenerio用戶可能有許多Android設備。由於這3個設備可能有7個註冊ID。我想發送3條推送消息,但GCM將發送7個。 – iravul

+0

我不明白我的迴應...對於每個設備,Google GCM服務器都希望定期刷新ID ...檢查android api文檔...錯誤在一開始:每個設備必須在一次只有一個REGID。 – trullallero

4

GCM可以更改registrationId,並且您必須在服務器端更新它。

  • 當您發送消息時,結果可能包含將用於設備的新registrationId,因此您必須更新舊的registrationId。

看看這個link at Interpreting a success response section

如果MESSAGE_ID設置,檢查registration_id:如果registration_id設置,在您的服務器數據庫中的新值(規範ID)取代原來的ID。請注意,原始ID不是結果的一部分,因此您需要從請求中傳遞的registration_ids列表中獲取它(使用相同的索引)。

+0

謝謝大家,但主要問題並不是要更新。在scenerio用戶可能有許多Android設備。由於這3個設備可能有7個註冊ID。我想發送3條推送消息,但GCM將發送7條。 – iravul

+0

通過GCM服務,一個registrationId可識別設備/應用,因此如果用戶使用GCM將3個設備連接到服務器,則應該有3個註冊ID。在'GCMRegistrar.register'之前檢查,如果您的regId仍然存儲在'GCMRegistrar.getRegistrationId'中,那麼您生成的是超過需要的。 – AlexBcn

+0

壞主意,因爲:(terminal1)gcm(aaa)登錄user1和user2,如果您更改(terminal1)gcm(bbb),如果您發送GCM檢查終端(bbb)並且user2或user1未收到此通知。誤解! – delive

3

有時Google會更改註冊ID,並且您將擁有多個關聯的ID。發送通知的服務器(您的服務器)必須使用新ID更新數據庫。

欲瞭解更多信息查看本文檔:

http://developer.android.com/google/gcm/adv.html

他們說:

這是一個典型的ID

在服務器端,只要應用程序表現很好,一切應該正常工作。但是,如果應用程序中的某個錯誤會觸發同一設備的多個註冊,則可能很難調和狀態,並且最終可能會出現重複的消息。

GCM提供了一種稱爲「規範註冊ID」的功能,可以輕鬆從這些情況中恢復。規範註冊ID被定義爲您的應用程序請求的最後一次註冊的ID。這是服務器在向設備發送消息時應使用的ID。

如果稍後嘗試使用不同的登記ID來發送消息,GCM將處理該請求如常,但將包括在該響應的registration_id字段規範註冊ID。請確保使用此規範ID替換存儲在您的服務器中的註冊ID,因爲您最終使用的ID將停止工作。

+0

我面臨與同一設備上的兩個不同註冊ID的問題,但0 canonical_ids返回.. – neobie

0

你會在你的推響應得到規範標識。您需要用新的規範ID更新您的舊ID。

還有一個解決方案。更像是一個補丁。您可以在GCM請求JSON中傳遞參數'dry_run'。當我們將其設置爲true時,它會向設備ID發送假消息並生成響應。

設備不會得到一個消息,但你會得到您的回覆,因此你可以檢查哪些設備ID具有registration_ids在他們的結果,並從數據庫中刪除它們。

 $fields = array(
        'registration_ids' => $deviceId, 
        'data' => array("message" =>'fake_message'), 
        'dry_run'=>true 
        ); 

希望它有幫助。

2

這裏是我的解決這個問題。 當您發送GCM通知你得到這樣

Array 
    (
     [multicast_id] => 12345678910 
     [success] => 8 
     [failure] => 3 
     [canonical_ids] => 4 
     [results] => Array 
      (
       [0] => Array 
        (
         [error] => NotRegistered 
        ) 

       [1] => Array 
        (
         [message_id] => 0:1412242641156904%3dc89e2df9fd7ecd 
        ) 

       [2] => Array 
        (
         [registration_id] => APA91bH3WdWwqFCVKbvZXsf-gj28iWU5oYbSCRZYFp987CHasxwT_HOiE7dp8212XID0FMGVG2n4NLohFsEGYJ-LEA07xsgsKfT00xModQcx5QgTBmJtxlWgeaWFpz29z-iCPYbvOHEhqfwHmN-HIps7DiWntcs-Qg 
         [message_id] => 0:1412242641155639%3dc89e2df9fd7ecd 
        ) 

       [3] => Array 
        (
         [registration_id] => APA91bH3WdWwqFCVKbvZXsf-gj28iWU5oYbSCRZYFp987CHasxwT_HOiE7dp8212XID0FMGVG2n4NLohFsEGYJ-LEA07xsgsKfT00xModQcx5QgTBmJtxlWgeaWFpz29z-iCPYbvOHEhqfwHmN-HIps7DiWntcs-Qg 
         [message_id] => 0:1412242641155809%3dc89e2df9fd7ecd 
        ) 


       [4] => Array 
        (
         [message_id] => 0:1412242641157971%3dc89e2df9fd7ecd 
        ) 


       [5] => Array 
        (
         [registration_id] => APA91bGXo_gnfBZsvPoqJTYy1BWz0FQIkwlD1EmBtcxgWWfceYvd0ehWqVCtfd8n56VGYrvXCS2v48kTiA69BD7Sci0BA9a9bKTIg_MUEnDd79ssCK-miPG88DDGL4oKtB14cPbh-_xbgVRZllMOzwNZf_w5uJGR8g 
         [message_id] => 0:1412242641157969%3dc89e2df9fd7ecd 
        ) 


       [6] => Array 
        (
         [registration_id] => APA91bGXo_gnfBZsvPoqJTYy1BWz0FQIkwlD1EmBtcxgWWfceYvd0ehWqVCtfd8n56VGYrvXCS2v48kTiA69BD7Sci0BA9a9bKTIg_MUEnDd79ssCK-miPG88DDGL4oKtB14cPbh-_xbgVRZllMOzwNZf_w5uJGR8g 
         [message_id] => 0:1412242641157967%3dc89e2df9fd7ecd 
        ) 

      ) 

    ) 
陣列中

的響應有一個索引canonical_ids是4,這意味着u有4個用戶都產生了新的GCM IDS,現在你需要做的是將您的gcmids替換爲您在上述陣列中收到的新gcmids,下次您發送gcm通知時。

我的PHP應用是建立在笨框架所以這裏是我做的。 我有一個模型稱爲登錄,並在那裏我有與該用戶的用戶ID一起返回從數據庫gcmids作爲數組

function getAllRegIds(){ 
    $query = "SELECT gcmid,id FROM users_app WHERE gcmid IS NOT NULL AND gcmid != '' GROUP BY gcmid"; //group by incase a user loggedin with multiple userids in your a 
    $query = $this->db->query($query); 

    if($query->num_rows() > 0){ 
     $result = $query->result_array(); 
     $regids = array(); 

     foreach($result as $row){ 
      $regids[$row['id']] = $row['gcmid']; 
     } 
     return $regids; 
    }else{ 
     return false; 
    } 
} 

陣列看起來像這樣

Array(
    [29] => APA91bEYda3DVb... 
    [1] => APA91bF0yfdZjX4... 
    [12] => APA91bG-9fsBGT-... 
    [11] => APA91bGNRh_VWF... 
    [3] => APA91bGXo_gnfBZ... 
    [2] => APA91bH3WdWwqFC... 
    [26] => APA91bHn8Ufwe4... 
) 
的索引的函數

指標是價值gcmid

用戶ID調用此函數控制器功能裏面,這裏是實現

public function sendtoall(){ 
    $this->load->model('app/login'); 

    $result = $this->login->getAllRegIds(); //here i got all gcmids with userids as index 

    $message = $this->input->post('message'); 
    $chunks = array_chunk($result,1000); //broken the array into chunks of 1000 ids because gcm can only send message to 1000 ids at a time 

    $status = $this->sendNotification($chunks,$message); 


    if(!empty($status) && is_array($status)){ 
     foreach($status as $key=>$row){ 

      if(array_key_exists('canonical_ids',$row) && $row['canonical_ids'] > 0){ 
       $canonical_ids = $row['canonical_ids']; 

       if(array_key_exists('results',$row) && !empty($row['results']) && is_array($row['results'])){ 
        foreach($row['results'] as $k=>$v){ 
         if(array_key_exists('registration_id',$v)){ 

          $userid = array_search($chunks[$key][$k], $result); 
          $newgcmid = $v['registration_id']; 

          $this->login->updateGCMId($userid,$newgcmid); 
         } 
        } 
       } 
      } 
     } 
    } 

    echo json_encode($status); 
} 

你在評論中我已經把數組分成了1000個ID,因爲gcm一次可以發送消息給1000ids,並且調用一個函數sendNotification,返回gcm接收到的響應,這是我粘貼的那個數組擁有所有規範ID。

然後我檢查如果狀態不爲空並且是一個數組,FOREACH狀態,因爲它可以有多個響應陣列因爲我在1000個IDS塊發送通知,見下文

sendNotification實施我檢查它是否有索引canonical_ids並且大於0,這意味着有需要被替換的id,然後我檢查它是否具有索引result,而不是空的並且是一個數組。

的foreach result並獲得具有registration_id指數在它的指數,這意味着這些ID的鍵和值需要在我們的數據庫

得到其gcmid需要被替換爲用戶的userid被替換搜索result陣列,與用戶的oldgcm ID($chunks[$key][$k],第一個參數是有你需要的gcmid和第二塊的關鍵是在於gcmidindex

得到新gcmid所述results陣列

呼叫模型函數updateGCMId,通過useridnewgcmid

這裏是執行sendNotificationupdateGCMId的功能。

private function sendNotification($regids,$message){ 
    $status = array(); 
    $result = $regids; 
    if($result){ 
     foreach($result as $thousandids){ 
      $registatoin_ids=$thousandids; 

      $msg=array("message"=>$message); 



      $url='https://android.googleapis.com/gcm/send'; 
      $fields=array 
      (
       'registration_ids'=>$registatoin_ids, 
       'data'=>$msg 
      ); 
      $headers=array 
      (
       'Authorization: key=AIza..............', 
       'Content-Type: application/json' 
      ); 
      $ch=curl_init(); 
      curl_setopt($ch,CURLOPT_URL,$url); 
      curl_setopt($ch,CURLOPT_POST,true); 
      curl_setopt($ch,CURLOPT_HTTPHEADER,$headers); 
      curl_setopt($ch,CURLOPT_RETURNTRANSFER,true); 
      curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,false); 
      curl_setopt($ch,CURLOPT_POSTFIELDS,json_encode($fields)); 
      $result=curl_exec($ch); 
      curl_close($ch); 


      $result = json_decode($result,1); 

      $status[] = $result; 

     } 
    } 

    return $status; 
} 

update功能:

public function updateGCMId($userid,$gcmid){ 
     $query = 'UPDATE users_app SET 
        gcmid = "'.$gcmid.'" 
       WHERE id = "'.$userid.'"'; 
     $this->db->query($query); 
} 
0

Google的示例代碼隨附在Android Studio中的模板中生成的後端爲您執行此操作。檢查MessageEndpoint類,你會注意到他們正在檢查規範的id,如果它存在,那麼假設是regid已經改變,因此理想情況下需要針對該特定設備進行更新。

public void sendMessage(@Named("message") String message) throws IOException { 
    if (message == null || message.trim().length() == 0) { 
     log.warning("Not sending message because it is empty"); 
     return; 
    } 
    // crop longer messages 
    if (message.length() > 1000) { 
     message = message.substring(0, 1000) + "[...]"; 
    } 
    Sender sender = new Sender(API_KEY); 
    Message msg = new Message.Builder().addData("message", message).build(); 
    List<RegistrationRecord> records = ofy().load().type(RegistrationRecord.class).limit(10).list(); 
    for (RegistrationRecord record : records) { 
     Result result = sender.send(msg, record.getRegId(), 5); 
     if (result.getMessageId() != null) { 
      log.info("Message sent to " + record.getRegId()); 
      String canonicalRegId = result.getCanonicalRegistrationId(); 
      if (canonicalRegId != null) { 
       // if the regId changed, we have to update the datastore 
       log.info("Registration Id changed for " + record.getRegId() + " updating to " + canonicalRegId); 
       record.setRegId(canonicalRegId); 
       ofy().save().entity(record).now(); 
      } 
     } else { 
      String error = result.getErrorCodeName(); 
      if (error.equals(Constants.ERROR_NOT_REGISTERED)) { 
       log.warning("Registration Id " + record.getRegId() + " no longer registered with GCM, removing from datastore"); 
       // if the device is no longer registered with Gcm, remove it from the datastore 
       ofy().delete().entity(record).now(); 
      } else { 
       log.warning("Error when sending message : " + error); 
      } 
     } 
    } 
}