0

我決定實施Google Cloud Messaging推送通知以通知用戶有關新聞。我認爲這是話題消息。爲了實施我拿了Google GCM sample。我在清單中添加了所有需要的服務,權限和接收者。當我向Google GCM服務器發送發佈請求時,對消息標識的響應是真實的,但設備不會通知。有什麼事?我在Bluestacks測試。GCM不能正常工作

我的清單:

<?xml version="1.0" encoding="utf-8"?> 
<manifest xmlns:android="http://schemas.android.com/apk/res/android" 
    xmlns:tools="http://schemas.android.com/tools" 
    package="packagename" > 

    <uses-permission android:name="android.permission.INTERNET" /> 
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> 
    <uses-permission android:name="android.permission.WAKE_LOCK" /> 
    <uses-permission android:name="android.permission.GET_ACCOUNTS" /> 
    <uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" /> 
    <uses-permission android:name="packagename.permission.C2D_MESSAGE" /> 

    <permission android:name="packagename.permission.C2D_MESSAGE" 
     android:protectionLevel="signature" /> 

    <application 
     android:name=".App" 
     android:allowBackup="true" 
     android:icon="@mipmap/ic_launcher" 
     android:label="@string/app_name" 
     android:theme="@style/AppTheme" > 
     <activity 
      android:name=".activities.MainActivity" 
      android:configChanges="keyboardHidden|orientation|screenSize" 
      android:label="@string/app_name" 
      android:launchMode="singleTop" > 
      <intent-filter> 
       <action android:name="android.intent.action.MAIN" /> 

       <category android:name="android.intent.category.LAUNCHER" /> 
      </intent-filter> 
     </activity> 
     <activity 
      android:name=".activities.BiographyActivity" 
      android:configChanges="keyboardHidden|orientation|screenSize" 
      android:label="@string/title_biography" 
      android:parentActivityName=".activities.MainActivity" 
      tools:ignore="UnusedAttribute" > 
      <meta-data 
       android:name="android.support.PARENT_ACTIVITY" 
       android:value=".activities.MainActivity" /> 
     </activity> 
     <activity 
      android:name=".activities.AboutActivity" 
      android:label="@string/title_about_app" > 
      <meta-data 
       android:name="android.support.PARENT_ACTIVITY" 
       android:value=".activities.MainActivity" /> 
     </activity> 
     <activity android:name=".activities.CrashReportDialog" 
      android:theme="@style/Theme.Dialog" 
      android:process=":error_report" 
      android:launchMode="singleInstance" 
      android:excludeFromRecents="true" 
      android:finishOnTaskLaunch="true" /> 

     <meta-data 
      android:name="com.google.android.gms.version" 
      android:value="@integer/google_play_services_version" /> 

     <receiver 
      android:name="com.google.android.gms.gcm.GcmReceiver" 
      android:exported="true" 
      android:permission="com.google.android.c2dm.permission.SEND" > 
      <intent-filter> 
       <action android:name="com.google.android.c2dm.intent.RECEIVE" /> 
       <action android:name="com.google.android.c2dm.intent.REGISTRATION" /> 
       <category android:name="packagename" /> 
      </intent-filter> 
     </receiver> 
     <service 
      android:name="packagename.AppGcmListenerService" 
      android:exported="false" > 
      <intent-filter> 
       <action android:name="com.google.android.c2dm.intent.RECEIVE" /> 
      </intent-filter> 
     </service> 
     <service 
      android:name="packagename.AppInstanceIDListenerService" 
      android:exported="false"> 
      <intent-filter> 
       <action android:name="com.google.android.gms.iid.InstanceID"/> 
      </intent-filter> 
     </service> 
     <service 
      android:name="packagename.RegistrationIntentService" 
      android:exported="false"> 
     </service> 
    </application> 

</manifest> 

主要活動:

public class MainActivity extends AppCompatActivity {  

