2014-03-04 33 views
3

在我的Android應用程序中,我使用Google的移動後端啓動器。我希望在服務器上的CloudEntities更新時收到通知,並且此通知應包含來自更新實體的一些數據。它可以在應用程序在後臺運行時運行,但是當我關閉應用程序時(通過在多任務視圖中將其擦除),我無法發出此類通知,因爲我無法訪問GCMIntentService中的CloudBackendAsync當應用程序未運行時的移動後端啓動器通知

我已經看到了這個問題: Mobile Backend handle continuous queries in background

但它並沒有在GCMIntentService訪問雲數據的問題的解決方案。

編輯:我的當前在GCMIntentService.java代碼

protected void onHandleIntent(Intent intent) { 

    //... (Check if the GCM Message is about an update of the Mobile Backend) 

      // dispatch message 
      if (GCM_TYPEID_QUERY.equals(typeId)) { 
       // Here, a broadcast is sent to the Main Activity of the app, which then downloads 
       // the new content and shows a notification in the CloudCallbackHandler. That 
       // only works when the Activity is running. 
       // So I would like to get access to the CloudBackendAsync instance from 
       // the app here to download data in the background and show a notification. 

       Intent messageIntent = new Intent(BROADCAST_ON_MESSAGE); 
       messageIntent.putExtras(intent); 
       messageIntent.putExtra("token", tokens[2]); 
       LocalBroadcastManager.getInstance(this).sendBroadcast(messageIntent); 
      } 
    //... 
} 

回答

1

Android客戶端不會從後端(只有子ID令牌從演示後端這是發送接收通過推送通知事件的消息內容足以通知客戶關於給定主題已收到一些新消息並刷新它)。

據我所知,除非我們更改後端代碼,否則無法直接獲取客戶端GCMIntentService.onHandleIntent()方法中的實體數據。我曾在後端類ProspectiveSearchServlet以下更改,使其包括以及推送通知中的消息內容:

protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException { 
    // Return if push notification is not enabled 
    if (!backendConfigManager.isPushEnabled()) { 
     log.info("ProspectiveSearchServlet: couldn't send push notification because it is disabled."); 
     return; 
    } 

    // dispatch GCM messages to each subscribers 
    String[] subIds = req.getParameterValues("id"); 
    // Each subId has this format "<regId>:query:<clientSubId>" 
    for (String subId : subIds) { 
     String regId = SubscriptionUtility.extractRegId(subId); 
     if (isSubscriptionActive(regId)) { 
     Entity matchedEntity = ProspectiveSearchServiceFactory.getProspectiveSearchService().getDocument(req); 
     if(matchedEntity != null) { 
      log.info(String.format("ProspectiveSearchServlet: matchedEntity.toString: " + matchedEntity.toString())); 
     } else { 
      log.info(String.format("ProspectiveSearchServlet: matchedEntity is null.")); 
     } 
     //Add the matchedEntity object. 
     sendPushNotification(regId, subId, matchedEntity); 
     } else { 
     SubscriptionUtility.clearSubscriptionAndDeviceEntity(Arrays.asList(regId)); 
     } 
    } 

    } 

    private void sendPushNotification(String regId, String subId, Entity matchedEntity) throws IOException { 
    SubscriptionUtility.MobileType type = SubscriptionUtility.getMobileType(subId); 

    if (SubscriptionUtility.MobileType.ANDROID == type) { 
     sendGcmAlert(subId, regId, matchedEntity); 
    } else if (SubscriptionUtility.MobileType.IOS == type) { 
     sendIosAlert(subId, new String[] {regId}, matchedEntity); 
    } 
    } 


    private void sendGcmAlert(String subId, String regId, Entity matchedEntity) 
     throws IOException { 
    String gcmKey = backendConfigManager.getGcmKey(); 
    boolean isGcmKeySet = !(gcmKey == null || gcmKey.trim().length() == 0); 

    // Only attempt to send GCM if GcmKey is available 
    if (isGcmKeySet) { 
     Sender sender = new Sender(gcmKey); 

     if(matchedEntity != null) { 
      Message message = new Message.Builder().addData(SubscriptionUtility.GCM_KEY_SUBID, subId) 
        //extra data.<key> elements can be added here 
        .addData("data.message", (String) matchedEntity.getProperty("message")) 
        .addData("data.updatedBy", (String) matchedEntity.getProperty("_updatedBy")) 
        .addData("data.owner", (String) matchedEntity.getProperty("_owner")) 
        .addData("data.kindName", (String) matchedEntity.getProperty("_kindName")) 
        .build(); 

      Result r = sender.send(message, regId, GCM_SEND_RETRIES); 
      if (r.getMessageId() != null) { 
      log.info("ProspectiveSearchServlet: GCM sent: subId: " + subId); 
      } else { 
      log.warning("ProspectiveSearchServlet: GCM error for subId: " + subId + 
       ", senderId: " + gcmKey + ", error: " + r.getErrorCodeName()); 
      ArrayList<String> deviceIds = new ArrayList<String>(); 
      deviceIds.add(regId); 
      SubscriptionUtility.clearSubscriptionAndDeviceEntity(deviceIds); 
      } 
     } 
    } else { 
     // Otherwise, just write a log entry 
     log.info(String.format("ProspectiveSearchServlet: GCM is not sent: GcmKey: %s ", 
      isGcmKeySet)); 
    } 
    } 

