Служба Firebase Android не получает значение SharedPreferences - PullRequest
0 голосов
/ 15 февраля 2019

Я устанавливаю значение sharedPreferences для моего фрагмента (Kotlin), затем я хотел бы использовать это значение на моем FirebaseMessagingService (Java).Когда я устанавливаю значение, уничтожаю приложение и снова открываю, на моем фрагменте нет никаких проблем.Я вижу установленное значение.Поэтому я уверен, что значение sharedPreferences обновлено моим фрагментом.Но когда я пытаюсь использовать это значение в FirebaseMessagingService, я всегда получаю значение по умолчанию.

Вот как я настраиваю класс kotlin:

sharedPref = activity?.getSharedPreferences("com.xxx.xxx.xxx",Context.MODE_PRIVATE)!!

private fun sharedPrefWrite(boolean: Boolean){
    with (sharedPref?.edit()) {
        this!!.putBoolean("notf", boolean)
        apply()
    }
}

Это хорошо работает.

И вот как я получаю эти данные на FirebaseMessagingService:

@Override
public void onMessageReceived(RemoteMessage remoteMessage) {
    preferences = getApplicationContext().getSharedPreferences("com.xxx.xxx.xxx",Context.MODE_PRIVATE);
    if(preferences.getBoolean("notf",true))
    sendNotification(remoteMessage.getNotification().getBody());
}

и всегда служба отправки уведомлений.

И я не запустил этот сервис в своей деятельности, он только под тегом приложения на Manifest.xml вот так;

     <service android:name="com.xxx.xxx.xxx.newsFirebaseMessagingService">
        <intent-filter>
            <action android:name="com.google.firebase.MESSAGING_EVENT" />
        </intent-filter>
    </service>

Любое предложение о том, почему я не смог получить этозначение ?Спасибо

РЕДАКТИРОВАТЬ:

Я только что сделал пару отладки и когда приложение возобновляется (на переднем плане), служба Firebase получает значение правильно .. Но если приложение на фоне (onPause) или если приложение уничтожено, служба не может извлечь правильные данные из SharedPreferences.

РЕДАКТИРОВАТЬ 2

Я удалил функцию onMessageReceived из моей FirebaseMessagingService,и переустановите это приложение на моем устройстве, и когда приложение будет уничтожено, я получу уведомление, даже если нет «onMessageReceived» ...

LAST EDIT

Решение ниже

Ответы [ 2 ]

0 голосов
/ 18 февраля 2019

Я наконец решил проблему ..

В FCM (Firebase Cloud Messaging) есть два типа сообщений:

Отображение сообщений: эти сообщения вызывают обратный вызов onMessageReceived () только тогда, когда вашприложение находится на переднем плане

Сообщения данных: эти сообщения вызывают обратный вызов onMessageReceived (), даже если ваше приложение находится на переднем плане / background / kill

Так что я должен опубликовать сообщение данных для своего приложения.Обычно это делается примерно так:

POST https://fcm.googleapis.com/fcm/send

Заголовки

Key: Content-Type, Value: application/json
Key: Authorization, Value: key=<your-server-key>

Тело, использующее темы

{
   "to": "/topics/my_topic",
   "data": {
    "my_custom_key": "my_custom_value",
    "my_custom_key2": true
    }
}

НО Это больше не работает (Ошибка 401). В этом случае возникнет проблема с аутентификацией, поскольку FCM теперь использует OAUTH 2

. Поэтому я прочитал документацию по firebase и, согласно документации, новый способ отправки сообщения данных:

POST: https://fcm.googleapis.com/v1/projects/YOUR_FIREBASEDB_ID/messages:send

Заголовки

Key: Content-Type, Value: application/json

Auth

Bearer YOUR_TOKEN 

Body

{
   "message":{
    "topic" : "xxx",
    "data" : {
         "body" : "This is a Firebase Cloud Messaging Topic Message!",
         "title" : "FCM Message"
          }
      }
 }

В URL есть идентификатор базы данных, который вы можете найтина вашей консоли Firebase.(Перейти к настройкам проекта)

А теперь давайте возьмем наш токен (он будет действителен только 1 час):