    private BroadcastReceiver mRegistrationBroadcastReceiver; 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.activity_main); 

     mRegistrationBroadcastReceiver = new BroadcastReceiver() { 
      @Override 
      public void onReceive(Context context, Intent intent) { 
       SharedPreferences sharedPreferences = 
         PreferenceManager.getDefaultSharedPreferences(context); 
       boolean sentToken = sharedPreferences 
         .getBoolean(GcmPreferences.SENT_TOKEN_TO_SERVER, false); 
       if (sentToken) { 
        Log.i("GCM", "Success!"); 
       } else { 
        Log.i("GCM", "Error!"); 
       } 
      } 
     }; 

     Intent intent = new Intent(this, RegistrationIntentService.class); 
     startService(intent); 
    } 
} 

GCM偵聽器服務:

public class AppGcmListenerService extends GcmListenerService { 

    private static final String TAG = "GCM"; 

    /** 
    * Called when message is received. 
    * 
    * @param from SenderID of the sender. 
    * @param data Data bundle containing message data as key/value pairs. 
    *    For Set of keys use data.keySet(). 
    */ 
    @Override 
    public void onMessageReceived(String from, Bundle data) { 
     String message = data.getString("message"); 
     Log.d(TAG, "From: " + from); 
     Log.d(TAG, "Message: " + message); 

     /** 
     * Production applications would usually process the message here. 
     * Eg: - Syncing with server. 
     *  - Store message in local database. 
     *  - Update UI. 
     */ 

     /** 
     * In some cases it may be useful to show a notification indicating to the user 
     * that a message was received. 
     */ 
     sendNotification(message); 
    } 

    /** 
    * Create and show a simple notification containing the received GCM message. 
    * 
    * @param message GCM message received. 
    */ 
    private void sendNotification(String message) { 
     Intent intent = new Intent(this, MainActivity.class); 
     intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); 
     PendingIntent pendingIntent = PendingIntent.getActivity(this, 0 /* Request code */, intent, 
       PendingIntent.FLAG_ONE_SHOT); 

     Uri defaultSoundUri= RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION); 
     NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this) 
       .setSmallIcon(R.drawable.ic_app) 
       .setContentTitle("GCM Message") 
       .setContentText(message) 
       .setAutoCancel(true) 
       .setSound(defaultSoundUri) 
       .setContentIntent(pendingIntent); 

     NotificationManager notificationManager = 
       (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); 

     notificationManager.notify(0 /* ID of notification */, notificationBuilder.build()); 
    } 
} 

實例ID偵聽器服務:

public class AppInstanceIDListenerService extends InstanceIDListenerService { 

    /** 
    * Called if InstanceID token is updated. This may occur if the security of 
    * the previous token had been compromised. This call is initiated by the 
    * InstanceID provider. 
    */ 
    @Override 
    public void onTokenRefresh() { 
     // Fetch updated Instance ID token and notify our app's server of any changes (if applicable). 
     Intent intent = new Intent(this, RegistrationIntentService.class); 
     startService(intent); 
    } 
} 

登記意向服務:

public class RegistrationIntentService extends IntentService { 

private static final String TAG = "GCM"; 

public RegistrationIntentService() { 
    super(TAG); 
} 

@Override 
protected void onHandleIntent(Intent intent) { 
    SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this); 

    try { 
     // In the (unlikely) event that multiple refresh operations occur simultaneously, 
     // ensure that they are processed sequentially. 
     synchronized (TAG) { 
      // Initially this call goes out to the network to retrieve the token, subsequent calls 
      // are local. 
      InstanceID instanceID = InstanceID.getInstance(this); 
      String token = instanceID.getToken(getString(R.string.gcm_defaultSenderId), 
        GoogleCloudMessaging.INSTANCE_ID_SCOPE, null); 

      Log.d(TAG, "GCM Registration Token: " + token); 

      subscribeTopics(token); 

      // You should store a boolean that indicates whether the generated token has been 
      // sent to your server. If the boolean is false, send the token to your server, 
      // otherwise your server should have already received the token. 
      sharedPreferences.edit().putBoolean(GcmPreferences.SENT_TOKEN_TO_SERVER, true).apply(); 
     } 
    } catch (Exception e) { 
     Log.d(TAG, "Failed to complete token refresh", e); 
     // If an exception happens while fetching the new token or updating our registration data 
     // on a third-party server, this ensures that we'll attempt the update at a later time. 
     sharedPreferences.edit().putBoolean(GcmPreferences.SENT_TOKEN_TO_SERVER, false).apply(); 
    } 
    // Notify UI that registration has completed, so the progress indicator can be hidden. 
    Intent registrationComplete = new Intent(GcmPreferences.REGISTRATION_COMPLETE); 
    LocalBroadcastManager.getInstance(this).sendBroadcast(registrationComplete); 
} 

