Android GCM message successfully sent but not rece

2019-06-15 01:17发布

问题:

I'm trying to use the GCM service to send push notifications to my devices.

I've followed the Android Hive tutorial (which is now deprecated like many other questions and answers about this) for the server-side functions, which look to work as expected since I can get this kind of outputs :

{"multicast_id":9131068334342174816,"success":1,"failure":0,"canonical_ids":0,"results":[{"message_id":"0:1377441098827443%1d84a26ff9fd7ecd"}]}

But according to some answers, receiving this response just means that the message has been accepted by GCM servers for sending, but not that it has been sent. So, as expected, my BroadcastReceiver doesn't receive anything.

Here's my BroadcastReceiver code :

public class GcmBroadcastReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        Log.i("gcm_debug", "PushReceiver onReceive called");

        Bundle extras = intent.getExtras();
        GoogleCloudMessaging gcm = GoogleCloudMessaging.getInstance(context);

        String msgType = gcm.getMessageType(intent);

        if(!extras.isEmpty()){
            if(GoogleCloudMessaging.MESSAGE_TYPE_SEND_ERROR.equals(msgType)){
                Log.i("gcm_debug", "Message send error");
            }else if(GoogleCloudMessaging.MESSAGE_TYPE_DELETED.equals(msgType)){
                Log.i("gcm_debug", "Message deleted");
            }else if(GoogleCloudMessaging.MESSAGE_TYPE_MESSAGE.equals(msgType)){
                Log.i("gcm_debug", "Message received : " + extras.toString());
            }
        }

        setResultCode(Activity.RESULT_OK);
    }

}

And my AndroidManifest :

<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="com.google.android.providers.gsf.permission.READ_GSERVICES" />
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />

<permission android:name="<MYAPP>.permission.C2D_MESSAGE"
            android:protectionLevel="signature" />
<uses-permission android:name="<MYAPP>.permission.C2D_MESSAGE" />

<!-- Require OpenGL ES2 for GMap -->
<uses-feature android:glEsVersion="0x00020000"
              android:required="true" />


<!-- Because this app is using the GCM library to send messages, the min SDK cannot be lower
than 8 -->
<uses-sdk
    android:minSdkVersion="8"
    android:targetSdkVersion="18" />


<application
    android:allowBackup="true"
    android:icon="@drawable/ic_launcher"
    android:label="@string/app_name"
    android:theme="@style/LovRTheme" >
    <receiver
        android:name=".GcmBroadcastReceiver"
        android:permission="com.google.android.gcm.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="<MYAPP>" />
        </intent-filter>
    </receiver>
    <service android:name=".GcmIntentService" />

And the server-side code :

    $url = "https://android.googleapis.com/gcm/send";
    $fields = array(
        'registration_ids' => array($dstRegId),
        'delay_while_idle' => true,
        'data' => array("message" => $message));

    $headers = array(
        'Authorization: key=' . $google_api_key,
        'Content-Type: application/json');

    $ch = curl_init();

    curl_setopt($ch, CURLOPT_URL, $url);
    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);
    if($result === FALSE){
        die("Curl failed");
    }
    curl_close($ch);

    echo $result;

I'm coding from home, so I assume that GCM would not have problems getting in and out of the network since GCM uses a kind of reverse-shell connection. Anyway, i don't receive any of the log output i'm expecting.

EDIT: After leaving my app running for a while, LogCat sent me the following outputs :

08-26 00:00:48.984  17966-17966/? D/GCM: Ignoring attempt to send heartbeat on dead connection.
08-26 00:01:49.000  17966-17966/? D/GCM: Ignoring attempt to send heartbeat on dead connection.
08-26 00:02:01.672      433-448/? W/BroadcastQueue: Permission Denial: broadcasting Intent { act=com.google.android.c2dm.intent.RECEIVE flg=0x10 pkg=<myApp> (has extras) } from com.google.android.gsf (pid=17966, uid=10003) requires com.google.android.gcm.c2dm.permission.SEND due to receiver com.navissal.lovr/com.navissal.lovr.GcmBroadcastReceiver
08-26 00:17:09.063  17966-17966/? D/GCM: Ignoring attempt to send heartbeat on dead connection.
08-26 00:18:09.086  17966-17966/? D/GCM: Ignoring attempt to send heartbeat on dead connection.
08-26 00:24:15.250    3936-3951/? V/meshclient: uri: [/beacon?e=wTkyFfdWFtlzOme7rNizVCtnUu9t3SbJgKCe72og-OhyhGIYab1QikytBeU2Nc02QwdDtqI4sX7HHU6GpDQL8zZdKXFXmCics6ZG-Jmr84yvMX1x9EqdyyW1UI6PEhoOb9MV4R_msQ_MEWFnwUzQrV-vGTycKtSNKMMIRE-zM1caIe__7hdu_UStbhz0dhl7cAFmHYF74IQI6EYFCEORxgV2Wts4Ls-hRWEKfEzuBhViND7TeCVpqUOhdVwGMnDO_Qwlo0rpuSNFegdfJCYY4L8fZJogPsXdQW2cFSZ2S0kujCH9uIrljFUTSGcM5GCFuJRq8vWiTP07MqpMq7h2fGGpXQvjImFcVP81erkVzvlYu3bNpjyQe6MhxSFEZrG37Kdp2Fd3liXFZzSjKlLILeYsDK9rRYqO8fEy3PH07et1HjqYWrH-v7wnjcQm6TtyZu914oR-dPBAwX9D3WvbdQlPlqxnuwJ1huUTwaiKotPLgrAzo3Mc5vI93VTs3row]

回答1:

Here's your error:

<receiver
    android:name=".GcmBroadcastReceiver"
    android:permission="com.google.android.gcm.c2dm.permission.SEND" >

It should be:

<receiver
    android:name=".GcmBroadcastReceiver"
    android:permission="com.google.android.c2dm.permission.SEND" >