Android推送插件已注册但未收到任何消息

时间:2014-05-10 10:47:16

标签: android cordova push-notification google-cloud-messaging phonegap-pushplugin

我正在我的应用程序中实现针对android的push-plugin通知,为此我在实际实现我的应用程序中的android的phonegap推送插件之前遵循了几个教程

步骤1)我从样本中的GCM站点获得了一个示例代码,并创建了一个“Sample APP”。它正在使用tomcat服务器,即我能够注册>>在后端接收这些注册ID>>将它们存储在mysql中>>发送消息到每个注册的身份

步骤2)然后我尝试在我的“主应用程序”中使用android的phonegap推送插件。虽然它能够用gcm注册应用程序(获取注册ID)但我无法连接到我的后端tomcat服务器(与上面相同,具有相同的发件人ID),即使我尝试在mysql中创建示例regid然后推送消息虽然步骤1的“示例应用程序”仍然从Tomcat服务器接收消息

,但是在设备上没有收到消息但是没有收到消息

以下是主应用 AndroidManifest.xml 的代码 `

<?xml version="1.0" encoding="utf-8"?>
<!--
       Licensed to the Apache Software Foundation (ASF) under one
       or more contributor license agreements.  See the NOTICE file
       distributed with this work for additional information
       regarding copyright ownership.  The ASF licenses this file
       to you under the Apache License, Version 2.0 (the
       "License"); you may not use this file except in compliance
       with the License.  You may obtain a copy of the License at

         http://www.apache.org/licenses/LICENSE-2.0

       Unless required by applicable law or agreed to in writing,
       software distributed under the License is distributed on an
       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
       KIND, either express or implied.  See the License for the
       specific language governing permissions and limitations
       under the License.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.votesapp.phonegap"
    android:hardwareAccelerated="true"
    android:versionCode="1"
    android:versionName="1.0"
    android:windowSoftInputMode="adjustPan" >

    <supports-screens
        android:anyDensity="true"
        android:largeScreens="true"
        android:normalScreens="true"
        android:resizeable="true"
        android:smallScreens="true"
        android:xlargeScreens="true" />

    <uses-permission android:name="android.permission.CAMERA" />
    <uses-permission android:name="android.permission.VIBRATE" />
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" />
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.RECEIVE_SMS" />
    <uses-permission android:name="android.permission.RECORD_AUDIO" />
    <uses-permission android:name="android.permission.RECORD_VIDEO" />
    <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
    <uses-permission android:name="android.permission.READ_CONTACTS" />
    <uses-permission android:name="android.permission.WRITE_CONTACTS" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.GET_ACCOUNTS" />
    <uses-permission android:name="android.permission.BROADCAST_STICKY" />
    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.GET_ACCOUNTS" />
    <uses-permission android:name="android.permission.WAKE_LOCK" />
    <uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
    <permission android:name="com.plugin.gcm.permission.C2D_MESSAGE" android:protectionLevel="signature" />
     <uses-permission android:name="com.plugin.gcm.permission.C2D_MESSAGE" />
    <application
        android:hardwareAccelerated="true"
        android:icon="@drawable/icon"
        android:label="@string/app_name" >
        <activity
            android:name="VotesApp"
            android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale"
            android:label="@string/app_name"
            android:theme="@android:style/Theme.Black.NoTitleBar" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity android:name="com.plugin.gcm.PushHandlerActivity"/>
        <receiver android:name="com.plugin.gcm.CordovaGCMBroadcastReceiver" 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="com.plugin.gcm" />
    </intent-filter>
</receiver>
<service android:name="com.plugin.gcm.GCMIntentService" />
    </application>

    <uses-sdk
        android:minSdkVersion="7"
        android:targetSdkVersion="18" />

</manifest>

`

CordovaGCMBroadCastReceiver.java

 package com.plugin.gcm;

import android.content.Context;

import com.google.android.gcm.GCMBroadcastReceiver;
import static com.google.android.gcm.GCMConstants.DEFAULT_INTENT_SERVICE_CLASS_NAME;

