GCM с настраиваемым широковещательным приемником

Я реализую уведомления gcm в своем приложении. Поскольку я использую свой код для создания множества приложений с разными именами пакетов, я не могу использовать стандартное имя mypackage.GCMIntentService. При создании приложений я делаю изменения только в манифесте и меняю импорт своего класса R. Итак, я создал свой собственный BroadcastReceiver.

public class GCMReceiver extends GCMBroadcastReceiver {
  @Override
  protected String getGCMIntentServiceClassName(Context context) {
    return GCMIntentService.class.getName();
  }
}

чтобы вернуть имя GCMIntentService независимо от имени пакета.

Вот мой манифест:

    <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="com.google.android.c2dm.permission.RECEIVE" />
    <permission
        android:name="org.rferl.permission.C2D_MESSAGE"
        android:protectionLevel="signature" />

    <uses-permission android:name="org.rferl.permission.C2D_MESSAGE" />


    <service
        android:name="org.rferl.service.GCMIntentService"
        android:enabled="true" />


   <receiver
        android:name="org.rferl.GCMReceiver"
        android:enabled="true"
        android:permission="com.google.android.c2dm.permission.SEND" >
        <intent-filter>

            <!-- Receives the actual messages. -->
            <action android:name="com.google.android.c2dm.intent.RECEIVE" />
            <!-- Receives the registration id. -->
            <action android:name="com.google.android.c2dm.intent.REGISTRATION" />

            <category android:name="org.rferl" />
        </intent-filter>
    </receiver>

Все работает нормально, могу регистрироваться, отменять регистрацию, получать сообщения. Но когда приложение не запускается, GCMIntentService.onMessage не вызывается. Мне что-то не хватает в моем манифесте? Почему система не запустила службу?


person pcu    schedule 23.08.2012    source источник
comment
Я тоже столкнулся с той же проблемой? Ваша проблема сейчас решена? Пожалуйста, посмотрите мой последний вопрос из моей учетной записи и направьте меня соответствующим образом. Спасибо   -  person Shrikant Ballal    schedule 29.10.2012


Ответы (4)


Чтобы изменить имя пакета / класса для приложения / _1 _ / _ 2_ для Android GCM (с использованием Eclipse ADT)

Примечание. Рекомендуется убедиться, что вы можете получать сообщения через GCM, прежде чем вносить следующие изменения. Чтобы реализовать GCM в приложении Android с использованием имени пакета по умолчанию, см. GCM: начало работы.


Имя пакета

Чтобы изменить имя пакета вашего приложения (например, имя нового пакета = com.example.newpackage),

  • В проводнике пакетов щелкните правой кнопкой мыши проект → Инструменты Android → Переименовать пакет приложения.
    Это автоматически и удобно обновит имя пакета.
  • В AndroidManifest.xml обновите имя пакета в permission и uses-permission для C2D_MESSAGE:

    <permission android:name="com.example.newpackage.permission.C2D_MESSAGE" android:protectionLevel="signature" />
    <uses-permission android:name="com.example.newpackage.permission.C2D_MESSAGE" />
    
  • В AndroidManifest.xml обновите имя пакета в category receiver:

    <receiver
        android:name="com.example.oldpackage.GCMBroadcastReceiver"
        android:permission="com.google.android.c2dm.permission.SEND" >  <!-- Not this one!! -->
        <intent-filter>
            <action android:name="com.google.android.c2dm.intent.RECEIVE" />
            <action android:name="com.google.android.c2dm.intent.REGISTRATION" />
    
            <category android:name="com.example.newpackage" />  <!-- This one!! -->
        </intent-filter>
    </receiver>
    

Имя GCMIntentService

Если имя пакета вашего приложения com.example.newpackage, ваш GCMIntentService должен называться com.example.newpackage.GCMIntentService. Если не,

  • # P6 #
    public class MyBroadcastReceiver extends GCMBroadcastReceiver
    {
        @Override
        protected String getGCMIntentServiceClassName(Context context)
        {
            return MyIntentService.class.getName(); // Don't hard-code like "com.example.oldpackage.MyIntentService", see http://stackoverflow.com/a/936696/1402846
        }
    }
    
    # P7 #
    # P8 #
  • В AndroidManifest.xml обновите имя receiver:

    <receiver
        android:name="com.example.oldpackage.MyBroadcastReceiver"
        ... >
    </receiver>
    
  • В AndroidManifest.xml обновите имя service:

    <service android:name="com.example.oldpackage.MyIntentService" />
    

Имя GCMBroadcastReceiver

Если вы изменили имя пакета / класса GCMBroadcastReceiver:

  • В AndroidManifest.xml обновите имя receiver:

    <receiver
        android:name="com.example.oldpackage.NewBroadcastReceiver"
        ... >
    </receiver>
    

