APNS

用于在 iOS 上实现 APNS 推送通知,在 Android 上实现 Firebase 的插件。

为什么制作这个插件?

目前,唯一可用的推送通知插件是 `firebase_messaging`。这意味着,即使在 iOS 上,您也需要设置 firebase 并与 Google 通信以发送推送通知。此插件通过提供原生 APNS 实现来解决此问题,同时保留为 Android 配置的 Firebase。

用法

  1. 根据说明在 Android 上配置 firebase:https://pub.dartlang.org/packages/firebase_messaging

  2. 在 iOS 上,请确保您已正确配置应用程序以支持推送通知,并已生成用于发送推送的证书/令牌。有关更多信息,请参阅 如何运行 iOS 示例应用程序 部分。

  3. 将以下行添加到 iOS 项目的 AppDelegate.m/AppDelegate.swift 文件中的 `didFinishLaunchingWithOptions` 方法中。

Objective-C

if (@available(iOS 10.0, *)) {
  [UNUserNotificationCenter currentNotificationCenter].delegate = (id<UNUserNotificationCenterDelegate>) self;
}

Swift

if #available(iOS 10.0, *) {
  UNUserNotificationCenter.current().delegate = self as? UNUserNotificationCenterDelegate
}
  1. 将 `flutter_apns` 添加到您 `pubspec.yaml` 文件中的 依赖项
  2. 使用 `createPushConnector()` 方法,根据您的需求配置推送服务。`PushConnector` 非常类似于 `FirebaseMessaging`,因此在实现过程中 Firebase 示例可能很有用。您应该尽快创建连接器,以使 onLaunch 回调在应用程序关闭时启动时能够正常工作。

import 'package:flutter_apns/apns.dart';

final connector = createPushConnector();
connector.configure(
    onLaunch: _onLaunch,
    onResume: _onResume,
    onMessage: _onMessage,
);
connector.requestNotificationPermissions()
  1. 在设备上构建,并使用 Firebase 控制台(Android)和 CURL(iOS,请参阅 如何运行 iOS 示例应用程序)测试您的解决方案。

其他 APNS 功能

在前台显示通知

final connector = createPushConnector();
if (connector is ApnsPushConnector) {
  connector.shouldPresent = (x) => Future.value(true);
}

处理预定义操作

首先,配置支持的操作

final connector = createPushConnector();
if (connector is ApnsPushConnector) {
  connector.setNotificationCategories([
    UNNotificationCategory(
      identifier: 'MEETING_INVITATION',
      actions: [
        UNNotificationAction(
          identifier: 'ACCEPT_ACTION',
          title: 'Accept',
          options: [],
        ),
        UNNotificationAction(
          identifier: 'DECLINE_ACTION',
          title: 'Decline',
          options: [],
        ),
      ],
      intentIdentifiers: [],
      options: [],
    ),
  ]);
}

然后,在您的推送处理程序中处理可能的操作

Future<dynamic> onPush(String name, RemoteMessage payload) {
  final action = UNNotificationAction.getIdentifier(payload.data);

  if (action == 'MEETING_INVITATION') {
    // do something
  }

  return Future.value(true);
}

注意:如果用户在应用程序处于后台时点击您的通知,推送将通过 onResume 传递,而不会实际唤醒应用程序。请确保您对给定操作的处理快速且无误,因为后台运行的应用程序的执行时间非常有限。

请查看示例项目以获取完整的可用代码。

启用 FirebaseCore

如果您想使用 firebase,但不是 firebase messaging,请将此配置条目添加到您的 Info.plist(以避免 MissingPluginException)。

<key>flutter_apns.disable_firebase_core</key>
<false/>

flutter_apns_only – 无 firebase 的 APNS

如果您只关心 apns – 请使用 flutter_apns_only 插件。它不依赖于 firebase。为确保不发生(原始插件需要此操作来禁用 firebase)的 swizzling,请将此配置条目添加到您的 Info.plist。

<key>flutter_apns.disable_swizzling</key>
<true/>