/*
 * Implementation of GCMBroadcastReceiver that hard-wires the intent service to be 
 * com.plugin.gcm.GCMIntentService, instead of your_package.GCMIntentService 
 */
public class CordovaGCMBroadcastReceiver extends GCMBroadcastReceiver {

    @Override
    protected String getGCMIntentServiceClassName(Context context) {
        return "com.plugin.gcm" + DEFAULT_INTENT_SERVICE_CLASS_NAME;
    }

}

GCMIntentService.java

  package com.plugin.gcm;

    import android.content.Context;

    import com.google.android.gcm.GCMBroadcastReceiver;
    import static com.google.android.gcm.GCMConstants.DEFAULT_INTENT_SERVICE_CLASS_NAME;

    /*
     * Implementation of GCMBroadcastReceiver that hard-wires the intent service to be 
     * com.plugin.gcm.GCMIntentService, instead of your_package.GCMIntentService 
     */
    public class CordovaGCMBroadcastReceiver extends GCMBroadcastReceiver {

        @Override
        protected String getGCMIntentServiceClassName(Context context) {
            return "com.plugin.gcm" + DEFAULT_INTENT_SERVICE_CLASS_NAME;
        }


}

PushHandlerActivity.java

package com.plugin.gcm;

import android.app.Activity;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.util.Log;

public class PushHandlerActivity extends Activity
{
    private static String TAG = "PushHandlerActivity"; 

    /*
     * this activity will be started if the user touches a notification that we own. 
     * We send it's data off to the push plugin for processing.
     * If needed, we boot up the main activity to kickstart the application. 
     * @see android.app.Activity#onCreate(android.os.Bundle)
     */
    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        Log.v(TAG, "onCreate");

        boolean isPushPluginActive = PushPlugin.isActive();
        processPushBundle(isPushPluginActive);

        GCMIntentService.cancelNotification(this);

        finish();

        if (!isPushPluginActive) {
            forceMainActivityReload();
        }
    }

    /**
     * Takes the pushBundle extras from the intent, 
     * and sends it through to the PushPlugin for processing.
     */
    private void processPushBundle(boolean isPushPluginActive)
    {
        Bundle extras = getIntent().getExtras();

        if (extras != null) {
            Bundle originalExtras = extras.getBundle("pushBundle");

            originalExtras.putBoolean("foreground", false);
            originalExtras.putBoolean("coldstart", !isPushPluginActive);

            PushPlugin.sendExtras(originalExtras);
        }
    }

    /**
     * Forces the main activity to re-launch if it's unloaded.
     */
    private void forceMainActivityReload()
    {
        PackageManager pm = getPackageManager();
        Intent launchIntent = pm.getLaunchIntentForPackage(getApplicationContext().getPackageName());           
        startActivity(launchIntent);
    }

}

PushPlugin.java

package com.plugin.gcm;

import java.util.Iterator;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import android.content.Context;
import android.os.Bundle;
import android.util.Log;

import org.apache.cordova.api.CordovaInterface;
import org.apache.cordova.CordovaWebView;
import org.apache.cordova.api.CallbackContext;
import org.apache.cordova.api.CordovaPlugin;

import com.google.android.gcm.*;

/**
 * @author awysocki
 */

public class PushPlugin extends CordovaPlugin {
    public static final String TAG = "PushPlugin";

    public static final String REGISTER = "register";
    public static final String UNREGISTER = "unregister";
    public static final String EXIT = "exit";

    private static CordovaWebView gWebView;
    private static String gECB;
    private static String gSenderID;
    private static Bundle gCachedExtras = null;
    private static boolean gForeground = false;

    /**
     * Gets the application context from cordova's main activity.
     * @return the application context
     */
    private Context getApplicationContext() {
        return this.cordova.getActivity().getApplicationContext();
    }

