Android GCM 基本实现

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/11438464/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-20 07:25:18  来源:igfitidea点击:

Android GCM basic implementation

androidgoogle-cloud-messaging

提问by Rooster242

UPDATE:I fixed the problems in the code below so this makes a nice basic working example of how to use GCM

更新:我修复了下面代码中的问题,因此这是一个很好的基本工作示例,说明如何使用GCM



So, I'm trying to implement Android GCMinto my app. Here are the relevant parts I've added to the manifest:

所以,我正在尝试将 Android 实现GCM到我的应用程序中。以下是我添加到清单中的相关部分:

<uses-sdk android:minSdkVersion="8" android:targetSdkVersion="20" />

<permission
    android:name=".permission.C2D_MESSAGE"
    android:protectionLevel="signature" />
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
<uses-permission android:name=".permission.C2D_MESSAGE" />
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<uses-permission android:name="android.permission.GET_ACCOUNTS"/>

...

...

<receiver
    android:name="com.google.android.gcm.GCMBroadcastReceiver"
    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.badbob.app.gmctestapp" />
    </intent-filter>
</receiver>

<service android:name=".GCMIntentService" />

I've added the following code to the onCreate of my main activity:

我已将以下代码添加到我的主要活动的 onCreate 中:

    GCMRegistrar.checkDevice( this );
    GCMRegistrar.checkManifest( this );
    final String regId = GCMRegistrar.getRegistrationId( this );
    if( regId.equals( "" ) ) {
        GCMRegistrar.register( this, GCM_SENDER_ID );
    }
    else {
        Log.v( LOG_TAG, "Already registered" );
    }

I've also created the GCMIntenetServiceclass like so:

我也GCMIntenetService像这样创建了这个类:

public class GCMIntentService extends GCMBaseIntentService {

    private static final String LOG_TAG = "GetAClue::GCMIntentService";

    public GCMIntentService() {
        super( GCM_SENDER_ID );
        // TODO Auto-generated constructor stub
        Log.i( LOG_TAG, "GCMIntentService constructor called" );
    }

    @Override
    protected void onError( Context arg0, String errorId ) {
        // TODO Auto-generated method stub
        Log.i( LOG_TAG, "GCMIntentService onError called: " + errorId );
    }

    @Override
    protected void onMessage( Context arg0, Intent intent ) {
        // TODO Auto-generated method stub
        Log.i( LOG_TAG, "GCMIntentService onMessage called" );
        Log.i( LOG_TAG, "Message is: " + intent.getStringExtra( "message" ) );
    }

    @Override
    protected void onRegistered( Context arg0, String registrationId ) {
        // TODO Auto-generated method stub
        Log.i( LOG_TAG, "GCMIntentService onRegistered called" );
        Log.i( LOG_TAG, "Registration id is: " + registrationId );
    }

    @Override
    protected void onUnregistered( Context arg0, String registrationId ) {
        // TODO Auto-generated method stub
        Log.i( LOG_TAG, "GCMIntentService onUnregistered called" );
        Log.i( LOG_TAG, "Registration id is: " + registrationId );
    }
}

When I run this I get this in LogCat:

当我运行它时,我在LogCat 中得到了这个:

07-11 11:28:46.340: V/GCMRegistrar(27435): Registering receiver
07-11 11:28:46.370: D/GCMRegistrar(27435): resetting backoff for com.badbob.app.getacluebeta
07-11 11:28:46.380: V/GCMRegistrar(27435): Registering app com.badbob.app.getacluebeta of senders 128205395388

From what I've gleaned from other posts I should get a registration ID in LogCatbut I"m not. Also onRegistered()in GCMIntentServicenever gets called. So what am I doing wrong?

从我从其他帖子中收集的信息来看,我应该在其中获得一个注册 ID,LogCat但我没有。而且onRegistered()GCMIntentService永远不会被调用。那么我做错了什么?

采纳答案by Ryan Gray

this is incorrect

这是不正确的

protected GCMIntentService( String senderId ) {         
super(senderId);}

As it states in the documentation. you must declare a PUBLIC, NO ARGUMENT constructor for GCMIntentService. Otherwise the GCMIntentService can't be instantiated properly by background intent services.

