xamarin android пользовательские push-уведомления не получаются при закрытии приложения - PullRequest
0 голосов
/ 30 апреля 2018

возникла проблема, при которой эта настройка полностью работает:

1) создал концентратор уведомлений Azure и настроил ios apn и firebase fcm
2) добавлен код в приложение xamarin forms в ios и android для получения настраиваемого push-уведомления с использованием шаблона.
3) версия шаблона работает на 100% на ios (убитое приложение, фон и передний план), когда дело доходит до получения уведомления.
4) на xamarin android работает как передний, так и задний план, выбирая пользовательские push-уведомления и обрабатывая их.

Проблема: Я не могу отобразить xamarin android (в трее) или даже связать пользовательское push-уведомление с моим приложением. Это моя проблема, и я не могу найти способ сделать это? Любая помощь, ребята, очень ценится.

мой пользовательский шаблон:

string templateBodyAPNS = "{"data":{"message":"$(titleParam)","name":"$(bodyParam)","image":"$(imageParam)","url":"$(urlParam)"}}";

note : я удалил \ "в приведенном выше коде, чтобы сделать его более читабельным

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

Ответы [ 2 ]

0 голосов
/ 30 апреля 2018

Этот код может помочь вам реализовать что-то вроде Firebase JobDispacher

Этот пример с GCM, но важным здесь является WakefulBroadcastReceiver:

using Android.Support.V4.Content;
using Android.Content;
using Android.App;

[assembly: Permission(Name = "@PACKAGE_NAME@.permission.C2D_MESSAGE")]
[assembly: UsesPermission(Name = "@PACKAGE_NAME@.permission.C2D_MESSAGE")]
[assembly: UsesPermission(Name = "com.google.android.c2dm.permission.RECEIVE")]
[assembly: UsesPermission(Name = "android.permission.GET_ACCOUNTS")]
[assembly: UsesPermission(Name = "android.permission.INTERNET")]
[assembly: UsesPermission(Name = "android.permission.WAKE_LOCK")]

namespace PushNotification.Droid {
    [BroadcastReceiver(Permission = "com.google.android.c2dm.permission.SEND")]
    [IntentFilter(new string[] { "com.google.android.c2dm.intent.RECEIVE" }, Categories = new string[] { "@PACKAGE_NAME@" })]
    [IntentFilter(new string[] { "com.google.android.c2dm.intent.REGISTRATION" }, Categories = new string[] { "@PACKAGE_NAME@" })]
    [IntentFilter(new string[] { "com.google.android.gcm.intent.RETRY" }, Categories = new string[] { "@PACKAGE_NAME@" })]
    [IntentFilter(new string[] { Intent.ActionBootCompleted })]
    public class WakefulReceiver : WakefulBroadcastReceiver {
        public override void OnReceive(Context context, Intent intent) {
            StartWakefulService(context, intent);
        }
    }
}

WakefulBroadcastReceiver может запустить IntentService, если приложение убито. Итак, когда вы получаете PushNotification, вы можете обработать его следующим образом:

using System;
using Android.App;
using Android.Content;
using Android.Support.V4.Content;

namespace PushNotification.Droid {
    [Service(Exported = false), IntentFilter(new[] { "com.google.android.c2dm.intent.RECEIVE" }, Categories = new string[] { "@PACKAGE_NAME@" })]
    public class GCMNotificationIntentService : IntentService {
        public GCMNotificationIntentService() { }

        protected override void OnHandleIntent(Intent intent) {
            try {
                //I try to handle my push notification
                HandlePushNotification(ApplicationContext, intent);
            } finally {
                // But always run my intent with wakeful receiver
                // To ensure that it will be done
                WakefulReceiver.CompleteWakefulIntent(intent);
            }
        }


        private void HandlePushNotification(Context context, Intent intent) {
            Intent notificationReceived = new Intent(PushEventCenter.EVENT_NAMES.PUSH_NOTIFICATION_RECEIVED);
            foreach (String key in intent.Extras.KeySet()) {
                notificationReceived.PutExtra(key, intent.Extras.GetString(key));
            }
            LocalBroadcastManager.GetInstance(this).SendBroadcast(notificationReceived);
        }
    }
}

