# iOS 模态富媒体

从 Pushwoosh SDK 6.7.5 版本开始，您可以发送 **模态富媒体 (Modal Rich Media)**。

我们引入了可自定义的全新 **模态富媒体**。新的模态富媒体不会完全遮挡屏幕，并且可以放置在屏幕的不同位置（顶部、底部和中心）。

> 有关富媒体页面的更多信息，请参阅[我们的指南](/zh/product/content/rich-media)。

## 配置

<Aside type="note">
 默认情况下，Pushwoosh iOS SDK 支持显示旧版富媒体。
</Aside>

<Aside type="note">
如果您计划在 Customer Journey Builder 中将模态富媒体用作应用内消息显示，请确保您已实现如下所示的代码。有关详细信息，请参阅[基础 SDK 集成](/zh/developer/pushwoosh-sdk/ios-sdk/setting-up-pushwoosh-ios-sdk/basic-integration-guide/)。
</Aside>

```swift
//for silent push notifications
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
    Pushwoosh.configure.handlePushReceived(userInfo)
    completionHandler(.noData)
}
```

### 选项 1：Info.plist 配置

要启用模态富媒体的显示，请在您的 **info.plist** 中设置参数 `Pushwoosh_RICH_MEDIA_STYLE`，并为其分配值 `MODAL_RICH_MEDIA`。

**Info.plist**:
```xml
<key>Pushwoosh_RICH_MEDIA_STYLE</key>
<string>MODAL_RICH_MEDIA</string>
```

### 选项 2：通过代码配置 (SDK 7.0.14+)

<Aside type="tip">
自 Pushwoosh iOS SDK **7.0.14** 版本起可用。
</Aside>

您也可以在您的 AppDelegate 中通过代码配置富媒体的呈现样式：

<Tabs>
<TabItem label="Swift">
```swift
func application(_ application: UIApplication,
                 didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {

    // Set modal presentation style
    Pushwoosh.media.setRichMediaPresentationStyle(.modal)

    // Configure modal window appearance
    Pushwoosh.media.modalRichMedia.configure(
        position: .PWModalWindowPositionBottom,
        presentAnimation: .PWAnimationPresentFromBottom,
        dismissAnimation: .PWAnimationDismissDown
    )

    Pushwoosh.configure.registerForPushNotifications()
    return true
}
```
</TabItem>
<TabItem label="Objective-C">
```objective-c
- (BOOL)application:(UIApplication *)application
        didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

    // Set modal presentation style
    [[Pushwoosh media] setRichMediaPresentationStyle:PWRichMediaPresentationStyleModal];

    // Configure modal window appearance
    [[[Pushwoosh media] modalRichMedia] configureWithPosition:PWModalWindowPositionBottom
                                             presentAnimation:PWAnimationPresentFromBottom
                                             dismissAnimation:PWAnimationDismissDown];

    [[Pushwoosh configure] registerForPushNotifications];
    return YES;
}
```
</TabItem>
</Tabs>

默认情况下，模态富媒体将显示在屏幕中央，并带有从下到上的出现动画。

<div style={{ display: "flex", justifyContent: "center" }}>
<video src="/ios-push-notifications-ios-modal-rich-media-1.webm" title="示例" autoplay loop muted playsinline width="300" />
</div>

### 模态富媒体定位

模态富媒体可以放置在屏幕上的不同位置。

```objective-c
/**
 Enum defining the possible positions for displaying a modal window.

 - `PWModalWindowPositionTop`: The modal window appears at the top of the screen, within the safe area.
 - `PWModalWindowPositionCenter`: The modal window appears at the center of the screen, within the safe area.
 - `PWModalWindowPositionBottom`: The modal window appears at the bottom of the screen, within the safe area.
 - `PWModalWindowPositionBottomSheet`: The modal window appears at the very bottom of the screen, ignoring the safe area.
 - `PWModalWindowPositionDefault`: The default position is the center of the screen, within the safe area.
 */
typedef NS_ENUM(NSInteger, ModalWindowPosition) {
    PWModalWindowPositionTop,       // Appears at the top of the screen (within safe area)
    PWModalWindowPositionCenter,    // Appears at the center of the screen (within safe area)
    PWModalWindowPositionBottom,    // Appears at the bottom of the screen (within safe area)
    PWModalWindowPositionBottomSheet, // Appears at the very bottom of the screen (ignores safe area)
    PWModalWindowPositionFullScreen, // Fullscreen, ignores safe area insets
    PWModalWindowPositionDefault    // Default position (center of the screen, within safe area)
};
```