現在在客戶端,你可以在GCMIntentService以下更改,以顯示正確的推送通知(帶消息正文和用戶名):

@Override 
    protected void onHandleIntent(Intent intent) { 
     Bundle extras = intent.getExtras(); 
     GoogleCloudMessaging gcm = GoogleCloudMessaging.getInstance(this); 
     // The getMessageType() intent parameter must be the intent you received 
     // in your BroadcastReceiver. 
     String messageType = gcm.getMessageType(intent); 

     if (!extras.isEmpty()) { // has effect of unparcelling Bundle 
      /* 
      * Filter messages based on message type. Since it is likely that GCM will be 
      * extended in the future with new message types, just ignore any message types you're 
      * not interested in, or that you don't recognize. 
      */ 
      if (GoogleCloudMessaging.MESSAGE_TYPE_SEND_ERROR.equals(messageType)) { 
       Log.i(Consts.TAG, "onHandleIntent: message error"); 
      } else if (GoogleCloudMessaging.MESSAGE_TYPE_DELETED.equals(messageType)) {    
       Log.i(Consts.TAG, "onHandleIntent: message deleted"); 
     // If it's a regular GCM message, do some work. 
     } else if (GoogleCloudMessaging.MESSAGE_TYPE_MESSAGE.equals(messageType)) { 
      String subId = intent.getStringExtra(GCM_KEY_SUBID); 
      Log.i(Consts.TAG, "onHandleIntent: subId: " + subId); 
      String[] tokens = subId.split(":"); 
      String typeId = tokens[1]; 

      // dispatch message 
      if (GCM_TYPEID_QUERY.equals(typeId)) { 
       Intent messageIntent = new Intent(BROADCAST_ON_MESSAGE); 
       messageIntent.putExtras(intent); 
       messageIntent.putExtra("token", tokens[2]); 
       boolean isReceived = LocalBroadcastManager.getInstance(this).sendBroadcast(messageIntent); 
       //Check if the broadcast has been handled, if not show the notification. 
       if (!isReceived) { 
        Log.i(Consts.TAG, "A message has been recieved but no broadcast was handled."); 
        generateNotification(this, intent, tokens[2]); 
       } else { 
        Log.i(Consts.TAG, "A message has been recieved, broadcasted and handled."); 
       } 
      } 
     } 
    } 
    // Release the wake lock provided by the WakefulBroadcastReceiver. 
    GCMBroadcastReceiver.completeWakefulIntent(intent); 
} 

public static void generateNotification(Context context, Intent intent, String message) { 
    //Event keys 
    HashMap data = new HashMap(); 
    for (String key : intent.getExtras().keySet()) { 
     Log.d(Consts.TAG, "Message key: " + key + " value: " + intent.getExtras().getString(key)); 
     String eventKey = key.startsWith("data.") ? key.substring(5) : key; 
     data.put(eventKey, intent.getExtras().getString(key)); 
    } 

    CharSequence contentTitle = (CharSequence) data.get("updatedBy"); 
    if (contentTitle == null) contentTitle = "New Message"; 

    CharSequence contentText = (CharSequence) data.get("message"); 
    if (contentText == null) contentText = ""; 

    CharSequence userId = (CharSequence) data.get("updatedBy"); 
    Bitmap iconBitmap = getUserIcon(context, userId.toString()); 
    if (iconBitmap == null) iconBitmap = BitmapFactory.decodeResource(context.getResources(), R.drawable.ic_launcher); 

    // Creates an Intent for the Activity 
    Intent resultIntent = new Intent(context, GuestbookActivity.class); 
    // The stack builder object will contain an artificial back stack for the started Activity. 
    // This ensures that navigating backward from the Activity leads out of 
    // your application to the Home screen. 
    TaskStackBuilder stackBuilder = TaskStackBuilder.create(context); 
    // Adds the back stack for the Intent (but not the Intent itself) 
    stackBuilder.addParentStack(IntroductionActivity.class); 
    // Adds the Intent that starts the Activity to the top of the stack 
    stackBuilder.addNextIntent(resultIntent); 
    PendingIntent resultPendingIntent = stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT); 


    Notification.Builder mBuilder = new Notification.Builder(context); 
    mBuilder.setContentIntent(resultPendingIntent); 

    Notification notification = mBuilder 
    .setContentTitle(contentTitle) 
    .setContentText(contentText) 
    .setSmallIcon(R.drawable.notification_icon) 
    .setLargeIcon(iconBitmap) 
    .setTicker(contentTitle + ": " + contentText) 
    .setWhen(System.currentTimeMillis()) 
    .setAutoCancel(true) 
    .build(); 

    ///Get the notification ID, /it allows to update the notification later on. 
    int notifyID = 1; 
    String contentID = (String) data.get("id"); 
    if(contentID != null) { 
     notifyID = Integer.parseInt(contentID); 
    } 

    NotificationManager mNotificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); 
    mNotificationManager.notify(notifyID, notification); 
} 
相關問題