正如文档中所述。您必须为 GCMIntentService 声明一个 PUBLIC, NO ARGUMENT 构造函数。否则 GCMIntentService 无法被后台意图服务正确实例化。

public GCMIntentService(){
super(senderID);}

the senderID can be a hard coded constant string because it will no longer change with the new GCM. It's also very important you use the correct senderID. 24 hours is long enough for yours to be active so if my above solution doesn't work you are using the incorrect senderID. Everything else looks great.

senderID 可以是硬编码的常量字符串,因为它不会再随新 GCM 改变。使用正确的 senderID 也很重要。24 小时足以让您处于活动状态,因此如果我的上述解决方案不起作用,则您使用的是不正确的发件人 ID。其他一切看起来都很棒。

The senderID is in the URL of your web browser when you are browsing the Google API access page. Click on GCM and a 12 digit number will be present in the browser URL. That is the correct key to use. NOT your API key. That is used on the App server side.

当您浏览 Google API 访问页面时,senderID 位于您的网络浏览器的 URL 中。单击 GCM,浏览器 URL 中将出现一个 12 位数字。这是正确使用的密钥。不是您的 API 密钥。这是在应用程序服务器端使用的。

回答by redestructa

I also had this ANNOYing bug, til now. The Problem was, that i declared the intentservice inside another package... even if i declared the name in the android manifest and no classnotfound exception had been place... no error at all could be found... so i made sure the intentservice is in the root package.

我也有这个烦人的错误,直到现在。问题是,我在另一个包中声明了 intentservice ......即使我在 android manifest 中声明了名称并且没有 classnotfound 异常发生......根本找不到任何错误......所以我确保intentservice 在根包中。

回答by yugidroid

I think you have some issues in the code.

我认为您在代码中存在一些问题。

You should do the registration of your own broadcast receiver in the manifest file and that receiver will trigger the <service android:name=".GCMIntentService" />.

您应该在清单文件中注册您自己的广播接收器,该接收器将触发<service android:name=".GCMIntentService" />.

Therefore you must do something like I write below.

因此你必须像我在下面写的那样做一些事情。

  • The receiver must be declared like:

    <receiver
        android:name="your.package.name.YourBroadCastReceiver"
        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" />
        </intent-filter>
    

  • Your broadcast receiver that will start the service.

    public class YourBroadCastReceiver extends BroadcastReceiver {
    
    @Override
     public final void onReceive(Context context, Intent intent) {
         GCMIntentService .runIntentInService(context, intent);
         setResult(Activity.RESULT_OK, null, null);
     }  
    }
    
  • 接收者必须声明如下:

    <receiver
        android:name="your.package.name.YourBroadCastReceiver"
        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" />
        </intent-filter>
    

  • 您将启动服务的广播接收器。

    public class YourBroadCastReceiver extends BroadcastReceiver {
    
    @Override
     public final void onReceive(Context context, Intent intent) {
         GCMIntentService .runIntentInService(context, intent);
         setResult(Activity.RESULT_OK, null, null);
     }  
    }
    

I advice you to take a look at the official GCM documentationwhere you can find a good example.

我建议您查看官方 GCM文档,您可以在其中找到一个很好的示例。

And... don't forget to enable the Google Cloud Messagingservice in the main Google APIs Console page.

并且...不要忘记在主 Google API 控制台页面中启用Google Cloud Messaging服务。

Let me know if it helps!

如果有帮助,请告诉我!

回答by swiftBoy

Here I have written few steps for How to Get RegID and Notification starting from scratch

在这里我写了几个步骤如何从头开始获取 RegID 和通知

  1. Create/Register App on Google Cloud
  2. Setup Cloud SDK with Development
  3. Configure project for GCM
  4. Get Device Registration ID
  5. Send Push Notifications
  6. Receive Push Notifications
  1. 在 Google Cloud 上创建/注册应用
  2. 使用开发设置 Cloud SDK
  3. 为 GCM 配置项目
  4. 获取设备注册 ID
  5. 发送推送通知
  6. 接收推送通知

You can find complete tutorial in below URL link