下面的示例展示了一个显示在屏幕顶部的模态富媒体。

<div style={{ display: "flex", justifyContent: "center" }}>
<video src="/ios-push-notifications-ios-modal-rich-media-2.webm" title="示例" autoplay loop muted playsinline width="300" />
</div>

模态富媒体的显示动画包括：

```objective-c
typedef NS_ENUM(NSInteger, PresentModalWindowAnimation) {
    PWAnimationPresentFromBottom,
    PWAnimationPresentFromTop,
    PWAnimationPresentFromRight,
    PWAnimationPresentFromLeft,
    PWAnimationPresentNone
};
```

模态富媒体的关闭动画包括：

```objective-c
typedef NS_ENUM(NSInteger, DismissModalWindowAnimation) {
    PWAnimationDismissDown,
    PWAnimationDismissUp,
    PWAnimationDismissLeft,
    PWAnimationDismissRight,
    PWAnimationCurveEaseInOut,
    PWAnimationDismissNone,

    /**
     * Default dismiss animation is `PWAnimationCurveEaseInOut`
     */
    PWAnimationDismissDefault
};
```

下面的示例演示了在屏幕底部显示模态富媒体，并带有从左到右的显示动画和向右的关闭动画：

<div style={{ display: "flex", justifyContent: "center" }}>
<video src="/ios-push-notifications-ios-modal-rich-media-3.webm" title="示例" autoplay loop muted playsinline width="300" />
</div>

### 模态富媒体的附加参数

<Aside type="tip">
以下 API 自 Pushwoosh iOS SDK **7.0.14** 版本起可用。
</Aside>

用于显示模态富媒体的附加参数包括添加振动类型的触觉反馈、启用滑动手势以及设置在指定持续时间后自动关闭的计时器等选项。

<Tabs>
<TabItem label="Swift">
```swift
// Haptic Feedback Type
Pushwoosh.media.modalRichMedia.setHapticFeedbackType(.PWHapticFeedbackLight)

// Swipe directions to dismiss
Pushwoosh.media.modalRichMedia.setDismissSwipeDirections([
    NSNumber(value: DismissSwipeDirection.PWSwipeDismissDown.rawValue),
    NSNumber(value: DismissSwipeDirection.PWSwipeDismissUp.rawValue)
])

// Set Rich Media corner radius
let topCorners = PWCornerTypeTopLeft.rawValue | PWCornerTypeTopRight.rawValue
Pushwoosh.media.modalRichMedia.setCornerType(CornerType(rawValue: topCorners), withRadius: 16)

// Close Modal Rich Media after N seconds
Pushwoosh.media.modalRichMedia.closeAfter(3)
```
</TabItem>
<TabItem label="Objective-C">
```objective-c
// Haptic Feedback Type
[[[Pushwoosh media] modalRichMedia] setHapticFeedbackType:PWHapticFeedbackLight];

// Swipe directions to dismiss
[[[Pushwoosh media] modalRichMedia] setDismissSwipeDirections:@[
    @(PWSwipeDismissDown),
    @(PWSwipeDismissUp)
]];

// Set Rich Media corner radius
CornerType topCorners = PWCornerTypeTopLeft | PWCornerTypeTopRight;
[[[Pushwoosh media] modalRichMedia] setCornerType:topCorners withRadius:16.0];

// Close Modal Rich Media after N seconds
[[[Pushwoosh media] modalRichMedia] closeAfter:3.0];
```
</TabItem>
</Tabs>

**触觉反馈类型：**

```objective-c
typedef NS_ENUM(NSInteger, HapticFeedbackType) {
    PWHapticFeedbackLight,         // Light vibration feedback
    PWHapticFeedbackMedium,        // Medium vibration feedback
    PWHapticFeedbackHard,          // Strong vibration feedback
    PWHapticFeedbackNone           // Vibration is off (default)
};
```

**滑动方向：**

```objective-c
typedef NS_ENUM(NSInteger, DismissSwipeDirection) {
    PWSwipeDismissDown,
    PWSwipeDismissUp,
    PWSwipeDismissLeft,
    PWSwipeDismissRight,
    PWSwipeDismissNone
};
```

## PWRichMediaPresentingDelegate

<Aside type="tip">
通过 `Pushwoosh.media.modalRichMedia.delegate` 的委托 API 自 SDK **7.0.14** 版本起可用。
</Aside>

