iOS Firebase 推送通知:如何提供 Firebase 用户的设备令牌并发送通知

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/37667753/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-31 09:16:24  来源:igfitidea点击:

iOS Firebase Push Notifications : How To Give Firebase User's Device Token And Send Notification

iospush-notificationfirebase

提问by EQOxx123

Somewhat recently at the Google I/O event Google renovated Firebase & added a lot of new features, and touched up on the remaining ones. I have been trying to implement the iOS Push Notifications via Firebase into my app through the most basic level, So I created a very simple app that really does nothing besides receive remote push notifications.

最近在 Google I/O 活动中,Google 翻新了 Firebase 并添加了许多新功能,并对其余功能进行了改进。我一直在尝试通过最基本的级别通过 Firebase 将 iOS 推送通知实现到我的应用程序中,所以我创建了一个非常简单的应用程序,除了接收远程推送通知之外,它真的什么都不做。

Inside of Firebase, I have uploaded my certificate and within Xcode my provisioning profiles have been added to both the target and project, and in Firebase I have uploaded the correct certificate. Below is the code contained inside of my AppDelegate.swiftfile but because my ViewController.swiftis "empty," I did not include it.

在 Firebase 中,我上传了我的证书,在 Xcode 中我的配置文件已添加到目标和项目中,并且在 Firebase 中我上传了正确的证书。下面是我的AppDelegate.swift文件中包含的代码,但因为我的文件ViewController.swift是“空的”,所以我没有包含它。

Although there are no crashes or runtime errors, when I load the app, I accept the notifications. Then, I exit the app and turn off my device. In Firebase, I send the notification to the correct app. After a couple of minutes, in Firebase it says the notification was "Completed".

虽然没有崩溃或运行时错误,但当我加载应用程序时,我接受了通知。然后,我退出应用程序并关闭我的设备。在 Firebase 中,我将通知发送到正确的应用程序。几分钟后,在 Firebase 中,它说通知“已完成”。

However, I never received the notification on the device. So, in conclusion, I need a solution to send Firebase this deviceTokenand then use 'Firebase Notifications' to send the push notification Message.

但是,我从未在设备上收到通知。因此,总而言之,我需要一个解决方案来发送 Firebase deviceToken,然后使用“Firebase 通知”发送推送通知消息。

Any help for my code or in general would be greatly appreciated and I hope this helps future viewers. Thank you! My code in AppDelegate.swift:

对我的代码或一般情况的任何帮助将不胜感激,我希望这有助于未来的观众。谢谢!我的代码AppDelegate.swift

import UIKit
import Firebase
import FirebaseMessaging

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?

    func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {

        FIRApp.configure()

        let notificationTypes : UIUserNotificationType = [UIUserNotificationType.Alert, UIUserNotificationType.Badge, UIUserNotificationType.Sound]

        let notificationSettings = UIUserNotificationSettings(forTypes: notificationTypes, categories: nil)

        application.registerForRemoteNotifications()
        application.registerUserNotificationSettings(notificationSettings)

        return true
    }

    func application(application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: NSData) {

        print("Device Token: \(deviceToken)")

    }

    func applicationWillResignActive(application: UIApplication) {

    }

    func applicationDidEnterBackground(application: UIApplication) {

    }

    func applicationWillEnterForeground(application: UIApplication) {

    }

    func applicationDidBecomeActive(application: UIApplication) {

    }

    func applicationWillTerminate(application: UIApplication) {

    }

    func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject], fetchCompletionHandler completionHandler: (UIBackgroundFetchResult) -> Void) {

        print("MessageID : \(userInfo["gcm.messgae_id"]!)") // or gcm_etc...

        print(userInfo)

    }


}

回答by onmyway133

Updated: As of Firebase 4.0.4, you can follow https://github.com/onmyway133/blog/issues/64

更新:从 Firebase 4.0.4 开始,您可以关注https://github.com/onmyway133/blog/issues/64

HOW APNS DEVICE TOKEN IS HANDLED

如何处理 APNS 设备令牌

I've been reading Send a Notification to a User Segment on iOSbut there is no mention of APNS device token, which is crucial to push notifications.

我一直在阅读在 iOS 上向用户段发送通知,但没有提到 APNS 设备令牌,这对于推送通知至关重要。

So Firebase must be doing some swizzling under the hood. In fact it is. Reading backend documentation Downstream Messagesgives us the idea

所以 Firebase 必须在幕后进行一些调整。事实上它是。阅读后端文档下游消息给了我们这个想法

Swizzlingdisabled: mapping your APNs token and registration token