    @Override
    public boolean execute(String action, JSONArray data, CallbackContext callbackContext) {

        boolean result = false;

        Log.v(TAG, "execute: action=" + action);

        if (REGISTER.equals(action)) {

            Log.v(TAG, "execute: data=" + data.toString());

            try {
                JSONObject jo = data.getJSONObject(0);

                gWebView = this.webView;
                Log.v(TAG, "execute: jo=" + jo.toString());

                gECB = (String) jo.get("ecb");
                gSenderID = (String) jo.get("senderID");

                Log.v(TAG, "execute: ECB=" + gECB + " senderID=" + gSenderID);

                GCMRegistrar.register(getApplicationContext(), gSenderID);
                result = true;
                callbackContext.success();
            } catch (JSONException e) {
                Log.e(TAG, "execute: Got JSON Exception " + e.getMessage());
                result = false;
                callbackContext.error(e.getMessage());
            }

            if ( gCachedExtras != null) {
                Log.v(TAG, "sending cached extras");
                sendExtras(gCachedExtras);
                gCachedExtras = null;
            }

        } else if (UNREGISTER.equals(action)) {

            GCMRegistrar.unregister(getApplicationContext());

            Log.v(TAG, "UNREGISTER");
            result = true;
            callbackContext.success();
        } else {
            result = false;
            Log.e(TAG, "Invalid action : " + action);
            callbackContext.error("Invalid action : " + action);
        }

        return result;
    }

    /*
     * Sends a json object to the client as parameter to a method which is defined in gECB.
     */
    public static void sendJavascript(JSONObject _json) {
        String _d = "javascript:" + gECB + "(" + _json.toString() + ")";
        Log.v(TAG, "sendJavascript: " + _d);

        if (gECB != null && gWebView != null) {
            gWebView.sendJavascript(_d); 
        }
    }

    /*
     * Sends the pushbundle extras to the client application.
     * If the client application isn't currently active, it is cached for later processing.
     */
    public static void sendExtras(Bundle extras)
    {
        if (extras != null) {
            if (gECB != null && gWebView != null) {
                sendJavascript(convertBundleToJson(extras));
            } else {
                Log.v(TAG, "sendExtras: caching extras to send at a later time.");
                gCachedExtras = extras;
            }
        }
    }

    @Override
    public void initialize(CordovaInterface cordova, CordovaWebView webView) {
        super.initialize(cordova, webView);
        gForeground = true;
    }

    @Override
    public void onPause(boolean multitasking) {
        super.onPause(multitasking);
        gForeground = false;
    }

    @Override
    public void onResume(boolean multitasking) {
        super.onResume(multitasking);
        gForeground = true;
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        gForeground = false;
        gECB = null;
        gWebView = null;
    }

    /*
     * serializes a bundle to JSON.
     */
    private static JSONObject convertBundleToJson(Bundle extras)
    {
        try
        {
            JSONObject json;
            json = new JSONObject().put("event", "message");

            JSONObject jsondata = new JSONObject();
            Iterator<String> it = extras.keySet().iterator();
            while (it.hasNext())
            {
                String key = it.next();
                Object value = extras.get(key); 

                // System data from Android
                if (key.equals("from") || key.equals("collapse_key"))
                {
                    json.put(key, value);
                }
                else if (key.equals("foreground"))
                {
                    json.put(key, extras.getBoolean("foreground"));
                }
                else if (key.equals("coldstart"))
                {
                    json.put(key, extras.getBoolean("coldstart"));
                }
                else
                {
                    // Maintain backwards compatibility
                    if (key.equals("message") || key.equals("msgcnt") || key.equals("soundname"))
                    {
                        json.put(key, value);
                    }

                    if ( value instanceof String ) {
                    // Try to figure out if the value is another JSON object

                        String strValue = (String)value;
                        if (strValue.startsWith("{")) {
                            try {
                                JSONObject json2 = new JSONObject(strValue);
                                jsondata.put(key, json2);
                            }
                            catch (Exception e) {
                                jsondata.put(key, value);
                            }
                            // Try to figure out if the value is another JSON array
                        }
                        else if (strValue.startsWith("["))
                        {
                            try
                            {
                                JSONArray json2 = new JSONArray(strValue);
                                jsondata.put(key, json2);
                            }
                            catch (Exception e)
                            {
                                jsondata.put(key, value);
                            }
                        }
                        else
                        {
                            jsondata.put(key, value);
                        }
                    }
                }
            } // while
            json.put("payload", jsondata);

            Log.v(TAG, "extrasToJSON: " + json.toString());

            return json;
        }
        catch( JSONException e)
        {
            Log.e(TAG, "extrasToJSON: JSON exception");
        }           
        return null;        
    }