Исправление проблем

  • Убедитесь, что в AndroidManifest.xml имя пакета должно появиться как минимум 4 раза:

    • In manifest:

      <manifest ...
          package="com.example.newpackage" ...
      
    • In permission:

      <permission android:name="com.example.newpackage.permission.C2D_MESSAGE" android:protectionLevel="signature" />
      
    • In uses-permission:

      <uses-permission android:name="com.example.newpackage.permission.C2D_MESSAGE" />
      
    • В category в intent-filter в receiver для широковещательного приемника GCM:

      <category android:name="com.example.newpackage" />
      
  • Если вы изменили имя пакета, удалите старое приложение на своем устройстве / эмуляторе перед тестированием.

  • Если вы изменили имя пакета, обратите внимание, что идентификатор регистрации (который вы получаете в _ 46_) изменился.
  • Если вы получили свой регистрационный идентификатор в _ 47_, вы должны увидеть что-то вроде этого в LogCat (тег GCMBroadcastReceiver):

    GCMBroadcastReceiver        onReceive: com.google.android.c2dm.intent.REGISTRATION
    GCMBroadcastReceiver        GCM IntentService class: com.example.oldpackage.MyIntentService
    

    Убедитесь, что имя пакета / класса службы намерения правильное.

  • Если вы переопределите _50 _ в вашем собственном GCMBroadcastReceiver, вы должны увидеть что-то вроде этого в LogCat (тег GCMRegistrar):

    GCMRegistrar        Setting the name of retry receiver class to com.example.oldpackage.MyBroadcastReceiver
    

    Убедитесь, что имя пакета / класса широковещательного приемника правильное.

  • Когда ваш сервер отправляет сообщение серверу GCM, проверьте код состояния HTTP и ответ HTTP на наличие ошибок.
  • And if you are desperate:
    • Check LogCat for errors.
    • Попробуйте перезапустить ваше устройство / эмулятор.
    • Попробуйте удалить свое приложение на устройстве / эмуляторе.
    • Попробуйте перезапустить Eclipse.
    • Попробуйте очистить и пересобрать проект.
    • Попробуйте обновить ADT (раскрывающееся меню → Окно → Android SDK Manager → Установить пакеты).
    • Попробуйте обновить Eclipse (раскрывающееся меню → Справка → Проверить наличие обновлений).
    • Попробуйте перезагрузить компьютер.
    • Высыпайся или молись.
person Pang    schedule 20.01.2013

Вы должны поместить класс GCMIntentService в свой корневой пакет приложения. Здесь org.rferl

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

и приемник

   <receiver
            android:name="com.google.android.gcm.GCMBroadcastReceiver"
            android:permission="com.google.android.c2dm.permission.SEND" >
            <intent-filter>

                <!-- Receives the actual messages. -->
                <action android:name="com.google.android.c2dm.intent.RECEIVE" />
                <!-- Receives the registration id. -->
                <action android:name="com.google.android.c2dm.intent.REGISTRATION" />

                <category android:name="com.EgoSecure.ma" />
            </intent-filter>
        </receiver>
person Yahor10    schedule 23.08.2012
comment
Это невозможно из-за использования исходного кода в качестве основы для создания многих приложений - они должны иметь другое имя пакета, которое я изменяю в манифесте. Итак, если я создаю приложение, например org.rferl.en, тогда мне нужно изменить структуру пакета для многих классов, меняющих импорт, и так ... Также я написал, что все работает нормально, когда приложение работает, я могу получать сообщения. Только система не вызывает приемник и не запускает службу, когда приложение не запущено. - person pcu; 23.08.2012
comment
Если вы используете Android 3.0 или ›, вы должны установить флаг для остановленных приложений. - person Yahor10; 23.08.2012
comment
Вы правы, остановленное приложение тоже убивает пользователь. Так что убил при тестировании. Я не могу проверить это правильно, потому что серверы из другой компании. Также образец из Google не работает, когда я убил его вручную. Но когда я его запустил и например выключил телефон, все работает. Но как поставить этот флаг в файл манифеста? Я обычно убиваю приложения на своем телефоне, если что-то пошло не так, и пока я не запустил их, я не могу получать сообщения. Немного странное поведение. - person pcu; 23.08.2012
comment
Флаг должен добавить к вашему намерению трансляции - включить остановленные пакеты. Но если вы не получаете данные gcm с сервера, это вам не поможет. - person Yahor10; 24.08.2012
comment
Это не мое намерение. Это намерение, которое вызывает мой приемник, предоставляет услугу GCM. Поэтому у меня нет контроля над обновлением, я создаю его программно. - person pcu; 24.08.2012
comment
Измените свой радиовещательный приемник, как я описал выше - person Yahor10; 24.08.2012

Поскольку я использую свой код для создания множества приложений с разными именами пакетов, я не могу использовать стандартное имя mypackage.GCMIntentService.

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


В AndroidManifest вы можете использовать переменную $PACKAGE_NAME (доступна по умолчанию), которая будет ссылаться на имя пакета, которое вы указали в атрибуте package в корневом элементе manifest.

Значение этого атрибута package не обязательно должно быть жестко закодированной строкой, но также может быть установлено динамически через ссылку на ресурс, например:

<manifest package="@string/app_package" ...>
    ...
    <service
        android:name="$PACKAGE_NAME.service.GCMIntentService"
        android:enabled="true" />
    ...
</manifest>

Примечание .service - это просто подпакет, который я включил, чтобы показать, как вы их указываете. Конечно, это решение будет работать только в том случае, если ваши приложения будут следовать общим правилам, таким как размещение классов обслуживания в .service подпакете.

Также обратите внимание, что вы можете полностью отключить корневой пакет. Он будет расширен Android:

<manifest package="@string/app_package" ...>
    ...
    <service
        android:name=".service.GCMIntentService"
        android:enabled="true" />
    ...
</manifest>

Фактически то же, что и выше.

Если вы ищете более гибкий способ замены значений в AndroidManifest (или других файлах), вы можете взглянуть на задачу Ant Replace (http://ant.apache.org/manual/Tasks/replace.html) или фильтрация ресурсов (http://maven.apache.org/plugins/maven-resources-plugin/examples/filter.html) с Maven.

person Risadinha    schedule 31.07.2013

Приемник широковещательной передачи gcm (GCMBroadcastReceiver.class) вызывает класс обслуживания намерений (GCMIntentService.class) из корневого каталога приложения. Вы не можете использовать org.rferl.service.GCMIntentService прямо сейчас. Вы должны переопределить метод getGCMIntentServiceClassName из GCMBroadcastReceiver, который возвращает имя вашего класса GCMIntentService. Как это сделать, здесь

person dexxtr    schedule 26.08.2012