# Pushwoosh InboxKit iOS সেট আপ করা

*iOS SDK [7.0.40](https://github.com/Pushwoosh/pushwoosh-ios-sdk/releases/tag/7.0.40) থেকে উপলব্ধ।*

Pushwoosh InboxKit বিদ্যমান ইনবক্স ব্যাকএন্ডের উপরে একটি আধুনিক UIKit ইনবক্স স্ক্রিন সরবরাহ করে। ছয়টি ডিফল্ট সেল লেআউট সাধারণ কন্টেন্ট-কার্ডের আকারগুলিকে কভার করে — সাধারণ ব্যানার থেকে শুরু করে ইমেজ ক্যারোসেল, ইনলাইন ভিডিও, এবং Apple Wallet পাস পর্যন্ত — ইনলাইন CTA বোতামগুলি সবচেয়ে সাধারণ ইন্টারঅ্যাকশনগুলি পরিচালনা করে, এবং যদি আপনার একটি বিশেষ চেহারার প্রয়োজন হয় তবে পুরো সারফেসটি সাবক্লাসিংয়ের জন্য উন্মুক্ত।

<img src="/setting-up-pushwoosh-inboxkit-ios-feed.webp" alt="ইনবক্সকিট ফিড ব্যানার, ক্যাপশনযুক্ত, ক্লাসিক, ক্যারোসেল, ভিডিও এবং অ্যাপল ওয়ালেট কার্ড দেখাচ্ছে" width="300" style="display: block; margin: 0 auto;"/>

<p style="text-align: center; opacity: 0.7; font-size: 0.875rem; margin-top: 0.5rem;">ডিফল্ট ইনবক্সকিট ফিড ব্যানার, ক্যাপশনযুক্ত, ক্লাসিক, ক্যারোসেল, ভিডিও, এবং অ্যাপল ওয়ালেট কার্ড সহ।</p>

## কখন InboxKit ব্যবহার করবেন

যেকোনো নতুন iOS ইন্টিগ্রেশনের জন্য InboxKit ব্যবহার করুন। এটি পুরোনো Objective-C [PushwooshInboxUI](/bn/developer/pushwoosh-sdk/ios-sdk/setting-up-pushwoosh-inboxui-ios/) মডিউলের প্রস্তাবিত প্রতিস্থাপন।

InboxKit আপনাকে দেয়:

- ছয়টি বিল্ট-ইন সেল টাইপ — ব্যানার, ক্যাপশনযুক্ত, ক্লাসিক, ক্যারোসেল, ভিডিও, এবং Apple Wallet — পেলোডের `displayType` এর মাধ্যমে প্রতি মেসেজের জন্য নির্বাচিত, অথবা কোড থেকে `attributes.forceCellKind` এর মাধ্যমে জোর করে সেট করা। সম্পূর্ণ তালিকার জন্য [কার্ডের প্রকারভেদ](#card-types) দেখুন। (Apple Wallet কার্ডটি শুধুমাত্র iOS-এর জন্য।)
- একটি টাইপড `PushwooshInboxButtonAction` enum (`openURL`, `dismiss`, `markRead`, `custom`) সহ ইনলাইন CTA বোতাম। SDK প্রথম তিনটি স্বয়ংক্রিয়ভাবে পরিচালনা করে; আপনার ডেলিগেট `custom` কে আপনার নিজের লজিকে রুট করে।
- পিনিং সাপোর্ট: `actionParams["pinned"] == true` সহ মেসেজগুলি ফিডের শীর্ষে ভাসে এবং একটি পিন গ্লিফ রেন্ডার করে।
- সোয়াইপ-টু-ডিলিট, পুল-টু-রিফ্রেশ, অদৃশ্য হয়ে গেলে স্বয়ংক্রিয়ভাবে পঠিত হিসাবে চিহ্নিত করা — সবই `PushwooshInboxKitAttributes` এর মাধ্যমে টগলযোগ্য।
- পারসিস্টেন্ট স্টোরেজ: নেটওয়ার্ক কল এখনও স্বীকৃত না হলেও ডিলিট এবং পঠিত অবস্থা একটি প্রসেস রিস্টার্টের পরেও টিকে থাকে।
- সম্পূর্ণ কাস্টম লেআউটের জন্য একটি উন্মুক্ত `PushwooshInboxCell` বেস ক্লাস।

সার্ভার চুক্তি অপরিবর্তিত — একই Pushwoosh ইনবক্স ব্যাকএন্ড, পেলোড, এবং ড্যাশবোর্ড টুলিং আগের মতোই কাজ করে।

## আপনার ইন্টিগ্রেশন পদ্ধতি বেছে নিন

- [**সুইফট প্যাকেজ ম্যানেজারের সাথে ইনবক্সকিট সেট আপ করুন**](/bn/developer/pushwoosh-sdk/ios-sdk/setting-up-pushwoosh-inboxkit-ios/set-up-inboxkit-with-swift-package-manager/) — নতুন প্রকল্পের জন্য প্রস্তাবিত।
- [**কোকোপডস দিয়ে ইনবক্সকিট সেট আপ করুন**](/bn/developer/pushwoosh-sdk/ios-sdk/setting-up-pushwoosh-inboxkit-ios/set-up-inboxkit-with-cocoapods/) — ইতিমধ্যে CocoaPods ব্যবহার করা প্রকল্পগুলির জন্য।

## কার্ডের প্রকারভেদ

InboxKit প্রতিটি মেসেজের জন্য একটি সেল লেআউট বেছে নেয়। ডিফল্ট রিজলভার পুশ পেলোড থেকে `displayType` পড়ে — এটি `data` অবজেক্টের ভিতরে রাখুন, যা SDK `actionParams` এর অধীনে সরবরাহ করে। যখন `displayType` অনুপস্থিত থাকে, রিজলভার একটি হিউরিস্টিকের উপর নির্ভর করে: ছবি + কোনো শিরোনাম নেই → ব্যানার, ছবি + শিরোনাম → ক্যাপশনযুক্ত, অন্যথায় ক্লাসিক। কোড থেকে পুরো ফিডের জন্য একটি লেআউট জোর করে সেট করতে, `attributes.forceCellKind` সেট করুন।

প্রতিটি রিচ লেআউট সুন্দরভাবে ডিগ্রেড করে: যদি প্রয়োজনীয় পেলোড অনুপস্থিত বা ত্রুটিপূর্ণ হয়, কার্ডটি একটি খালি স্থানধারক রেন্ডার করার পরিবর্তে `classic`-এ ফিরে আসে (এবং একটি `WARN` লগ করা হয়)।

| `displayType` | লেআউট | প্রয়োজনীয় পেলোড ফিল্ড | ডিগ্রেড হয়ে যায় |
|---|---|---|---|
| `banner` | ফুল-ব্লিড ছবি, কোনো টেক্সট নেই | ছবি (`inbox_image` বা `data.image`) | ছবি না থাকলে `classic` |
| `captioned` | উপরে ছবি, নিচে শিরোনাম + বডি | ছবি (`inbox_image` বা `data.image`) | ছবি না থাকলে `classic` |
| `classic` | রঙিন প্রাথমিক অবতার + শিরোনাম + বডি | — | — |
| `carousel` | সোয়াইপযোগ্য মাল্টি-ইমেজ গ্যালারি | `data.carousel` (স্লাইডের অ্যারে) | স্লাইড না থাকলে `classic` |
| `video` | প্লে ব্যাজ সহ পোস্টার, ট্যাপে ফুল-স্ক্রিন প্লেয়ার | `data.video` (`url` + ঐচ্ছিক `poster`) | বর্ণনাকারী না থাকলে `classic` |
| `wallet` | "Add to Apple Wallet" বোতাম (শুধুমাত্র iOS) | `data.wallet` (`.pkpass` URL) | পাস URL না থাকলে `classic` |

{/* 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="ইনবক্সকিট ব্যানার কার্ড" style="width: 100%; border-radius: 12px;"/><figcaption style="text-align: center; font-size: 0.85rem; color: #94a3b8; margin-top: 0.4rem;"><strong>ব্যানার কার্ড</strong></figcaption></figure>
  <figure style="width: 200px; margin: 0;"><img src="/setting-up-pushwoosh-inboxkit-ios-card-captioned.webp" alt="ইনবক্সকিট ক্যাপশনযুক্ত কার্ড" style="width: 100%; border-radius: 12px;"/><figcaption style="text-align: center; font-size: 0.85rem; color: #94a3b8; margin-top: 0.4rem;"><strong>ক্যাপশনযুক্ত কার্ড</strong></figcaption></figure>
  <figure style="width: 200px; margin: 0;"><img src="/setting-up-pushwoosh-inboxkit-ios-card-classic.webp" alt="ইনবক্সকিট ক্লাসিক কার্ড" style="width: 100%; border-radius: 12px;"/><figcaption style="text-align: center; font-size: 0.85rem; color: #94a3b8; margin-top: 0.4rem;"><strong>ক্লাসিক কার্ড</strong></figcaption></figure>
  <figure style="width: 200px; margin: 0;"><img src="/setting-up-pushwoosh-inboxkit-ios-card-carousel.webp" alt="ইনবক্সকিট ক্যারোসেল কার্ড" style="width: 100%; border-radius: 12px;"/><figcaption style="text-align: center; font-size: 0.85rem; color: #94a3b8; margin-top: 0.4rem;"><strong>ক্যারোসেল কার্ড</strong></figcaption></figure>
  <figure style="width: 200px; margin: 0;"><img src="/setting-up-pushwoosh-inboxkit-ios-card-video.webp" alt="ইনবক্সকিট ভিডিও কার্ড" style="width: 100%; border-radius: 12px;"/><figcaption style="text-align: center; font-size: 0.85rem; color: #94a3b8; margin-top: 0.4rem;"><strong>ভিডিও কার্ড</strong></figcaption></figure>
  <figure style="width: 200px; margin: 0;"><img src="/setting-up-pushwoosh-inboxkit-ios-card-wallet.webp" alt="ইনবক্সকিট অ্যাপল ওয়ালেট কার্ড" style="width: 100%; border-radius: 12px;"/><figcaption style="text-align: center; font-size: 0.85rem; color: #94a3b8; margin-top: 0.4rem;"><strong>Apple Wallet কার্ড</strong></figcaption></figure>
</div>

ব্যানার, ক্যাপশনযুক্ত, এবং ক্লাসিক কার্ডগুলি স্ট্যান্ডার্ড মেসেজ ফিল্ড (ছবি, শিরোনাম, বডি) এবং ঐচ্ছিক `buttons` অ্যারে দ্বারা চালিত হয় — [ইনলাইন CTA বোতাম যোগ করুন](#add-inline-cta-buttons) দেখুন। ক্যারোসেল, ভিডিও, এবং Apple Wallet কার্ডগুলি `data`-এর ভিতরে অতিরিক্ত স্ট্রাকচার্ড ডেটা বহন করে, যা নিচে নথিভুক্ত করা হয়েছে।

### ক্যারোসেল কার্ড

একটি ক্যারোসেল একটি একক বার্তা থেকে বেশ কয়েকটি ছবি রেন্ডার করে — একটি সোয়াইপযোগ্য গ্যালারি যেখানে প্রতি-স্লাইড ক্যাপশন এবং ট্যাপ করার গন্তব্য ঐচ্ছিক। স্লাইডগুলি `data.carousel`-এ থাকে। প্রতিটি স্লাইডের জন্য একটি `image` প্রয়োজন; `title` (ক্যাপশন ওভারলে) এবং `url` (ট্যাপ করলে খোলা ডিপ লিঙ্ক) ঐচ্ছিক। ছবি ছাড়া একটি স্লাইড বাদ দেওয়া হয়; `url` ছাড়া একটি স্লাইডে ট্যাপ করলে বার্তার ডিফল্ট রো অ্যাকশনে চলে যায়।

```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]
    }]
  }
}
```

### ভিডিও কার্ড

একটি ভিডিও কার্ড একটি প্লে ব্যাজ সহ একটি পোস্টার ছবি দেখায়; এটিতে ট্যাপ করলে একটি পূর্ণ-স্ক্রীন প্লেয়ার খোলে (সাইলেন্ট সুইচ চালু থাকলেও শব্দ সহ)। বর্ণনাকারী `data.video`-তে থাকে: `url` প্রয়োজনীয় এবং এটি একটি `http`/`https` স্ট্রিম বা ফাইল হতে হবে; `poster` একটি ঐচ্ছিক প্রিভিউ ছবি।

```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 কার্ড

Apple Wallet কার্ডটি অফিসিয়াল **Add to Apple Wallet** বোতামের উপরে একটি ঐচ্ছিক হিরো ছবি, শিরোনাম এবং বডি দেখায়। বোতামটি ট্যাপ করলে `.pkpass` ডাউনলোড হয় এবং সিস্টেম অ্যাড-পাস শীট উপস্থাপন করে। এটি ইনবক্স থেকে সরাসরি কুপন, লয়ালটি কার্ড, টিকিট বা বোর্ডিং পাস সরবরাহ করতে ব্যবহার করুন। কার্ডটি শুধুমাত্র iOS / Mac Catalyst-এর জন্য — অন্যান্য প্ল্যাটফর্মে বার্তাটি একটি ক্লাসিক কার্ড হিসাবে রেন্ডার হয়।

পাস URL `data.wallet`-এ থাকে, হয় একটি বেয়ার স্ট্রিং হিসাবে অথবা `pass` ফিল্ড সহ একটি অবজেক্ট হিসাবে। একটি ঐচ্ছিক `data.image` হিরো ছবি যোগ করে। যখন কোনো পাস URL না থাকে বা ডিভাইস পাস যোগ করতে পারে না তখন বোতামটি স্বয়ংক্রিয়ভাবে নিজেকে লুকিয়ে রাখে।

```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]
    }]
  }
}
```

ফলাফল আপনার ডেলিগেটের কাছে রিপোর্ট করা হয়:

```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.
    }
}
```

উভয় কলব্যাকই ঐচ্ছিক (এগুলিতে ডিফল্ট খালি ইমপ্লিমেন্টেশন রয়েছে)। একজন ব্যবহারকারী সিস্টেম শীট বাতিল করলে তা সাফল্য বা ব্যর্থতা কোনোটিই নয়, তাই সেক্ষেত্রে কোনো কলব্যাক ফায়ার হয় না।

## অ্যাক্সেসিবিলিটি

InboxKit সেলগুলি বক্সের বাইরেই VoiceOver-প্রস্তুত। ব্যানার, ক্যাপশনযুক্ত এবং ক্লাসিক কার্ডগুলি তাদের শিরোনাম, বডি এবং তারিখ অন্তর্নিহিত লেবেলের মাধ্যমে প্রকাশ করে এবং ইনলাইন CTA বোতামগুলি তাদের নিজস্ব শিরোনাম পড়ে। রিচ কার্ডগুলি স্পষ্ট শব্দার্থ যোগ করে:

- **ভিডিও** — পোস্টারটি "Play video" লেবেলযুক্ত একটি একক বোতাম উপাদান হিসাবে প্রকাশ করা হয় (বৈশিষ্ট্য `.button` + `.startsMediaSession`), তাই VoiceOver এটিকে একটি সাধারণ ছবির পরিবর্তে একটি মিডিয়া নিয়ন্ত্রণ হিসাবে ঘোষণা করে।
- **ক্যারোসেল** — প্রতিটি স্লাইড একটি বোতাম উপাদান যার অ্যাক্সেসিবিলিটি লেবেল হল স্লাইডের ক্যাপশন, অথবা যখন কোনো ক্যাপশন না থাকে তখন "Slide"। পেজ ইন্ডিকেটর বর্তমান অবস্থানকে "*total*-এর মধ্যে *n*" হিসাবে ঘোষণা করে।
- **Apple Wallet** — **Add to Apple Wallet** বোতামটি Apple-এর স্ট্যান্ডার্ড `PKAddPassButton`, যা তার নিজস্ব স্থানীয়কৃত VoiceOver লেবেল বহন করে।

UI টেস্টিং এবং অটোমেশনের জন্য, দুটি স্থিতিশীল `accessibilityIdentifier` সেট করা আছে: ভিডিও পোস্টারে `inboxkit.video.play` এবং Wallet বোতামে `inboxkit.wallet.add`।

## একটি বার্তা থেকে কাস্টম ডেটা পড়ুন

একটি পুশকে ইনবক্সে উপস্থিত করতে, [Messages API](/bn/developer/api-reference/messages-api/) `createMessage` অনুরোধে অবশ্যই `inbox_image`, `inbox_date`, বা `inbox_days` অন্তর্ভুক্ত থাকতে হবে — এই ক্ষেত্রগুলির একটি ছাড়া পুশটি একটি নিয়মিত বিজ্ঞপ্তি হিসাবে বিতরণ করা হয় এবং ইনবক্স ফিডে পৌঁছায় না। ফ্রি-ফর্ম কাস্টম ডেটা `data` কী-এর অধীনে যায়, যা SDK ক্লায়েন্টকে `u` প্যারামিটার হিসাবে সরবরাহ করে:

```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]
    }]
  }
}
```

SDK সেই অবজেক্টটি ইনবক্স মেসেজে `actionParams`-এর মাধ্যমে প্রকাশ করে। ব্যবহারকারী যখন সারি বা একটি ইনলাইন CTA ট্যাপ করে তখন ডেলিগেট থেকে এটি পড়ুন:

```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
    }
}
```

একই `actionParams["u"]` লুকআপ ইনলাইন CTA বোতামগুলির জন্য `inboxKit(_:didTapButton:onMessage:)`-এর ভিতরে কাজ করে। টাইপড CTA কেসগুলির জন্য (`openURL`, `dismiss`, `markRead`) SDK ইতিমধ্যে ডিফল্ট অ্যাকশন সম্পাদন করে — সেই আচরণটি রাখতে `true` রিটার্ন করুন, অথবা এটিকে দমন করতে এবং আপনার নিজেরটি চালাতে `false` রিটার্ন করুন।

## ইনলাইন CTA বোতাম যোগ করুন

একটি বার্তায় তিনটি পর্যন্ত ইনলাইন কল-টু-অ্যাকশন বোতাম থাকতে পারে। বোতামগুলি `data`-এর ভিতরে অন্যান্য কাস্টম ডেটার পাশাপাশি একটি `buttons` অ্যারে হিসাবে থাকে। SDK স্বয়ংক্রিয়ভাবে সেগুলিকে ক্যাপশনযুক্ত এবং ক্লাসিক সেলের ভিতরে রেন্ডার করে:

```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]
    }]
  }
}
```

প্রতিটি বোতাম অবজেক্টের এই ক্ষেত্রগুলি রয়েছে:

| ফিল্ড | টাইপ | কখন |
|---|---|---|
| `title` | string | প্রয়োজনীয়। দৃশ্যমান বোতাম লেবেল। |
| `url` | string | একটি খালি নয় এমন পার্সযোগ্য URL একটি `openURL` অ্যাকশন তৈরি করে। আপনার ডেলিগেট এটি দমন না করলে SDK এটি `UIApplication.shared.open` এর মাধ্যমে খোলে। |
| `action` | string | স্পষ্ট অ্যাকশন টোকেন: `dismiss` (ফিড থেকে বার্তাটি সরিয়ে দেয়), `markRead` (বার্তাটি পঠিত হিসাবে চিহ্নিত করে), বা `custom` (হোস্ট-হ্যান্ডেলড)। কেস-ইনসেনসিটিভ। |
| অন্য কিছু | any | যখন `action` `custom` হয়, তখন বোতাম অবজেক্টের `title` এবং `action` ছাড়া প্রতিটি কী আপনার ডেলিগেটের কাছে কাস্টম পেলোড হিসাবে ফরোয়ার্ড করা হয় — বিপণনকারীর সাথে একটি কী-তে সম্মত হন (যেমন `tag`) এবং সেটির উপর ভিত্তি করে ডিসপ্যাচ করুন। |

রেজোলিউশন অগ্রাধিকার: প্রথমে স্পষ্ট `action` টোকেন, তারপর `url` যদি খালি না থাকে, অন্যথায় বোতামটি `custom`-এ পড়ে যায় এবং সম্পূর্ণ পেলোড বহন করে (`title` এবং `action` ছাড়া)।

আপনার ডেলিগেট থেকে ট্যাপগুলি ইন্টারসেপ্ট করুন। `button.action` প্রপার্টিটি হল টাইপড `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
        }
    }
}
```