您可以在以下 URL 链接中找到完整的教程

Getting Started with Android Push Notification : Latest Google Cloud Messaging (GCM) - step by step complete tutorial

Android 推送通知入门:最新的 Google Cloud Messaging (GCM) - 分步完整教程

enter image description here

在此处输入图片说明

Code snip to get Registration ID (Device Token for Push Notification).

获取注册 ID(推送通知的设备令牌)的代码片段。

Configure project for GCM

为 GCM 配置项目



Update AndroidManifest file

更新 AndroidManifest 文件

For enable GCM in our project we need to add few permission in our manifest file Go to AndroidManifest.xml and add below code Add Permission

为了在我们的项目中启用 GCM,我们需要在我们的清单文件中添加一些权限转到 AndroidManifest.xml 并添加以下代码添加权限

<uses-permission android:name="android.permission.INTERNET”/>
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="android.permission.WAKE_LOCK" />

<uses-permission android:name="android.permission.VIBRATE" />

<uses-permission android:name=“.permission.RECEIVE" />
<uses-permission android:name=“<your_package_name_here>.permission.C2D_MESSAGE" />
<permission android:name=“<your_package_name_here>.permission.C2D_MESSAGE"
        android:protectionLevel="signature" />

Add GCM Broadcast Receiver declaration

添加 GCM 广播接收器声明

add GCM Broadcast Receiver declaration in your application tag

在您的应用程序标签中添加 GCM 广播接收器声明

<application
        <receiver
            android:name=".GcmBroadcastReceiver"
            android:permission="com.google.android.c2dm.permission.SEND" ]]>
            <intent-filter]]>
                <action android:name="com.google.android.c2dm.intent.RECEIVE" />
                <category android:name="" />
            </intent-filter]]>

        </receiver]]>

<application/>

Add GCM Servie declaration

添加 GCM 服务声明

<application
     <service android:name=".GcmIntentService" />
<application/>


Get Registration ID (Device Token for Push Notification)

获取注册 ID(推送通知的设备令牌)

Now Go to your Launch/Splash Activity

现在转到您的启动/启动活动

Add Constants and Class Variables

添加常量和类变量

private final static int PLAY_SERVICES_RESOLUTION_REQUEST = 9000;
public static final String EXTRA_MESSAGE = "message";
public static final String PROPERTY_REG_ID = "registration_id";
private static final String PROPERTY_APP_VERSION = "appVersion";
private final static String TAG = "LaunchActivity";
protected String SENDER_ID = "Your_sender_id";
private GoogleCloudMessaging gcm =null;
private String regid = null;
private Context context= null;

Update OnCreate and OnResume methods

更新 OnCreate 和 OnResume 方法

@Override
protected void onCreate(Bundle savedInstanceState)
{
     super.onCreate(savedInstanceState);
     setContentView(R.layout.activity_launch);
     context = getApplicationContext();
         if (checkPlayServices()) 
     {
            gcm = GoogleCloudMessaging.getInstance(this);
            regid = getRegistrationId(context);

            if (regid.isEmpty())
            {
                registerInBackground();
            }
            else
            {
            Log.d(TAG, "No valid Google Play Services APK found.");
            }
      }
 }

@Override protected void onResume()
{
       super.onResume();       checkPlayServices();
}


# Implement GCM Required methods (Add below methods in LaunchActivity)

private boolean checkPlayServices() {
        int resultCode = GooglePlayServicesUtil.isGooglePlayServicesAvailable(this);
        if (resultCode != ConnectionResult.SUCCESS) {
            if (GooglePlayServicesUtil.isUserRecoverableError(resultCode)) {
                GooglePlayServicesUtil.getErrorDialog(resultCode, this,
                        PLAY_SERVICES_RESOLUTION_REQUEST).show();
            } else {
                Log.d(TAG, "This device is not supported - Google Play Services.");
                finish();
            }
            return false;
        }
        return true;
 }