/** 
* Subscribe to any GCM topics of interest, as defined by the TOPICS constant. 
* 
* @param token GCM token 
* @throws IOException if unable to reach the GCM PubSub service 
*/ 
private void subscribeTopics(String token) throws IOException { 
    GcmPubSub.getInstance(this).subscribe(token, "/topics/global", null); 
} 

}

我的PHP POST請求:

<?php 
$postData = array('to' => '/topics/global', 
        'notification' => array(
         'body' => 'GCM Topic Message', 
         'title' => 'Test message')); 

$curl = curl_init('https://gcm-http.googleapis.com/gcm/send'); 

curl_setopt_array($curl, array(CURLOPT_POST => true, 
CURLOPT_RETURNTRANSFER => true, 
CURLOPT_HTTPHEADER => array(
    'Authorization:key=AIzaSyBbUfgnuDyAmO9G8wk6_eqwZFiYX0J0PxI', 
    'Content-Type:application/json' 
), 
CURLOPT_POSTFIELDS => json_encode($postData))); 

$response = curl_exec($curl); 

if($response === false){ 
    die(curl_error($curl)); 
} 

$responseData = json_decode($response, true); 

// Print the date from the response 
print_r($responseData); 
?> 

我測試POST請求。在Bluestacks App Player和真實手機上測試的Android應用程序。

+0

Bluetstacks是否默認使用Google Apps等Google Apps?Google Play服務是GCM工作所必需的。 –

+0

@viertausend是的。 GCM在其他應用程序的作品。 –

+0

@viertausend我注意到應用程序不在設置中運行的服務。另外我在真實手機上測試了應用程序,但通知仍然沒有出現:(我有很長時間沒有使用它了,問題很奇怪,我檢查了我的代碼 - 整個過程都是在Google示例和文檔中。 –

回答

1

它看起來像你試圖從你的PHP服務器發送通知消息。通知消息允許您在服務器端指定通知的參數,就像您在此處所做的那樣。

Android上的通知消息需要您不包括的圖標字段,請檢查full list of notification message fields以確保您包含所有必需字段的不同平臺。

此外,您正在使用的快速入門通過數據字段處理下游消息。通過通知字段發送的消息由庫處理,因此onMessageReceived永遠不會被調用。您必須通過onMessageReceived的數據字段發送消息才能被調用。例如,在同一個快速入門中考慮GCM Sender

+0

我已經決定了我的問題,我刪除了舊的Google Developers Consloe應用並創建了新的應用這很奇怪 –

0
Convert notification to data . 

$postData = array('to' => '/topics/global', 
        'notification' => array(
         'body' => 'GCM Topic Message', 
         'title' => 'Test message')); 

$postData = array('to' => '/topics/global', 
        'data' => array(
         'body' => 'GCM Topic Message', 
         'title' => 'Test message')); 

Then only onMessagedReceived is called then on this method generate your own notification.Don't forget on creating your own notification icon,title,text are required field 
+0

我已經試過了,但它對我沒有幫助,問題已經決定 - http://stackoverflow.com/questions/31214476/gcm-is-not-working/31562613#comment51005745_31281150 –

+0

使用「registration_ids」而不是「to」你的json會變成registration_ids:array(registerid1,registerid2 ...等等) –

+0

「請注意,對於主題消息傳遞,不需要將註冊令牌發送到您的應用服務器;但是,如果您確實發送了註冊令牌,則服務器可以驗證令牌的有效性並獲取有關所創建應用的更多信息它。」所以不需要標記ID。例如:$ fields = array('to'=>「/ topics/global」,'data'=> $ message); –