Сначала в консоли Firebase откройте Настройки> Учетные записи служб .Нажмите Создать новый закрытый ключ , надежно сохраните файл JSON, содержащий ключ.Мне нужен был этот JSON-файл для авторизации запросов к серверу вручную.Я скачал его.

Затем я создаю проект node.js и использовал эту функцию для получения моего токена;

var PROJECT_ID = 'YOUR_PROJECT_ID';
var HOST = 'fcm.googleapis.com';
var PATH = '/v1/projects/' + PROJECT_ID + '/messages:send';
var MESSAGING_SCOPE = 'https://www.googleapis.com/auth/firebase.messaging';
var SCOPES = [MESSAGING_SCOPE];

  router.get('/', function(req, res, next) {
      res.render('index', { title: 'Express' });
      getAccessToken().then(function(accessToken) {
        console.log("TOKEN: "+accessToken)
      })

    });

function getAccessToken() {
return new Promise(function(resolve, reject) {
    var key = require('./YOUR_DOWNLOADED_JSON_FILE.json');
    var jwtClient = new google.auth.JWT(
        key.client_email,
        null,
        key.private_key,
        SCOPES,
        null
    );
    jwtClient.authorize(function(err, tokens) {
        if (err) {
            reject(err);
            return;
        }
        resolve(tokens.access_token);
    });
});
}

Теперь я использую этот токен в своем почтовом запросе.Затем я отправляю свое сообщение с данными, и оно теперь обрабатывается моими приложениями onMessageReceived .

0 голосов
/ 15 февраля 2019

У меня была похожая проблема: не все из Android API работает правильно в моем FirebaseMessagingService.

Я подумал, что это может быть связано с ограничениями запуска фоновых сервисов из Oreo и выше, а сообщения FCM являютсяисключение из этих https://developer.android.com/about/versions/oreo/background#services

Я полагаю, у вас есть эта проблема только на Android> = 8, верно?

Итак, что я сделал сейчас, это два куска кода для pre-Oreoи Oreo-and-newer соответственно, запущенные из моего onMessageReceived

@Override
public void onMessageReceived(RemoteMessage remoteMessage) {
        val body = remoteMessage.getNotification().getBody()
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
            scheduleJobService(body);
        } else {
            runIntentService(body);
        }
}

, затем в runIntentService я просто запускаю службу Intent (думаю, вы знаете, как это сделать), но это может работать только до Oreo,из-за упомянутых ограничений

на Android 8 и выше вам потребуется запланировать JobService или реализовать собственный настраиваемый BroadcastReceiver ...

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

@RequiresApi(Build.VERSION_CODES.LOLLIPOP)
private fun scheduleNotificationJobService(body: String) {
    val serviceName = ComponentName(getPackageName(),
            NotificationJobService::class.java.name)

    val scheduler = getSystemService(Context.JOB_SCHEDULER_SERVICE) as JobScheduler

    val notificationInfoBundle = PersistableBundle()
    notificationInfoBundle.putString(Constants.EXTRA_NOTIF_BODY, body)

    val builder = JobInfo.Builder(JOB_ID, serviceName)
            .setOverrideDeadline(0)
            .setExtras(notificationInfoBundle)
    val notificationInfo = builder.build()
    scheduler.schedule(notificationInfo)
}

тогда ваш JobService будетхорошо, как это:

@RequiresApi(Build.VERSION_CODES.LOLLIPOP)
class NotificationJobService : JobService() {

    override fun onStopJob(params: JobParameters?): Boolean {}

    @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
    override fun onStartJob(params: JobParameters?): Boolean {
        params?.extras?.let {
            val body = it.getString(Constants.EXTRA_NOTIF_BODY)
            val preferences = getApplicationContext().getSharedPreferences("com.xxx.xxx.xxx",Context.MODE_PRIVATE)
            if(preferences.getBoolean("notf",true)){
                sendNotification(body);
            }
        }
        return false
    }
}

не забудьте объявить об этом в AndroidManifest.xml

    <service android:name=".push.NotificationJobService"
        android:permission="android.permission.BIND_JOB_SERVICE">
    </service>

дайте мне знать, пожалуйста, если это работает и для вас :) ура

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...