If you have disabled method swizzling, you'll need to explicitly map your APNs token to the FCM registration token. Override the

methods didRegisterForRemoteNotificationsWithDeviceTokento retrieve the APNs token, and then call setAPNSToken.

Swizzling 已禁用:映射您的 APNs 令牌和注册令牌

If you have disabled method swizzling, you'll need to explicitly map your APNs token to the FCM registration token. Override the

方法didRegisterForRemoteNotificationsWithDeviceToken来检索 APNs 令牌,然后调用setAPNSToken.

func application(application: UIApplication,
                   didRegisterForRemoteNotificationsWithDeviceToken deviceToken: NSData) {
  FIRInstanceID.instanceID().setAPNSToken(deviceToken, type: FIRInstanceIDAPNSTokenTypeSandbox)
}

I particularly try to avoid swizzling as much as possible. Reading Migrate a GCM Client App for iOS to Firebase Cloud Messaginggives us how to do disable it

我特别尽量避免 swizzling。阅读Migrate a GCM Client App for iOS to Firebase Cloud Messaging为我们提供了如何禁用它

Enabling/disabling method swizzling

启用/禁用方法调配

Method swizzling available with FCM simplifies your client code. However, for developers who prefer not to use it, FCM allows you to disable method swizzling by adding the FIRMessagingAutoRegisterEnabledflagin the app's Info.plist file and setting its value to NO (boolean value).

FCM swizzling affects how you handle the default registration token, and how you handle downstream message callbacks. Where

applicable, this guide provides migration examples both with and without method swizzling enabled.

FCM 提供的方法混合可简化您的客户端代码。但是,对于不喜欢使用它的开发人员,FCM 允许您通过在应用程序的 Info.plist 文件中添加FIRMessagingAutoRegisterEnabledflag并将其值设置为 NO(布尔值)来禁用方法 调配

FCM swizzling affects how you handle the default registration token, and how you handle downstream message callbacks. Where

适用,本指南提供了启用和不启用方法调配的迁移示例。

SHOW ME THE CODE

给我看代码

Have this in your Podfile

有这个在你的 Podfile

pod 'Firebase'
pod 'FirebaseMessaging'

Here is the completed code

这是完成的代码

import Firebase
import FirebaseMessaging

override func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
  FIRApp.configure()

  NSNotificationCenter.defaultCenter().addObserver(self,
                                                   selector: #selector(tokenRefreshNotification(_:)),
                                                   name: kFIRInstanceIDTokenRefreshNotification,
                                                   object: nil)
}

// NOTE: Need to use this when swizzling is disabled
public func application(application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: NSData) {

  FIRInstanceID.instanceID().setAPNSToken(deviceToken, type: FIRInstanceIDAPNSTokenType.Sandbox)
}

func tokenRefreshNotification(notification: NSNotification) {
  // NOTE: It can be nil here
  let refreshedToken = FIRInstanceID.instanceID().token()
  print("InstanceID token: \(refreshedToken)")

  connectToFcm()
}

func connectToFcm() {
  FIRMessaging.messaging().connectWithCompletion { (error) in
    if (error != nil) {
      print("Unable to connect with FCM. \(error)")
    } else {
      print("Connected to FCM.")
    }
  }
}

public func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject]) {
  print(userInfo)
}

回答by Sanandiya Vipul

Integrate without CocoaPods

无需 CocoaPods 即可集成

First Read Firebase Doc.=> Firebase Doc

首先阅读 Firebase 文档。=> Firebase 文档

  1. Register project on Firebase here => Register Project here

  2. Get GoogleService-Info.plist file from here=> project=> settings => General

  3. GoogleService-Info.plist file drop in your project.

  4. set Notification .p12 Certificates (Production and Development) in Firebase => project=> settings => Cloud Messaging

  5. Download Firebase SDK here => Firebase SDK Download

  6. Create SDK folder in your project and Drop all SDK Folder in it.

  7. Now Add this Framework in your Xcode => libicucore.tbd

  8. Set Background Modes ON in Xcode => Projects => Capabilities => Background Mode ON => RemoteNotification
  9. Add in your Info.Plist file FirebaseAppDelegateProxyEnabledSet BOOL NO.
  1. 在此处在 Firebase 上注册项目 => 在此处注册项目

  2. 从这里获取 GoogleService-Info.plist 文件 => 项目 => 设置 => 常规

  3. GoogleService-Info.plist 文件放入您的项目中。

  4. 在 Firebase => 项目 => 设置 => 云消息传递中设置 Notification .p12 证书(生产和开发)

  5. 在此处下载 Firebase SDK => Firebase SDK 下载

  6. 在您的项目中创建 SDK 文件夹并将所有 SDK 文件夹放入其中。

  7. 现在在你的 Xcode 中添加这个框架 => libicucore.tbd

  8. 在 Xcode 中设置背景模式 => 项目 => 功能 => 背景模式开启 => 远程通知
  9. 在您的 Info.Plist 文件中添加FirebaseAppDelegateProxyEnabled设置 BOOL NO

