# Pushwoosh InboxKit für iOS einrichten

*Verfügbar seit iOS SDK [7.0.40](https://github.com/Pushwoosh/pushwoosh-ios-sdk/releases/tag/7.0.40).*

Pushwoosh InboxKit liefert einen modernen UIKit-Posteingangsbildschirm zusätzlich zum bestehenden Posteingangs-Backend. Sechs Standard-Zellenlayouts decken die gängigen Content-Card-Formen ab – von einfachen Bannern über Bilderkarussells, Inline-Videos und Apple Wallet-Pässe – Inline-CTA-Schaltflächen handhaben die häufigsten Interaktionen, und die gesamte Oberfläche ist offen für Subclassing, falls Sie ein maßgeschneidertes Aussehen benötigen.

<img src="/setting-up-pushwoosh-inboxkit-ios-feed.webp" alt="InboxKit-Feed mit Banner-, Untertitel-, Klassik-, Karussell-, Video- und Apple Wallet-Karten" width="300" style="display: block; margin: 0 auto;"/>

<p style="text-align: center; opacity: 0.7; font-size: 0.875rem; margin-top: 0.5rem;">Standard-InboxKit-Feed mit Banner-, Untertitel-, Klassik-, Karussell-, Video- und Apple Wallet-Karten.</p>

## Wann sollte man InboxKit verwenden?

Verwenden Sie InboxKit für jede neue iOS-Integration. Es ist der empfohlene Ersatz für das ältere Objective-C [PushwooshInboxUI](/de/developer/pushwoosh-sdk/ios-sdk/setting-up-pushwoosh-inboxui-ios/) Modul.

InboxKit bietet Ihnen:

- Sechs integrierte Zelltypen – Banner, Untertitel, Klassik, Karussell, Video und Apple Wallet – die pro Nachricht über den `displayType` des Payloads ausgewählt oder per Code über `attributes.forceCellKind` erzwungen werden. Eine vollständige Liste finden Sie unter [Kartentypen](#card-types). (Die Apple Wallet-Karte ist nur für iOS verfügbar.)
- Inline-CTA-Schaltflächen mit einer typisierten `PushwooshInboxButtonAction` Enum (`openURL`, `dismiss`, `markRead`, `custom`). Das SDK behandelt die ersten drei automatisch; Ihr Delegate leitet `custom` an Ihre eigene Logik weiter.
- Anpinn-Unterstützung: Nachrichten mit `actionParams["pinned"] == true` schweben an den Anfang des Feeds und rendern ein Anpinn-Symbol.
- Wischen zum Löschen, Ziehen zum Aktualisieren, automatisches Als-gelesen-Markieren beim Verschwinden – alles umschaltbar über `PushwooshInboxKitAttributes`.
- Persistenter Speicher: Löschungen und Gelesen-Status überleben einen Prozessneustart, auch wenn der Netzwerkaufruf noch nicht bestätigt wurde.
- Eine offene `PushwooshInboxCell` Basisklasse für vollständig benutzerdefinierte Layouts.

Der Serververtrag bleibt unverändert – dasselbe Pushwoosh-Posteingangs-Backend, Payloads und Dashboard-Tools funktionieren wie zuvor.

## Wählen Sie Ihre Integrationsmethode

- [**InboxKit mit Swift Package Manager einrichten**](/de/developer/pushwoosh-sdk/ios-sdk/setting-up-pushwoosh-inboxkit-ios/set-up-inboxkit-with-swift-package-manager/) – empfohlen für neue Projekte.
- [**InboxKit mit CocoaPods einrichten**](/de/developer/pushwoosh-sdk/ios-sdk/setting-up-pushwoosh-inboxkit-ios/set-up-inboxkit-with-cocoapods/) – für Projekte, die bereits CocoaPods verwenden.

## Kartentypen

InboxKit wählt pro Nachricht ein Zellenlayout aus. Der Standard-Resolver liest `displayType` aus dem Push-Payload – platzieren Sie es im `data`-Objekt, das das SDK unter `actionParams` liefert. Wenn `displayType` fehlt, greift der Resolver auf eine Heuristik zurück: Bild + kein Titel → Banner, Bild + Titel → Untertitel, ansonsten Klassik. Um ein Layout für den gesamten Feed per Code zu erzwingen, setzen Sie `attributes.forceCellKind`.

Jedes Rich-Layout degradiert anmutig: Wenn der erforderliche Payload fehlt oder fehlerhaft ist, fällt die Karte auf `classic` zurück, anstatt einen leeren Platzhalter zu rendern (und ein `WARN` wird protokolliert).

| `displayType` | Layout | Erforderliches Payload-Feld | Fällt zurück auf |
|---|---|---|---|
| `banner` | Bild ohne Rand, kein Text | Bild (`inbox_image` oder `data.image`) | `classic` wenn kein Bild |
| `captioned` | Bild oben, Titel + Text unten | Bild (`inbox_image` oder `data.image`) | `classic` wenn kein Bild |
| `classic` | Farbiger Initial-Avatar + Titel + Text | — | — |
| `carousel` | Wischbare Galerie mit mehreren Bildern | `data.carousel` (Array von Folien) | `classic` wenn keine Folien |
| `video` | Poster mit Play-Badge, Vollbild-Player bei Tippen | `data.video` (`url` + optional `poster`) | `classic` wenn kein Deskriptor |
| `wallet` | "Zu Apple Wallet hinzufügen"-Schaltfläche (nur iOS) | `data.wallet` (`.pkpass` URL) | `classic` wenn keine Pass-URL |

{/* TODO(screenshot): replace each placeholder below with a per-card screenshot. Suggested filenames: setting-up-pushwoosh-inboxkit-ios-card-banner.webp, -captioned.webp, -classic.webp, -carousel.webp, -video.webp, -wallet.webp — then swap each <div> for an <img src="/<filename>" width="240" .../>. */}
<div style="display: flex; flex-wrap: wrap; gap: 1rem; justify-content: center; margin: 1.5rem 0;">
  <figure style="width: 200px; margin: 0;"><img src="/setting-up-pushwoosh-inboxkit-ios-card-banner.webp" alt="InboxKit Banner-Karte" style="width: 100%; border-radius: 12px;"/><figcaption style="text-align: center; font-size: 0.85rem; color: #94a3b8; margin-top: 0.4rem;"><strong>Banner-Karte</strong></figcaption></figure>
  <figure style="width: 200px; margin: 0;"><img src="/setting-up-pushwoosh-inboxkit-ios-card-captioned.webp" alt="InboxKit Untertitel-Karte" style="width: 100%; border-radius: 12px;"/><figcaption style="text-align: center; font-size: 0.85rem; color: #94a3b8; margin-top: 0.4rem;"><strong>Untertitel-Karte</strong></figcaption></figure>
  <figure style="width: 200px; margin: 0;"><img src="/setting-up-pushwoosh-inboxkit-ios-card-classic.webp" alt="InboxKit Klassik-Karte" style="width: 100%; border-radius: 12px;"/><figcaption style="text-align: center; font-size: 0.85rem; color: #94a3b8; margin-top: 0.4rem;"><strong>Klassik-Karte</strong></figcaption></figure>
  <figure style="width: 200px; margin: 0;"><img src="/setting-up-pushwoosh-inboxkit-ios-card-carousel.webp" alt="InboxKit Karussell-Karte" style="width: 100%; border-radius: 12px;"/><figcaption style="text-align: center; font-size: 0.85rem; color: #94a3b8; margin-top: 0.4rem;"><strong>Karussell-Karte</strong></figcaption></figure>
  <figure style="width: 200px; margin: 0;"><img src="/setting-up-pushwoosh-inboxkit-ios-card-video.webp" alt="InboxKit Video-Karte" style="width: 100%; border-radius: 12px;"/><figcaption style="text-align: center; font-size: 0.85rem; color: #94a3b8; margin-top: 0.4rem;"><strong>Video-Karte</strong></figcaption></figure>
  <figure style="width: 200px; margin: 0;"><img src="/setting-up-pushwoosh-inboxkit-ios-card-wallet.webp" alt="InboxKit Apple Wallet-Karte" style="width: 100%; border-radius: 12px;"/><figcaption style="text-align: center; font-size: 0.85rem; color: #94a3b8; margin-top: 0.4rem;"><strong>Apple Wallet-Karte</strong></figcaption></figure>
</div>

Banner-, Untertitel- und Klassik-Karten werden durch die Standard-Nachrichtenfelder (Bild, Titel, Text) sowie das optionale `buttons`-Array gesteuert – siehe [Inline-CTA-Schaltflächen hinzufügen](#add-inline-cta-buttons). Die Karussell-, Video- und Apple Wallet-Karten enthalten zusätzliche strukturierte Daten in `data`, die unten dokumentiert sind.

### Karussell-Karte

Ein Karussell rendert mehrere Bilder aus einer einzigen Nachricht – eine wischbare Galerie mit optionalen Bildunterschriften pro Folie und Zielen beim Tippen. Die Folien befinden sich in `data.carousel`. Jede Folie benötigt ein `image`; `title` (Untertitel-Overlay) und `url` (Deep Link, der beim Tippen geöffnet wird) sind optional. Eine Folie ohne Bild wird verworfen; ein Tippen auf eine Folie ohne `url` fällt auf die Standard-Zeilenaktion der Nachricht zurück.

```json title="POST https://api.pushwoosh.com/json/1.3/createMessage"
{
  "request": {
    "application": "XXXXX-XXXXX",
    "auth": "API_TOKEN",
    "notifications": [{
      "send_date": "now",
      "ios_title": "New arrivals",
      "content": "Swipe through this week's drops",
      "inbox_days": 7,
      "data": {
        "displayType": "carousel",
        "carousel": [
          { "image": "https://cdn.example.com/inbox/1.jpg", "title": "New in", "url": "myapp://product/1" },
          { "image": "https://cdn.example.com/inbox/2.jpg", "title": "On sale", "url": "myapp://product/2" },
          { "image": "https://cdn.example.com/inbox/3.jpg" }
        ]
      },
      "platforms": [1]
    }]
  }
}
```

### Video-Karte

Eine Video-Karte zeigt ein Posterbild mit einem Play-Badge; ein Tippen darauf öffnet einen Vollbild-Player (Ton an, auch bei aktiviertem Stummschalter). Der Deskriptor befindet sich in `data.video`: `url` ist erforderlich und muss ein `http`/`https`-Stream oder eine Datei sein; `poster` ist ein optionales Vorschaubild.

```json title="POST https://api.pushwoosh.com/json/1.3/createMessage"
{
  "request": {
    "application": "XXXXX-XXXXX",
    "auth": "API_TOKEN",
    "notifications": [{
      "send_date": "now",
      "ios_title": "Watch the reveal",
      "content": "Tap to play",
      "inbox_days": 7,
      "data": {
        "displayType": "video",
        "video": {
          "url": "https://cdn.example.com/inbox/clip.mp4",
          "poster": "https://cdn.example.com/inbox/poster.jpg"
        }
      },
      "platforms": [1]
    }]
  }
}
```

### Apple Wallet-Karte

Die Apple Wallet-Karte zeigt ein optionales Hero-Bild, einen Titel und einen Text über der offiziellen **Zu Apple Wallet hinzufügen**-Schaltfläche. Ein Tippen auf die Schaltfläche lädt die `.pkpass`-Datei herunter und präsentiert das Systemblatt zum Hinzufügen von Pässen. Verwenden Sie es, um Gutscheine, Kundenkarten, Tickets oder Bordkarten direkt aus dem Posteingang zu liefern. Die Karte ist nur für iOS / Mac Catalyst verfügbar – auf anderen Plattformen wird die Nachricht als Klassik-Karte gerendert.

Die Pass-URL befindet sich in `data.wallet`, entweder als reiner String oder als Objekt mit einem `pass`-Feld. Ein optionales `data.image` fügt das Hero-Bild hinzu. Die Schaltfläche blendet sich automatisch aus, wenn keine Pass-URL vorhanden ist oder das Gerät keine Pässe hinzufügen kann.

```json title="POST https://api.pushwoosh.com/json/1.3/createMessage"
{
  "request": {
    "application": "XXXXX-XXXXX",
    "auth": "API_TOKEN",
    "notifications": [{
      "send_date": "now",
      "ios_title": "Your loyalty card is ready",
      "content": "Add it to Apple Wallet in one tap",
      "inbox_days": 7,
      "data": {
        "displayType": "wallet",
        "image": "https://cdn.example.com/inbox/loyalty.png",
        "wallet": "https://passes.example.com/v1/passes/pass.com.example.loyalty/abc123?token=…"
      },
      "platforms": [1]
    }]
  }
}
```

Das Ergebnis wird an Ihren Delegate gemeldet:

```swift
extension MyInboxHost: PushwooshInboxKitDelegate {

    func inboxKit(_ vc: PushwooshInboxKitViewController,
                  didAddWalletPassFor message: PWInboxMessageProtocol) {
        // The pass is now in the user's Wallet — show a confirmation if you like.
    }

    func inboxKit(_ vc: PushwooshInboxKitViewController,
                  didFailToAddWalletPassFor message: PWInboxMessageProtocol,
                  error: Error?) {
        // Download failed — surface a retry, log, etc.
    }
}
```

Beide Callbacks sind optional (sie haben standardmäßig leere Implementierungen). Wenn ein Benutzer das Systemblatt abbricht, ist dies weder ein Erfolg noch ein Fehlschlag, daher wird in diesem Fall kein Callback ausgelöst.

## Barrierefreiheit

InboxKit-Zellen sind von Haus aus VoiceOver-fähig. Banner-, Untertitel- und Klassik-Karten stellen ihren Titel, Text und ihr Datum über die zugrunde liegenden Labels zur Verfügung, und Inline-CTA-Schaltflächen lesen ihre eigenen Titel vor. Die Rich-Karten fügen explizite Semantik hinzu:

- **Video** – das Poster wird als einzelnes Schaltflächenelement mit der Bezeichnung "Video abspielen" (Eigenschaften `.button` + `.startsMediaSession`) bereitgestellt, sodass VoiceOver es als Mediensteuerung anstelle eines einfachen Bildes ankündigt.
- **Karussell** – jede Folie ist ein Schaltflächenelement, dessen Barrierefreiheits-Label die Bildunterschrift der Folie ist, oder "Folie", wenn keine vorhanden ist. Der Seitenindikator gibt die aktuelle Position als "*n* von *gesamt*" an.
- **Apple Wallet** – die **Zu Apple Wallet hinzufügen**-Schaltfläche ist Apples Standard-`PKAddPassButton`, der sein eigenes lokalisiertes VoiceOver-Label trägt.

Für UI-Tests und Automatisierung sind zwei stabile `accessibilityIdentifier` gesetzt: `inboxkit.video.play` auf dem Video-Poster und `inboxkit.wallet.add` auf der Wallet-Schaltfläche.

## Benutzerdefinierte Daten aus einer Nachricht lesen

Damit ein Push im Posteingang erscheint, muss die [Messages API](/de/developer/api-reference/messages-api/) `createMessage`-Anfrage `inbox_image`, `inbox_date` oder `inbox_days` enthalten – ohne eines dieser Felder wird der Push als reguläre Benachrichtigung zugestellt und erreicht niemals den Posteingangs-Feed. Freiform-benutzerdefinierte Daten gehören unter den `data`-Schlüssel, den das SDK als `u`-Parameter an den Client liefert:

```json title="POST https://api.pushwoosh.com/json/1.3/createMessage"
{
  "request": {
    "application": "XXXXX-XXXXX",
    "auth": "API_TOKEN",
    "notifications": [{
      "send_date": "now",
      "ios_title": "Summer sale",
      "content": "30% off everything — limited time only",
      "inbox_image": "https://cdn.example.com/inbox/summer.png",
      "inbox_days": 7,
      "data": {
        "displayType": "captioned",
        "promo_id": "SUMMER2026",
        "screen": "promo_details"
      },
      "platforms": [1]
    }]
  }
}
```

Das SDK stellt dieses Objekt in der Posteingangsnachricht über `actionParams` zur Verfügung. Lesen Sie es aus dem Delegate, wenn der Benutzer auf die Zeile oder einen Inline-CTA tippt:

```swift
extension MyInboxHost: PushwooshInboxKitDelegate {

    func inboxKit(_ vc: PushwooshInboxKitViewController,
                  didSelect message: PWInboxMessageProtocol) -> Bool {
        guard let params = message.actionParams as? [String: Any] else { return true }

        // The custom `data` object arrives under the "u" key —
        // either as a nested dictionary or as a JSON-encoded string,
        // depending on how the payload was built upstream.
        let custom: [String: Any]? = {
            if let dict = params["u"] as? [String: Any] { return dict }
            if let raw = params["u"] as? String,
               let bytes = raw.data(using: .utf8),
               let parsed = try? JSONSerialization.jsonObject(with: bytes) as? [String: Any] {
                return parsed
            }
            return nil
        }()

        if let promoId = custom?["promo_id"] as? String {
            navigateToPromo(promoId)
            return false   // we handled the tap; SDK should not run the default action
        }
        return true
    }
}
```

Dieselbe `actionParams["u"]`-Suche funktioniert in `inboxKit(_:didTapButton:onMessage:)` für Inline-CTA-Schaltflächen. Für die typisierten CTA-Fälle (`openURL`, `dismiss`, `markRead`) führt das SDK bereits die Standardaktion aus – geben Sie `true` zurück, um dieses Verhalten beizubehalten, oder `false`, um es zu unterdrücken und Ihre eigene auszuführen.

## Inline-CTA-Schaltflächen hinzufügen

Eine Nachricht kann bis zu drei Inline-Call-to-Action-Schaltflächen enthalten. Schaltflächen befinden sich zusammen mit anderen benutzerdefinierten Daten in `data` als `buttons`-Array. Das SDK rendert sie automatisch in den Untertitel- und Klassik-Zellen:

```json title="POST https://api.pushwoosh.com/json/1.3/createMessage"
{
  "request": {
    "application": "XXXXX-XXXXX",
    "auth": "API_TOKEN",
    "notifications": [{
      "send_date": "now",
      "ios_title": "New promo card",
      "content": "Tap a button to claim or save",
      "inbox_image": "https://cdn.example.com/inbox/promo.png",
      "inbox_days": 7,
      "data": {
        "displayType": "captioned",
        "promo_id": "SUMMER2026",
        "buttons": [
          { "title": "Claim", "url": "https://example.com/promo/SUMMER2026" },
          { "title": "Read",  "action": "markRead" },
          { "title": "Save",  "action": "custom", "tag": "save_promo" }
        ]
      },
      "platforms": [1]
    }]
  }
}
```

Jedes Schaltflächenobjekt hat diese Felder:

| Feld | Typ | Wann |
|---|---|---|
| `title` | string | Erforderlich. Sichtbares Schaltflächen-Label. |
| `url` | string | Eine nicht leere, parsable URL erzeugt eine `openURL`-Aktion. Das SDK öffnet sie über `UIApplication.shared.open`, es sei denn, Ihr Delegate unterdrückt dies. |
| `action` | string | Explizites Aktions-Token: `dismiss` (entfernt die Nachricht aus dem Feed), `markRead` (markiert die Nachricht als gelesen) oder `custom` (vom Host behandelt). Groß-/Kleinschreibung wird nicht beachtet. |
| Alles andere | any | Wenn `action` `custom` ist, wird jeder Schlüssel im Schaltflächenobjekt außer `title` und `action` als benutzerdefinierter Payload an Ihren Delegate weitergeleitet – einigen Sie sich mit dem Marketer auf einen Schlüssel (z. B. `tag`) und führen Sie eine Verzweigung darauf aus. |

Auflösungspriorität: zuerst das explizite `action`-Token, dann `url`, wenn nicht leer, andernfalls fällt die Schaltfläche in `custom` und trägt den vollständigen Payload (ohne `title` und `action`).

Fangen Sie Taps von Ihrem Delegate ab. Die `button.action`-Eigenschaft ist die typisierte `PushwooshInboxButtonAction`-Enum:

```swift
extension MyInboxHost: PushwooshInboxKitDelegate {

    func inboxKit(_ vc: PushwooshInboxKitViewController,
                  didTapButton button: PushwooshInboxButton,
                  onMessage message: PWInboxMessageProtocol) -> Bool {
        switch button.action {
        case .openURL(let url):
            // Default behavior is fine — let SDK open the URL.
            return true

        case .dismiss, .markRead:
            // SDK handles both. Return false if you want to override.
            return true

        case .custom(let payload):
            // Marketer-defined custom button. Dispatch on a key you agreed on.
            if let tag = payload["tag"] as? String {
                switch tag {
                case "save_promo":
                    saveCurrentPromoLocally(message: message)
                default:
                    break
                }
            }
            return true   // ignored for custom — SDK never runs a default action here
        }
    }
}
```