ios - didReceiveRemoteNotification não está funcionando em segundo plano




xcode push-notification (3)

  1. Registre-se para receber notificações push no delegado do aplicativo.
  2. Adicione o modo de segundo plano nos recursos do aplicativo.
  3. Adicione "content-available" = "1" ao enviar a notificação por push (se você estiver usando o firebase, substitua "content-available" = "1" por "content_available" = "true" ao enviar a notificação por push do servidor).

Estou trabalhando em um grande aplicativo com um grande pedaço de código legado. Atualmente - há uma implementação para:

- (void) application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo

O problema é que ele é chamado apenas quando o aplicativo está em primeiro plano OU quando o usuário toca na notificação enquanto o aplicativo está em segundo plano. Eu tentei implementar:

- (void) application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler

Mas o aplicativo se comporta da mesma maneira. De qualquer forma - esse método não é chamado quando o aplicativo está em segundo plano. Qual poderia ser o problema?


Estou criando um projeto iOS que utilizará o Firebase Cloud Messaging (FCM) para fornecer elementos de dados personalizados, enviados via notificações Firebase / APNS, de um servidor da empresa para o dispositivo iOS.

A primeira coisa que eu precisava entender é que, diferente do Android, não existe um tipo semelhante de 'Serviço' capaz de capturar e salvar as informações que estou enviando, independentemente de o aplicativo estar em primeiro plano (ativo), em segundo plano (ainda na memória) ou não está ativo (não está na memória). Portanto, eu tenho que usar as mensagens de notificação e não as mensagens de dados, como eu havia projetado para o Android.

Depois de muita leitura para entender o Apple APNS e a interface do Firebase entre o aplicativo iOS e o servidor APNS, observando inúmeras postagens no e outros recursos da web, finalmente descobri como fazer isso funcionar de acordo com meus requisitos.

Quando uma mensagem de Notificação do Firebase Cloud Messaging (FCM) é enviada do servidor (ou Firebase Console como o FCM é padronizado como Mensagens de Notificação NÃO de Dados), ela é entregue via APNS e apresentada como uma notificação no dispositivo iOS. Quando o usuário toca no banner de notificação, o iOS faz o seguinte: se o aplicativo não estiver em execução / carregado, o iOS inicia o aplicativo, se o aplicativo está carregado / em execução, mas em segundo plano, o iOS coloca o aplicativo em primeiro plano OU se o aplicativo estiver em execução. em primeiro plano (todos os três casos), o conteúdo da mensagem é entregue por meio do aplicativo func (_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any], fetchCompletionHandler conclusãoHandler: (UIBackgroundFetchResult) -> Void) {}.

Uma coisa é certa: você deve ativar os modos de segundo plano e verificar a notificação remota; NÃO é necessário incluir {"content-available": 1} na carga útil.

1) Siga as configurações do APNS e do Firebase, bastante direto, gere e registre certificados e tal.

2) No appDelegate, didFinishLaunchingWithOptions, adicione:

        Messaging.messaging().delegate = self as? MessagingDelegate

        if #available(iOS 10.0, *) {

            UNUserNotificationCenter.current().delegate = self

            let authOptions: UNAuthorizationOptions = [.alert, .badge, .sound]

            UNUserNotificationCenter.current().requestAuthorization(
                options: authOptions,
                completionHandler: {_, _ in })
        }
        else {

            let settings: UIUserNotificationSettings =
                UIUserNotificationSettings(types: [.alert, .badge, .sound], categories: nil)

            application.registerUserNotificationSettings(settings)
        }

        application.registerForRemoteNotifications()

3) Em seguida, adicione estas funções de retorno de chamada ao appDelegate:

    func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: (UIBackgroundFetchResult) -> Void) {

        // Print message ID.
        if let messageID = userInfo["gcm.message_id"] {

            print("\n*** application - didReceiveRemoteNotification - fetchCompletionHandler - Message ID: \(messageID)")
        }

        // Print full message.
        print("\n*** application - didReceiveRemoteNotification - full message - fetchCompletionHandler, userInfo: \(userInfo)")

        myNotificationService?.processMessage(title: userInfo["Title"] as! String
            , text: userInfo["Text"] as! String, completion: { (success) in

                if success {
                    completionHandler(.newData)
                }
                else {
                    completionHandler(.noData)
                }
        })
    }

    func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {

        completionHandler([.alert, .badge, .sound])
    }

Muito útil:

https://developer.apple.com/library/archive/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/CreatingtheNotificationPayload.html

https://firebase.googleblog.com/2017/01/debugging-firebase-cloud-messaging-on.html


Implementando didReceiveRemoteNotification e didReceiveRemoteNotification:fetchCompletionHandler é a maneira correta, mas você também precisa fazer o seguinte:

Certifique-se de se registrar para receber notificações remotas, consulte a documentação aqui :

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{    
    [[UIApplication sharedApplication] registerForRemoteNotificationTypes:(UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound)];

    return YES;
}

Certifique-se também de editar o Info.plist e marque as Info.plist seleção "Ativar modos de segundo plano" e "Notificações remotas":

Além disso, você precisa adicionar "content-available":1 à carga útil da notificação por push, caso contrário, o aplicativo não será ativado se estiver em segundo plano (consulte a documentação aqui ):

Para uma notificação por push acionar uma operação de download, a carga útil da notificação deve incluir a chave de conteúdo disponível com seu valor definido como 1. Quando essa chave está presente, o sistema ativa o aplicativo em segundo plano (ou o lança em segundo plano) e chama o aplicativo do delegado do aplicativo: didReceiveRemoteNotification: fetchCompletionHandler: method. Sua implementação desse método deve baixar o conteúdo relevante e integrá-lo ao seu aplicativo

Portanto, a carga útil deve ser pelo menos assim:

{
    aps = {
        "content-available" : 1,
        sound : ""
    };
}




apple-push-notifications