# iOS 推送自定义

当 iOS 设备收到包含提醒的通知时，系统会分两个阶段显示提醒内容。首先，它会显示一个缩略横幅，其中包含通知的标题、副标题和两到四行的正文文本。如果用户按下缩略横幅，iOS 会显示完整的通知界面，包括任何与通知相关的操作。系统为缩略横幅提供界面，但您可以使用通知内容应用扩展程序自定义完整界面。

<img src="/ios-push-notifications-ios-push-customization-1.webp" alt=""/>

通知内容应用扩展程序管理一个显示自定义通知界面的视图控制器 (view controller)。此视图控制器可以补充或替换通知的默认系统界面。您可以使用视图控制器来：

*   自定义项目的位置，包括提醒的标题、副标题和正文文本。
*   为界面元素替换不同的字体或样式。
*   显示应用特定数据——例如，存储在通知有效负载 (payload) 的应用特定键中的数据。
*   包含自定义图像或品牌元素。

您的应用扩展程序必须使用立即可用的数据来配置其视图控制器，例如通知内容和应用扩展程序包 (bundle) 中存在的文件。如果您使用应用组 (app group) 在应用和应用扩展程序之间共享数据，您也可以使用在应用组中找到的任何文件。为确保您的通知能及时送达，请尽快配置视图。不要执行任何长时间运行的任务，例如尝试通过网络检索数据。

<Aside type="caution">
通知内容应用扩展程序仅在 iOS 应用中受支持。
</Aside>

### 将通知内容应用扩展程序添加到您的项目中

要将通知内容应用扩展程序添加到您的 iOS 应用中：

1.  在 Xcode 中选择 **File** > **New** > **Target**。
2.  从 iOS Application Extension 中选择 **Notification Content Extension**。
3.  点击 **Next**。
4.  为您的应用扩展程序提供一个**名称**。
5.  点击 **Finish**。

### 向您的视图控制器添加视图

Xcode 提供的模板包含一个故事板 (storyboard) 和一个视图控制器 (view controller) 供您配置。通过向视图控制器添加视图来构建您的自定义通知界面。例如，使用标签 (labels) 来显示通知的标题、副标题和正文文本。您还可以添加图像视图 (image views) 和显示非交互式内容的视图。您无需为视图提供任何初始内容。

在 iOS 12 及更高版本中，您可以添加交互式控件（例如，按钮或开关）。有关更多信息，请参阅支持交互式控件。

<Aside type="caution">
不要向您的应用扩展程序或故事板文件添加额外的视图控制器。您的应用扩展程序必须只包含一个视图控制器。
</Aside>

### 配置您的视图控制器

使用视图控制器的 `didReceive(_:)` 方法来更新其标签和其他视图。通知有效负载 (payload) 包含配置视图控制器时要使用的数据。您也可以使用来自应用扩展程序其他文件的数据。[清单 1](https://developer.apple.com/documentation/usernotificationsui/customizing_the_appearance_of_notifications#2950663) 展示了此方法的一个版本，它从通知有效负载中检索标题和正文文本，并将字符串分配给两个 [`UILabel`](https://developer.apple.com/documentation/uikit/uilabel) 控件，这些控件作为出口 (outlets) 存储在视图控制器上。

<Tabs>
<TabItem label="Swift">
```swift
// Configuring the notification interface at runtime

func didReceive(_ notification: UNNotification) {
   self.bodyText?.text = notification.request.content.body
   self.headlineText?.text = notification.request.content.title
}
```
</TabItem>
</Tabs>

如果在您的视图控制器已经可见时有第二条通知到达，系统会再次调用 `didReceive(_:)` 方法，并传入新的通知有效负载。

### 支持交互式控件
在 iOS 12 及更高版本中，您可以在自定义通知中启用用户交互。这允许您向自定义界面添加交互式控件，例如按钮和开关。

要启用用户交互：

1.  打开您的通知内容扩展程序的 `info.plist` 文件。
2.  将 `UNNotificationExtensionUserInteractionEnabled` 键添加到您的扩展程序属性中。为其指定一个布尔值，设置为 `YES`。

<img src="/ios-push-notifications-ios-push-customization-2.webp" alt="在通知扩展程序的 info.plist 文件中启用用户交互"/>

### 将 Apple Pay 添加到您的推送通知扩展程序中（示例视图）
<br />
<img
  src="/ios-push-notifications-ios-push-customization-3.webp"
  alt=""
  style={{ display: "block", margin: "0 auto", maxWidth: "60%", height: "auto" }}
  width="400"
/>

### 在推送通知扩展程序中使用 Apple Pay 按钮的代码块示例

<Tabs>
<TabItem label="Swift">
```swift
import UIKit
import Foundation
import UserNotifications
import UserNotificationsUI
import PassKit

class NotificationViewController: UIViewController, UNNotificationContentExtension, PKPaymentAuthorizationViewControllerDelegate {


    func paymentAuthorizationViewControllerDidFinish(_ controller: PKPaymentAuthorizationViewController) {
        controller.dismiss(animated: true, completion: nil)
    }


    @IBOutlet weak var buyWithApplePayButton: UIButton!
    @IBOutlet weak var containerView: UIView!
    @IBOutlet weak var payInAppButton: UIButton!
    @IBOutlet weak var segmentCustom: UISegmentedControl!

    private var amount: NSDecimalNumber = 0;

    override func viewDidLoad() {
        super.viewDidLoad()

        buttonCustomisation()

        amount = NSDecimalNumber.init(value: 5)
    }

    func buttonCustomisation () {
        self.buyWithApplePayButton.layer.masksToBounds = true
        self.buyWithApplePayButton.layer.cornerRadius = 10
        self.payInAppButton.layer.masksToBounds = true
        self.payInAppButton.layer.cornerRadius = 10
        self.containerView.layer.borderColor = UIColor.gray.cgColor
        self.containerView.layer.borderWidth = 0.7
        self.containerView.layer.masksToBounds = true
        self.containerView.layer.cornerRadius = 20
    }

    func didReceive(_ notification: UNNotification) {
        // Configuring the notification interface at runtime
    }

    @IBAction func buyWithApplePayAction(_ sender: Any) {
        let request = PKPaymentRequest()
        request.merchantIdentifier = "merchant.com.sample.ApplePayAction"
        request.supportedNetworks = [PKPaymentNetwork.visa, PKPaymentNetwork.masterCard, PKPaymentNetwork.amex]
        request.merchantCapabilities = PKMerchantCapability.capability3DS
        request.countryCode = "US"
        request.currencyCode = "USD"

        request.paymentSummaryItems = [
            PKPaymentSummaryItem(label: "Some Product", amount: amount)
        ]

        let applePayController = PKPaymentAuthorizationViewController(paymentRequest: request)
        applePayController?.delegate = self
        self.present(applePayController!, animated: true, completion: nil)
    }

    @IBAction func payInAppButtonAction(_ sender: Any) {
        print("pay in app button tapped")
    }

    @IBAction func segmentAction(_ sender: Any) {
        switch segmentCustom.selectedSegmentIndex {
        case 0:
            amount = NSDecimalNumber.init(value: 5)
            break
        case 1:
            amount = NSDecimalNumber.init(value: 10)
            break
        case 2:
            amount = NSDecimalNumber.init(value: 20)
            break
        default:
            amount = NSDecimalNumber.init(value: 5)
            break
        }
    }
}
```
</TabItem>
</Tabs>