Базовая реализация Android GCM

ОБНОВЛЕНИЕ: я исправил проблемы в коде ниже, так что это хороший хороший рабочий пример того, как использовать GCM


Итак, я пытаюсь реализовать 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" />

Я добавил следующий код в 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" );
    }

Я также создал 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 );
    }
}

Когда я запускаю это, я получаю это в 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

Из того, что я почерпнул из других постов, я должен получить регистрационный идентификатор в LogCat но я нет. Также onRegistered() в GCMIntentService никогда не звонят. Так что я делаю не так?

9 ответов

Решение

Это неверно

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

Как говорится в документации. Вы должны объявить конструктор PUBLIC, NO ARGUMENT для GCMIntentService. В противном случае GCMIntentService не может быть должным образом создан экземплярами фоновых сервисов.

public GCMIntentService(){
super(senderID);}

senderID может быть жестко закодированной константной строкой, потому что она больше не будет изменяться с новым GCM. Также очень важно использовать правильный идентификатор отправителя. 24 часа достаточно для вашей активности, поэтому, если мое решение не работает, вы используете неверный senderID. Все остальное выглядит отлично.

SenderID находится в URL вашего веб-браузера, когда вы просматриваете страницу доступа к Google API. Нажмите на GCM, и 12-значный номер будет присутствовать в URL браузера. Это правильный ключ для использования. НЕ ваш ключ API. Это используется на стороне сервера приложений.

У меня также была эта досадная ошибка, до сих пор. Проблема заключалась в том, что я объявил intentservice внутри другого пакета... даже если я объявил имя в манифесте android, и не было найдено исключение classnotfound... никакой ошибки не было найдено... поэтому я убедился, что intentservice находится в корневом пакете.

Я думаю, у вас есть некоторые проблемы в коде.

Вам необходимо зарегистрировать свой собственный приемник вещания в файле манифеста, и этот приемник вызовет <service android:name=".GCMIntentService" />,

Поэтому вы должны сделать что-то, как я пишу ниже.

  • Получатель должен быть объявлен как:

    <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);
     }  
    }
    

Я советую вам взглянуть на официальную документацию GCM, где вы можете найти хороший пример.

И... не забудьте включить службу облачных сообщений Google на главной странице консоли API Google.

Дайте мне знать, если это поможет!

Здесь я написал несколько шагов для того, как получить RegID и уведомление, начиная с нуля

  1. Создать / зарегистрировать приложение в Google Cloud
  2. Настройка Cloud SDK с разработкой
  3. Настроить проект для GCM
  4. Получить регистрационный номер устройства
  5. Отправка push-уведомлений
  6. Получать Push-уведомления

Вы можете найти полный учебник в ссылке ниже URL

Начало работы с push-уведомлениями Android: новейшие облачные сообщения Google (GCM) - пошаговое руководство

Отсканируйте код, чтобы получить регистрационный идентификатор (токен устройства для push-уведомлений).

Настроить проект для GCM


Обновить файл AndroidManifest

Чтобы включить GCM в нашем проекте, нам нужно добавить несколько разрешений в наш файл манифеста. Перейти к AndroidManifest.xml и добавить нижеприведенный код Add Permission.

<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" />

Добавить объявление приемника вещания GCM

добавьте декларацию GCM Broadcast Receiver в тег вашего приложения

<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/>

Добавить объявление GCM Servie

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

Получить регистрационный идентификатор (токен устройства для push-уведомлений)

Теперь перейдите к своей деятельности по запуску / всплеску

Добавить константы и переменные класса

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;

Обновите методы 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);
}

Примечание: пожалуйста, сохраните REGISTRATION_KEY, это важно для отправки сообщения PN в GCM, также имейте это в виду, что это будет уникальным для всех устройств, при использовании этого только GCM будет отправлять Push-уведомления.

Получать Push-уведомления

Добавить GCM Broadcast Receiver Class

Так как мы уже объявили "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();
    }
}

Добавить класс обслуживания GCM

Так как мы уже объявили "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());
     }
}

Прочитав пост ClouDeveloper я удалил onCreate(), onDestroy()и другие методы обратного вызова onXXX(). Также мой GCMIntentService.onRegistered(Context, regId) называется с regId,

Спасибо ClouDeveloper!

Вам также необходимо зарегистрироваться на сервере приложений в обратном вызове GCMBaseIntentService.onRegistered(). В противном случае вы не сможете отправлять сообщения приложения.

Вы действительно должны проверить демонстрационный клиент Google GCM, поскольку он предоставляет рабочий образец со всем правильным кодом. У нас также есть рабочий пример на github: airbop-client. Он предоставляет немного более полный пример, учитывая, что он имеет рабочие взаимодействия с сервером приложений, что необходимо для приложения с поддержкой GCM. Он работает с серверами AirBop (которые я помогал создать), на которых свободно до 1000 устройств.

Не уверен, связано ли это с вашей конкретной проблемой, однако у меня возникла та же проблема. Насколько я мог сказать, все было настроено правильно, но onRegistered() Хендлер никогда не вызывался.

У меня был стандарт onCreate(), onStart() а также onDestroy() методы обслуживания как часть моего класса GCMIntentService. Как только я удалил их, обработчик был вызван, как и ожидалось.

Я предполагаю, что, переопределив эти методы, я обошел необходимую инициализацию кода.

Если вы не получаете ответ от регистрации, одна из основных причин заключается в том, что ваш файл манифеста не настроен правильно - особенно укажите "имя_пакета" (имя пакета вашего приложения, например com.xxx.yyy) в <permission> а также <intent filter> правильно.

Другие вопросы по тегам