要管理模态富媒体的队列，您需要实现 `PWRichMediaPresentingDelegate` 的委托方法。
使用此功能时，模态富媒体会按顺序呈现，下一个富媒体在用户关闭当前富媒体之前不会显示。一旦用户关闭了已呈现的富媒体，属于不同推送通知的下一个富媒体将会显示。

<Tabs>
<TabItem label="Swift">
```swift
import UIKit
import PushwooshFramework

@main
class AppDelegate: UIResponder, UIApplicationDelegate, PWRichMediaPresentingDelegate {

    var richMediaQueue: [PWRichMedia] = []
    var isPresenting = false

    func application(_ application: UIApplication,
                     didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {

        // Configure modal rich media
        Pushwoosh.media.setRichMediaPresentationStyle(.modal)
        Pushwoosh.media.modalRichMedia.configure(
            position: .PWModalWindowPositionBottom,
            presentAnimation: .PWAnimationPresentFromBottom,
            dismissAnimation: .PWAnimationDismissDown
        )

        // Set delegate
        Pushwoosh.media.modalRichMedia.delegate = self

        Pushwoosh.configure.registerForPushNotifications()
        return true
    }

    // MARK: - PWRichMediaPresentingDelegate

    func richMediaManager(_ richMediaManager: PWRichMediaManager, shouldPresent richMedia: PWRichMedia) -> Bool {
        if !richMediaQueue.contains(where: { $0 === richMedia }) {
            richMediaQueue.append(richMedia)
        }
        return !isPresenting
    }

    func richMediaManager(_ richMediaManager: PWRichMediaManager, didPresent richMedia: PWRichMedia) {
        isPresenting = true
    }

    func richMediaManager(_ richMediaManager: PWRichMediaManager, didClose richMedia: PWRichMedia) {
        isPresenting = false

        if let idx = richMediaQueue.firstIndex(where: { $0 === richMedia }) {
            richMediaQueue.remove(at: idx)
        }

        // Present next rich media in queue
        if let nextRichMedia = richMediaQueue.first {
            Pushwoosh.media.modalRichMedia.present(nextRichMedia)
        }
    }

    func richMediaManager(_ richMediaManager: PWRichMediaManager, presentingDidFailFor richMedia: PWRichMedia, withError error: Error) {
        richMediaManager(richMediaManager, didClose: richMedia)
    }
}
```
</TabItem>
<TabItem label="Objective-C">
```objective-c
#import "AppDelegate.h"
#import <PushwooshFramework/PushwooshFramework.h>

@interface AppDelegate () <PWRichMediaPresentingDelegate>

@property (nonatomic, strong) NSMutableArray<PWRichMedia *> *richMediaQueue;
@property (nonatomic, assign) BOOL isPresenting;

@end

@implementation AppDelegate

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

    self.richMediaQueue = [NSMutableArray array];
    self.isPresenting = NO;

    // Configure modal rich media
    [[Pushwoosh media] setRichMediaPresentationStyle:PWRichMediaPresentationStyleModal];
    [[[Pushwoosh media] modalRichMedia] configureWithPosition:PWModalWindowPositionBottom
                                             presentAnimation:PWAnimationPresentFromBottom
                                             dismissAnimation:PWAnimationDismissDown];

    // Set delegate
    [[[Pushwoosh media] modalRichMedia] setDelegate:self];

    [[Pushwoosh configure] registerForPushNotifications];
    return YES;
}

#pragma mark - PWRichMediaPresentingDelegate

- (BOOL)richMediaManager:(PWRichMediaManager *)richMediaManager shouldPresentRichMedia:(PWRichMedia *)richMedia {
    if (![self.richMediaQueue containsObject:richMedia]) {
        [self.richMediaQueue addObject:richMedia];
    }
    return !self.isPresenting;
}

- (void)richMediaManager:(PWRichMediaManager *)richMediaManager didPresentRichMedia:(PWRichMedia *)richMedia {
    self.isPresenting = YES;
}

- (void)richMediaManager:(PWRichMediaManager *)richMediaManager didCloseRichMedia:(PWRichMedia *)richMedia {
    self.isPresenting = NO;

    [self.richMediaQueue removeObject:richMedia];

    // Present next rich media in queue
    if (self.richMediaQueue.count > 0) {
        [[[Pushwoosh media] modalRichMedia] presentRichMedia:self.richMediaQueue.firstObject];
    }
}

- (void)richMediaManager:(PWRichMediaManager *)richMediaManager presentingDidFailForRichMedia:(PWRichMedia *)richMedia withError:(NSError *)error {
    [self richMediaManager:richMediaManager didCloseRichMedia:richMedia];
}

@end
```
</TabItem>
</Tabs>