enter image description here

在此处输入图片说明

In Objective-c your Appdelegate.m file

在 Objective-c 中你的 Appdelegate.m 文件

#import "AppDelegate.h"
#import "Firebase.h"
#import "AFNHelper.h"

@interface AppDelegate (){

    NSString *InstanceID;
}
@property (nonatomic, strong) NSString *strUUID;
@property (nonatomic, strong) NSString *strDeviceToken;
@end
@implementation AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

    UIUserNotificationType allNotificationTypes =
    (UIUserNotificationTypeSound | UIUserNotificationTypeAlert | UIUserNotificationTypeBadge);
    UIUserNotificationSettings *settings =
    [UIUserNotificationSettings settingsForTypes:allNotificationTypes categories:nil];
    [[UIApplication sharedApplication] registerUserNotificationSettings:settings];
    [[UIApplication sharedApplication] registerForRemoteNotifications];

    [FIRApp configure];

    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(tokenRefreshNotification:) name:kFIRInstanceIDTokenRefreshNotification object:nil];

    return YES;
}
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {

    NSLog(@"Message ID: %@", userInfo[@"gcm.message_id"]);
    [[FIRMessaging messaging] appDidReceiveMessage:userInfo];

    NSLog(@"userInfo=>%@", userInfo);
}
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {

    [[FIRInstanceID instanceID] setAPNSToken:deviceToken type:FIRInstanceIDAPNSTokenTypeProd];
    NSLog(@"deviceToken1 = %@",deviceToken);

}
- (void)tokenRefreshNotification:(NSNotification *)notification {
   NSLog(@"instanceId_notification=>%@",[notification object]);
    InstanceID = [NSString stringWithFormat:@"%@",[notification object]];

 [self connectToFcm];  
}

- (void)connectToFcm {

[[FIRMessaging messaging] connectWithCompletion:^(NSError * _Nullable error) {
    if (error != nil) {
        NSLog(@"Unable to connect to FCM. %@", error);
    } else {

        NSLog(@"InstanceID_connectToFcm = %@", InstanceID);
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{

            dispatch_async(dispatch_get_main_queue(), ^{
                [self sendDeviceInfo];
                NSLog(@"instanceId_tokenRefreshNotification22=>%@",[[FIRInstanceID instanceID] token]);

            });
        });


    }
}];
}

回答by Shubhank

Docs are pretty poor for the FCM for iOS now.

现在,iOS 版 FCM 的文档非常糟糕。

Follow the sampleapp they have on github

按照他们在 github 上的示例应用程序

Important part added here :

重要部分在这里添加:

import Firebase
import FirebaseInstanceID
import FirebaseMessaging

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
    // Register for remote notifications
    if #available(iOS 8.0, *) {
      let settings: UIUserNotificationSettings =
      UIUserNotificationSettings(forTypes: [.Alert, .Badge, .Sound], categories: nil)
      application.registerUserNotificationSettings(settings)
      application.registerForRemoteNotifications()
    } else {
      // Fallback
      let types: UIRemoteNotificationType = [.Alert, .Badge, .Sound]
      application.registerForRemoteNotificationTypes(types)
    }

    FIRApp.configure()

    // Add observer for InstanceID token refresh callback.
    NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(self.tokenRefreshNotificaiton),
        name: kFIRInstanceIDTokenRefreshNotification, object: nil)

    return true
  }

 func tokenRefreshNotificaiton(notification: NSNotification) {
    let refreshedToken = FIRInstanceID.instanceID().token()!
    print("InstanceID token: \(refreshedToken)")

    // Connect to FCM since connection may have failed when attempted before having a token.
    connectToFcm()
  }
  // [END refresh_token]

  // [START connect_to_fcm]
  func connectToFcm() {
    FIRMessaging.messaging().connectWithCompletion { (error) in
      if (error != nil) {
        print("Unable to connect with FCM. \(error)")
      } else {
        print("Connected to FCM.")
      }
    }
  }

Now your token has been sent to the FCM server

现在您的令牌已发送到 FCM 服务器