    public static boolean isInForeground()
    {
      return gForeground;
    }

    public static boolean isActive()
    {
        return gWebView != null;
    }
}

代码是来自phonegap push plugin github存储库,请帮助或建议我一些我可以尝试的东西。提前谢谢。

3 个答案:

答案 0 :(得分:1)

嗨我通过在“通过phonegap push-plugin for Android提供的Notifcations”提供的onNotificationGCM(ecb)javascript方法中的事件回调函数(ECB)中添加对服务器的显式调用来解决我自己的问题,现在我能够在前台和后台接收通知

var theUrl = new String("http://<yourUrl>:8080?regId="+e.regid+"&userName=xyz");

                            var xmlHttp = null;

                            xmlHttp = new XMLHttpRequest();
                            xmlHttp.open( "GET", theUrl, false );
                            xmlHttp.send( null );
                            alert(xmlHttp.responseText);

我还了解到CordovaGCMBroadCastReceiver和GCMIntentService应该“在一起”并且在主包中(在mainfest标签中指定的包),原因是当同一设备存在多播(非折叠)时,多个将创建线程用于将消息发送到同一设备,然后它们中的任何一个将用于获取导致死锁情况的唤醒锁,当我将CordovaGCMBroadCastReceiver和GCMIntentService移动到我的主程序包即com.plugin.gcm时,这被重新启动com.votesapp.phonegap(我的清单标签中提到的包)。现在我可以收到同一设备的多个通知。

注意:此解决方案特定于phonegap推送插件代码

答案 1 :(得分:0)

@ user2845335我按照相同的步骤操作。 我在警报中获得了注册ID。 GCM已在谷歌注册。 如果您在服务器http://www.mydomain.com/index.php

上调用该文件,则可以完美地向设备发送消息
<html>
<head>
 <title>GCM</title>
</head>
<body>
 <?php
  if(isset($_POST['submit'])){
   $con = mysql_connect("x.x.x.x", "Sqlxxxx","xxxxxxx");
   if(!$con){
    die('MySQL connection failed');
   }

   $db = mysql_select_db("Sqlxxxx");
   if(!$db){
    die('Database selection failed');
   }


   $registatoin_ids = array();
   $sql = "SELECT * FROM android_udid";
   $result = mysql_query($sql, $con);
   while($row = mysql_fetch_assoc($result)){
    array_push($registatoin_ids, $row['registration_id']);
   }

   // Set POST variables
   $url = 'https://android.googleapis.com/gcm/send';

   $message = array("message" => $_POST['message']);
       $fields = array(
           'registration_ids' => $registatoin_ids,
           'data' => $message,
        );

        $headers = array(
             'Authorization: key=mykey',
             'Content-Type: application/json'
         );
         // Open connection
         $ch = curl_init();

         // Set the url, number of POST vars, POST data
         curl_setopt($ch, CURLOPT_URL, $url);

         curl_setopt($ch, CURLOPT_POST, true);
         curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
         curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

         // Disabling SSL Certificate support temporarly
         curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);

         curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($fields));

         // Execute post
         $result = curl_exec($ch);
         if ($result === FALSE) {
             die('Curl failed: ' . curl_error($ch));
         }

         // Close connection
         curl_close($ch);
         echo $result;

  }
 ?>
 <form method="post" action="index.php">
  <label>Insert Message: </label><input type="text" name="message" />

  <input type="submit" name="submit" value="Send" />
 </form>
 <?php
if (isset($fields)) {
print_r($fields);
}
?>
</body>
</html>

我还是做不到的,就是存放在mysql id注册

<script> 

$(document).ready(function(){
  $("#button").click(function(){
        var name=$("#name").val();

$.ajax({
    type: "POST",  
    url: "http://www.mydomain.com/register.php",
    data:...

</script>

答案 2 :(得分:0)

您的API密钥和发件人ID存在问题用新的替换