private String getRegistrationId(Context context) 
{
   final SharedPreferences prefs = getGCMPreferences(context);
   String registrationId = prefs.getString(PROPERTY_REG_ID, "");
   if (registrationId.isEmpty()) {
       Log.d(TAG, "Registration ID not found.");
       return "";
   }
   int registeredVersion = prefs.getInt(PROPERTY_APP_VERSION, Integer.MIN_VALUE);
   int currentVersion = getAppVersion(context);
   if (registeredVersion != currentVersion) {
        Log.d(TAG, "App version changed.");
        return "";
    }
    return registrationId;
}

private SharedPreferences getGCMPreferences(Context context) 
{
    return getSharedPreferences(LaunchActivity.class.getSimpleName(),
                Context.MODE_PRIVATE);
}

private static int getAppVersion(Context context) 
{
     try 
     {
         PackageInfo packageInfo = context.getPackageManager()
                    .getPackageInfo(context.getPackageName(), 0);
            return packageInfo.versionCode;
      } 
      catch (NameNotFoundException e) 
      {
            throw new RuntimeException("Could not get package name: " + e);
      }
}


private void registerInBackground() 
{     new AsyncTask() {
     Override
     protected Object doInBackground(Object... params) 
     {
          String msg = "";
          try 
          {
               if (gcm == null) 
               {
                        gcm = GoogleCloudMessaging.getInstance(context);
               }
               regid = gcm.register(SENDER_ID);               Log.d(TAG, "########################################");
               Log.d(TAG, "Current Device's Registration ID is: "+msg);     
          } 
          catch (IOException ex) 
          {
              msg = "Error :" + ex.getMessage();
          }
          return null;
     }     protected void onPostExecute(Object result) 
     { //to do here };
  }.execute(null, null, null);
}


Note: please store REGISTRATION_KEY, it is important for sending PN Message to GCM also keep in mine this will be unique for all device, by using this only GCM will send Push Notification.

注意:请存储 REGISTRATION_KEY,将 PN 消息发送到 GCM 很重要也请保存在我的这对所有设备都是唯一的,通过使用这个只有 GCM 将发送推送通知。

Receive Push Notifications

接收推送通知

Add GCM Broadcast Receiver Class

添加 GCM 广播接收器类

As we have already declared “GcmBroadcastReceiver.java” in our Manifest file, So lets create this class update receiver class code this way

由于我们已经在 Manifest 文件中声明了“GcmBroadcastReceiver.java”,所以让我们以这种方式创建此类更新接收器类代码

public class GcmBroadcastReceiver extends WakefulBroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) 
    {        ComponentName comp = new ComponentName(context.getPackageName(),
                GcmIntentService.class.getName());        startWakefulService(context, (intent.setComponent(comp)));
        setResultCode(Activity.RESULT_OK);
        Toast.makeText(context, “wow!! received new push notification", Toast.LENGTH_LONG).show();
    }
}

Add GCM Service Class

添加 GCM 服务类

As we have already declared “GcmBroadcastReceiver.java” in our Manifest file, So lets create this class update receiver class code this way

由于我们已经在 Manifest 文件中声明了“GcmBroadcastReceiver.java”,所以让我们以这种方式创建此类更新接收器类代码