WakefulBroadcastReceiver устарело с API 26, но дает представление о том, как обеспечить выполнение моего кода, когда мое приложение не на переднем плане.

0 голосов
/ 30 апреля 2018

Вам нужно использовать Firebase JobDispatcher. Вы можете найти некоторую информацию здесь и здесь код. По сути, держите сервис, чтобы запустить его, когда это возможно, даже когда приложение убито.

Работает так:

Это ваш FirebaseService заявленный в manifest:

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

И реализация:

public class FirebaseCloudMessagingService extends FirebaseMessagingService {

    @Override
    public void onMessageReceived(RemoteMessage remoteMessage) {

        Map<String, String> data = remoteMessage.getData();
        Log.i("PUSH", data.toString());
        if (ApplicationContextProvider.isInBackground()) {
            //***********************
            //This is the most important portion of code
            FirebaseJobDispatcher dispatcher = new FirebaseJobDispatcher(new GooglePlayDriver(getApplicationContext()));
            Job myJob = dispatcher.newJobBuilder()
                .setService(SyncAppInBackgroundService.class) // the JobService that will be called
                .setTag("my-unique-tag")        // uniquely identifies the job
                .build();

            dispatcher.mustSchedule(myJob);
            //***********************
        } else {
            // This code manage the PushNotification when the user is in the app
            int notificationType = Integer.valueOf(data.get("type"));
            switch (notificationType) {
                case Constants.PushNotification.TYPE_NEW_MESSAGE:
                case Constants.PushNotification.TYPE_CHECK_MESSAGE:
                    if (Chat.TABLE.getByServerId(Long.valueOf(data.get("idChat"))) != null) {
                        new SyncAppHandler(null).execute(SyncAppHandler.SynchronizeTaskType.SynchronizeTaskTypeMessages);
                        break;
                    }
                case Constants.PushNotification.TYPE_NEW_GROUP:
                case Constants.PushNotification.TYPE_EDIT_CHAT_USER:
                    new SyncAppHandler(null).execute(SyncAppHandler.SynchronizeTaskType.SynchronizeTaskTypeChats);
                    break;
            }
        }
    }
}

Теперь нам нужно создать JobService для планирования:

public class SyncAppInBackgroundService extends JobService implements SyncAppDelegate {

    private JobParameters params;

    private SyncAppHandler syncAppHandler;
    private SynchronizeTaskType lastTask = SynchronizeTaskType.SynchronizeTaskTypeLogin;

    @Override
    public boolean onStartJob(JobParameters job) {
        // Do some work here
        params = job;
        syncAppHandler = new SyncAppHandler(this);
        syncAppHandler.execute(lastTask);
        return true; // Answers the question: "Is there still work going on?"
    }

    @Override
    public boolean onStopJob(JobParameters job) {
        return true;// Answers the question: "Should this job be retried?"
    }

    @Override
    public void didFinishExecutingTaskWithResult(SynchronizeTaskType type, int result) {
        //handle the sync and if you finished, call:
        jobFinished(params, true);
    }
}

Не добавляйте его в манифест:

<service
    android:name=".services.SyncAppInBackgroundService"
    android:exported="false">
    <intent-filter>
        <action android:name="com.firebase.jobdispatcher.ACTION_EXECUTE" />
    </intent-filter>
</service>

Все, что вам нужно сейчас, - это создать SyncAppHandler. Этот класс мой, не расширяет ни один класс Android или библиотеку. Просто внедрите там свой бизнес-код или переговоры для синхронизации.


EXTRA:

Мой способ узнать, находится ли приложение в фоновом режиме. Возвращает false только если приложение находится на переднем плане, во всех других случаях, таких как телефон заблокирован, приложение убито ... возвращает true.

public static boolean isInBackground() {
    RunningAppProcessInfo myProcess = new RunningAppProcessInfo();
    ActivityManager.getMyMemoryState(myProcess);
    if (myProcess.importance != RunningAppProcessInfo.IMPORTANCE_FOREGROUND)
        return true;

    KeyguardManager keyguardManager = (KeyguardManager) getContext().getSystemService(Context.KEYGUARD_SERVICE);
    return keyguardManager.inKeyguardRestrictedInputMode(); // app is in foreground, but if screen is locked show notification anyway
}
...