Подтвердить что ты не робот

Базовая реализация 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 никогда не вызывается. Так что я делаю неправильно?

4b9b3361

Ответ 1

это неверно

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

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

public GCMIntentService(){
super(senderID);}

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

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

Ответ 2

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

Ответ 3

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

Вы должны сделать регистрацию своего собственного широковещательного приемника в файле манифеста, и этот приемник активирует <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 Cloud Messaging на главной странице консоли Google API.

Сообщите мне, если это поможет!

Ответ 5

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

  • Создать/зарегистрировать приложение в Google Cloud
  • Настройка облачного SDK с развитием
  • Настройка проекта для GCM
  • Получить идентификатор регистрации устройства
  • Отправить Push-уведомления
  • Получение уведомлений о доставке

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

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

enter image description here

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

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


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

Для включения 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" />

Добавить декларацию приемника широковещательной передачи 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 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 Message в GCM также сохранится в моей, это будет уникальным для всего устройства, используя этот только GCM, отправит Push Notification.

Получение уведомлений о доставке

Добавить класс ретранслятора GCM

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

Ответ 6

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

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

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

Ответ 7

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

Спасибо ClouDeveloper!

Ответ 8

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

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

Ответ 9

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