故障排除

  1. 确保您在实际设备上进行测试。注意:从 11.4 开始可能不需要此项:https://ohmyswift.com/blog/2020/02/13/simulating-remote-push-notifications-in-a-simulator/
  2. 如果 onToken 方法未被调用,请在您的 AppDelegate 中添加错误日志记录,请参阅下面的代码。
  3. 打开 macOS 的 Console 应用程序,连接您的设备,然后运行您的应用程序。在日志中搜索“PUSH registration failed”字符串。错误消息将告诉您出了什么问题。

swift

import UIKit
import Flutter

@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
  override func application(
    _ application: UIApplication,
    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
  ) -> Bool {
    GeneratedPluginRegistrant.register(with: self)
    return super.application(application, didFinishLaunchingWithOptions: launchOptions)
  }

  func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
     NSLog("PUSH registration failed: \(error)")
  }
}

objc

#include "AppDelegate.h"
#include "GeneratedPluginRegistrant.h"

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application
    didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
  [GeneratedPluginRegistrant registerWithRegistry:self];
  // Override point for customization after application launch.
  return [super application:application didFinishLaunchingWithOptions:launchOptions];
}

-(void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error {
    NSLog(@"%@", error);
}

@end

如何运行 iOS 示例应用程序

在 iOS 上设置推送通知可能会很棘手,因为无法允许需要复杂证书设置的 Apple Push Notification Service (APNS)。以下指南描述了一个分步方法,用于通过此包的示例应用程序从 Mac 向 iPhone 发送推送通知。本指南仅描述调试环境设置。

  1. 使用 Xcode 打开示例 iOS 文件夹
  2. 选择 Runner -> Signing & Capabilities
  3. 选择您的开发团队,并添加一个全局唯一的捆绑标识符。图片中的那个已占用:
  4. 访问 https://developer.apple.com/account/resources/identifiers/list/bundleId 并点击加号按钮。
  5. 选择“App IDs”并继续
  6. 选择类型“App”
  7. 选择“App ID Prefix”,它应该与“Team ID”相同。
  8. 输入描述和捆绑标识符。后者需要与 3 中指定的捆绑标识符相同。
  9. 选择推送通知功能
  10. 点击“Continue”然后点击“Register”。
  11. 访问 https://developer.apple.com/account/resources/certificates 并通过点击加号按钮添加新证书。
  12. 选择“Apple Push Notification service SSL (Sandbox & Production)”
  13. 选择您在第 4-10 点定义的应用程序 ID。
  14. 选择一个证书签名请求 (CSR) 文件。有关如何创建此证书的信息,请参阅 https://help.apple.com/developer-account/
  15. 完成后,下载新创建的 Apple Push Services 证书。
  16. 通过打开新下载的文件将证书添加到您的本地钥匙串。
  17. 点击钥匙串窗口左上角的“login”,然后选择“My Certificates”选项卡
  18. 右键单击 Apple-Push-Services-certificate,然后将其导出为 .p12 文件。
  19. 使用以下命令将 p12 文件转换为 pem 文件。请注意,“flutterApns”需要替换为您相应的证书名称。 更多信息

    openssl pkcs12 -in flutterApns.p12 -out flutterApns.pem -nodes -clcerts
    
  20. 从 Xcode 或您喜欢的 IDE 在物理 iPhone 设备上启动示例应用程序。
  21. 当应用程序能够从 APNS 检索到推送令牌时,设备令牌会自动打印出来。这发生在接受通知权限提示后。
  22. 从您的开发 Mac 发送以下 CURL。您可以将 CURL 复制并粘贴到终端中执行,然后按 Enter。 更多信息

    curl -v \
    -d '{"aps":{"alert":"<your_message>","badge":2}}' \
    -H "apns-topic: <bundle_identifier_of_registered_app>" \
    -H "apns-priority: 10" \
    --http2 \
    --cert <file_path_to_downloaded_signed_and_converted_certificate>.pem \
    https://api.development.push.apple.com/3/device/<device_token>
    
  23. 当示例应用程序处于后台时,会出现推送通知。

如果不使用示例应用程序,您还需要 在 Xcode 中设置推送通知功能 并添加 使用 中提到的代码。

GitHub

查看 Github