public class GcmIntentService extends IntentService
{     public static final int NOTIFICATION_ID = 1;     private NotificationManager mNotificationManager;     private final static String TAG = "GcmIntentService";     public GcmIntentService() {
     super("GcmIntentService");     
     }     @Override
     protected void onHandleIntent(Intent intent) {
          Bundle extras = intent.getExtras();
          Log.d(TAG, "Notification Data Json :" + extras.getString("message"));

          GoogleCloudMessaging gcm = GoogleCloudMessaging.getInstance(this);
          String messageType = gcm.getMessageType(intent);          if (!extras.isEmpty()) {          if (GoogleCloudMessaging.MESSAGE_TYPE_SEND_ERROR
               .equals(messageType)) {
               sendNotification("Send error: " + extras.toString());
          } else if (GoogleCloudMessaging.MESSAGE_TYPE_DELETED
          .equals(messageType)) {
          sendNotification("Deleted messages on server: "
          + extras.toString());          // If it's a regular GCM message, do some work.
          } else if (GoogleCloudMessaging.MESSAGE_TYPE_MESSAGE
          .equals(messageType)) {
          // This loop represents the service doing some work.
          for (int i = 0; i < 5; i++) {
               Log.d(TAG," Working... " + (i + 1) + "/5 @ "
               + SystemClock.elapsedRealtime());               try {
                    Thread.sleep(5000);
               } catch (InterruptedException e) {
               }
             }
             Log.i(TAG, "Completed work @ " + SystemClock.elapsedRealtime());
             sendNotification(extras.getString("message"));
           }
        }        // Release the wake lock provided by the WakefulBroadcastReceiver.
        GcmBroadcastReceiver.completeWakefulIntent(intent);
     }     // Put the message into a notification and post it.
     // This is just one simple example of what you might choose to do with
     // a GCM message.
     private void sendNotification(String msg) {          mNotificationManager = (NotificationManager) this
          .getSystemService(Context.NOTIFICATION_SERVICE);
          PendingIntent contentIntent = PendingIntent.getActivity(this, 0,          new Intent(this, LaunchActivity.class), 0);

          NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(          this)
          .setSmallIcon(R.drawable.icon)
          .setContentTitle("Ocutag Snap")
          .setStyle(new NotificationCompat.BigTextStyle().bigText(msg))
          .setContentText(msg)
          .setDefaults(Notification.DEFAULT_SOUND | Notification.DEFAULT_VIBRATE);

          mBuilder.setContentIntent(contentIntent);          mNotificationManager.notify(NOTIFICATION_ID, mBuilder.build());
     }
}

回答by selsine

You also need to register with your application server in the GCMBaseIntentService.onRegistered()callback. Otherwise you will not be able to send your app messages.

您还需要在GCMBaseIntentService.onRegistered()回调中向您的应用程序服务器注册。否则,您将无法发送应用消息。

You should really checkout Google's GCM demo clientas it provides a working sample with all of the correct code. We also have a working sample up on github: airbop-client. It provides a slightly more complete example given that it has working interactions with an application server, which is necessary for a GCM enabled app. It works with the AirBopservers (which I helped create) which are free up to 1000 devices.

您真的应该查看Google 的 GCM 演示客户端,因为它提供了一个包含所有正确代码的工作示例。我们还在 github 上提供了一个工作示例:airbop-client。它提供了一个稍微完整的示例,因为它与应用程序服务器进行了工作交互,这是启用 GCM 的应用程序所必需的。它与AirBop服务器(我帮助创建)一起工作,这些服务器最多可免费使用 1000 台设备。

回答by Vinoth Prakash K

If you are not getting response from the registration, one of the main reason is your manifest file is not configured correctly - especially give the "package_name" (your app package name like com.xxx.yyy) in the <permission>and <intent filter>correctly.

如果你没有得到从注册响应,主要原因一个是你的清单文件没有正确配置-特别带来的“包名”(你喜欢com.xxx.yyy应用程序包名称)的<permission><intent filter>正确的。

回答by ClouDeveloper

Not sure if this is related to your specific problem, however, I was experiencing the same issue. Everything was setup correctly, as far as I could tell, but the onRegistered()handler was never called.

不确定这是否与您的具体问题有关,但是,我遇到了同样的问题。据我所知,一切都设置正确,但onRegistered()从未调用过处理程序。

I had the standard onCreate(), onStart()and onDestroy()service methods as part of my GCMIntentService class. Once I removed them, the handler was called, as expected.

我将标准onCreate(),onStart()onDestroy()service 方法作为我的 GCMIntentService 类的一部分。一旦我删除了它们,处理程序就会被调用,正如预期的那样。

My assumption is that by overriding these methods, I was by-passing needed code initialization.

我的假设是通过覆盖这些方法,我绕过了所需的代码初始化。

回答by tt6

After reading ClouDeveloper's post I removed onCreate(), onDestroy(), and the other onXXX()callback methods. Also, my GCMIntentService.onRegistered(Context, regId)is called with the regId.

阅读 ClouDeveloper 的帖子后,我删除了onCreate()onDestroy()和其他onXXX()回调方法。此外, myGCMIntentService.onRegistered(Context, regId)regId.

Thank you ClouDeveloper!

感谢 ClouDeveloper!