# iOS পুশ স্টোরিজ

পুশ স্টোরিজ একটি প্রসারিত পুশ নোটিফিকেশনকে একটি ফুল-স্ক্রিন, ইনস্টাগ্রাম-স্টাইলের স্টোরিজের অভিজ্ঞতায় পরিণত করে: ফুল-ব্লিড ছবি, উপরে অগ্রগতি বার, স্বয়ংক্রিয়ভাবে এগিয়ে যাওয়া পৃষ্ঠা, নেভিগেট করতে ট্যাপ, এবং একটি ডিপ লিঙ্ক সহ একটি বোতাম। এগুলি একটি স্বতন্ত্র `PushwooshNotificationUI` মডিউল ব্যবহার করে একটি Notification Content Extension দ্বারা রেন্ডার করা হয় — আপনি একটি ভিউ কন্ট্রোলারকে সাবক্লাস করেন এবং SDK পার্সিং, ইমেজ লোডিং, অগ্রগতি, টাইমিং, নেভিগেশন এবং ডিপ লিঙ্কগুলি পরিচালনা করে।

সংস্করণ 7.0.46 থেকে উপলব্ধ।

<img src="/ios-push-stories-demo.webp" alt="একটি প্রসারিত নোটিফিকেশনে পুশ স্টোরিজ চলছে"/>

## ১. একটি Notification Content Extension যোগ করুন

Xcode-এ, **File > New > Target…** বেছে নিন, **Notification Content Extension** নির্বাচন করুন, এবং এর একটি নাম দিন (উদাহরণস্বরূপ **StoriesContentExtension**)।

<img src="/ios-push-stories-1.webp" alt="Xcode-এ একটি Notification Content Extension টার্গেট যোগ করা হচ্ছে"/>

## ২. PushwooshNotificationUI মডিউল যোগ করুন

`PushwooshNotificationUI` একটি স্বতন্ত্র মডিউল যার অন্য কোনো Pushwoosh নির্ভরতা নেই, তাই এটি এক্সটেনশন প্রক্রিয়ার মধ্যে ছোট থাকে। এটি **কন্টেন্ট এক্সটেনশন টার্গেটে** যোগ করুন (অ্যাপ টার্গেটে নয়)।

**Swift Package Manager**

<img src="/ios-push-stories-spm.webp" alt="এক্সটেনশন টার্গেটে PushwooshNotificationUI প্যাকেজ যোগ করা হচ্ছে"/>

**CocoaPods**

```ruby
target 'StoriesContentExtension' do
  use_frameworks!

  pod 'PushwooshXCFramework/PushwooshNotificationUI'
end
```

## ৩. স্টোরিজ ভিউ কন্ট্রোলারকে সাবক্লাস করুন

জেনারেট করা `NotificationViewController` বডিকে `PushwooshStoriesViewController`-এর একটি সাবক্লাস দিয়ে প্রতিস্থাপন করুন। এটাই সম্পূর্ণ ইন্টিগ্রেশন।

<Tabs>
<TabItem label="Swift">
```swift
import PushwooshNotificationUI

class NotificationViewController: PushwooshStoriesViewController {}
```
</TabItem>
</Tabs>

## ৪. এক্সটেনশন Info.plist কনফিগার করুন

কন্টেন্ট এক্সটেনশনের **Info.plist**-এ, `NSExtension > NSExtensionAttributes`-এর অধীনে নিম্নলিখিত কীগুলি সেট করুন:

```xml
<key>UNNotificationExtensionCategory</key>
<string>PW_STORIES</string>
<key>UNNotificationExtensionUserInteractionEnabled</key>
<true/>
<key>UNNotificationExtensionDefaultContentHidden</key>
<true/>
<key>UNNotificationExtensionInitialContentSizeRatio</key>
<real>1.5</real>
```

<Aside type="note">
`UNNotificationExtensionCategory` অবশ্যই পুশে পাঠানো ক্যাটাগরির সাথে মিলতে হবে (`PW_STORIES`)। `UNNotificationExtensionInitialContentSizeRatio` প্রসারিত ভিউয়ের প্রাথমিক উচ্চতার অনুপাত সেট করে।
</Aside>

## ৫. একটি পুশ স্টোরিজ নোটিফিকেশন পাঠান

এমন একটি নোটিফিকেশন পাঠান যার ক্যাটাগরি `PW_STORIES` এবং যার কাস্টম ডেটাতে একটি `pw_stories` ব্লক রয়েছে। ক্যাটাগরির জন্য নির্দিষ্ট `ios_category_custom` ফিল্ড এবং স্টোরিজ পেলোডের জন্য `data` ফিল্ড ব্যবহার করুন।

```json
{
  "request": {
    "application": "APPLICATION_CODE",
    "auth": "API_ACCESS_TOKEN",
    "notifications": [
      {
        "send_date": "now",
        "content": "Tap to explore",
        "ios_title": "Push Stories",
        "ios_category_custom": "PW_STORIES",
        "ios_root_params": {
          "aps": {
            "mutable-content": 1
          }
        },
        "data": {
          "pw_stories": {
            "pages": [
              {
                "image": "https://example.com/story-1.jpg",
                "duration": 5.0,
                "link": "yourapp://page1",
                "button_title": "Get started",
                "title": "Welcome",
                "subtitle": "Swipe to explore what's new"
              },
              {
                "image": "https://example.com/story-2.jpg",
                "duration": 4.0,
                "link": "yourapp://page2",
                "button_title": "Learn more",
                "title": "Stay in the loop",
                "subtitle": "Updates, tips and more"
              }
            ]
          }
        }
      }
    ]
  }
}
```

প্রতিটি পৃষ্ঠা নিম্নলিখিত ফিল্ডগুলি সমর্থন করে। শুধুমাত্র `image` আবশ্যক; বাকিগুলো ঐচ্ছিক।

| ফিল্ড | বিবরণ |
|-------|-------------|
| `image` | পৃষ্ঠার জন্য ফুল-স্ক্রিন ছবির URL। |
| `duration` | স্বয়ংক্রিয়ভাবে এগিয়ে যাওয়ার আগে পৃষ্ঠাটি স্ক্রিনে কত সেকেন্ড থাকবে। ডিফল্ট প্রায় ৫ সেকেন্ড। |
| `link` | পৃষ্ঠার বোতামে ট্যাপ করলে যে ডিপ লিঙ্কটি খুলবে। |
| `button_title` | পৃষ্ঠার বোতামের শিরোনাম। |
| `title` | পৃষ্ঠার উপরে প্রদর্শিত শিরোনাম টেক্সট। |
| `subtitle` | পৃষ্ঠার উপরে প্রদর্শিত সাবটাইটেল টেক্সট। |

<Aside type="note">
একটি অনুপস্থিত, খালি বা ত্রুটিপূর্ণ `pw_stories` ব্লক এক্সটেনশনটিকে ক্র্যাশ করে না — এটি ডিফল্ট নোটিফিকেশন কন্টেন্টে ফিরে যায়। `mutable-content: 1` শুধুমাত্র নীচে বর্ণিত ঐচ্ছিক মিডিয়া প্রি-ক্যাশ পাথের জন্য প্রয়োজন।
</Aside>

## কাস্টমাইজেশন

অভিজ্ঞতা সামঞ্জস্য করতে আপনার সাবক্লাসের প্রোপার্টিগুলি ওভাররাইড করুন। সবগুলিরই সংবেদনশীল ডিফল্ট মান রয়েছে।

<Tabs>
<TabItem label="Swift">
```swift
import PushwooshNotificationUI

class NotificationViewController: PushwooshStoriesViewController {
    override var storyAspectRatio: CGFloat { 1.5 }     // keep in sync with InitialContentSizeRatio
    override var hapticsEnabled: Bool { true }
    override var longPressToPauseEnabled: Bool { true }
    override var crossfadesBetweenPages: Bool { true }
    override var loopsAfterLastPage: Bool { false }
}
```
</TabItem>
</Tabs>

| প্রোপার্টি | ডিফল্ট | বিবরণ |
|----------|---------|-------------|
| `storyAspectRatio` | `1.5` | স্টোরিজ এলাকার অ্যাসপেক্ট রেশিও (উচ্চতা ÷ প্রস্থ)। এটিকে `UNNotificationExtensionInitialContentSizeRatio`-এর সাথে সিঙ্কে রাখুন। |
| `hapticsEnabled` | `false` | ট্যাপ-জোন নেভিগেশনে একটি হালকা ট্যাকটাইল ট্যাপ প্লে করুন। |
| `longPressToPauseEnabled` | `false` | চাপ দিয়ে ধরে রাখলে বর্তমান পৃষ্ঠাটি পজ হবে; ছেড়ে দিলে আবার শুরু হবে। |
| `crossfadesBetweenPages` | `false` | পৃষ্ঠাগুলির মধ্যে হার্ড কাটের পরিবর্তে ক্রস-ডিসলভ করুন। Reduce Motion চালু থাকলে এটি একটি তাৎক্ষণিক পরিবর্তনে ফিরে আসে। |
| `loopsAfterLastPage` | `false` | শেষ পৃষ্ঠাটি শেষ হওয়ার পরে প্রথম পৃষ্ঠা থেকে পুনরায় শুরু করুন। |
| `appGroupIdentifier` | `nil` | মিডিয়া প্রি-ক্যাশের জন্য একটি Notification Service Extension-এর সাথে শেয়ার করা অ্যাপ গ্রুপ (নীচে দেখুন)। |

পেলোড অনুপস্থিত বা ত্রুটিপূর্ণ হলে দেখানো ফলব্যাক কাস্টমাইজ করতে আপনি `showDefaultContent(for:)` ওভাররাইড করতে পারেন (ডিফল্টরূপে এটি অ্যালার্ট বডি দেখায়)।

### মিডিয়া প্রি-ক্যাশ

একটি তাৎক্ষণিক, অফলাইন প্রথম ফ্রেমের জন্য, আপনার Content Extension এবং একটি Notification Service Extension-এর মধ্যে একটি App Group শেয়ার করুন। স্টোরিজ কন্ট্রোলারে `appGroupIdentifier` ওভাররাইড করুন, তারপর আপনার Service Extension-এর `didReceive(_:withContentHandler:)` থেকে মিডিয়া প্রি-ডাউনলোড করুন:

<Tabs>
<TabItem label="Swift">
```swift
import PushwooshNotificationUI

PushwooshStoriesMediaPrefetcher.prefetch(
    userInfo: request.content.userInfo,
    appGroupIdentifier: "group.com.example.app"
) {
    contentHandler(bestAttemptContent)
}
```
</TabItem>
</Tabs>

উভয় এক্সটেনশনে একই গ্রুপ আইডেন্টিফায়ার দিয়ে **App Groups** সক্ষমতা চালু করুন, এবং `mutable-content: 1` পাঠান যাতে Service Extension চলে। একটি App Group ছাড়া, মিডিয়া এক্সটেনশনের `tmp` ডিরেক্টরিতে ক্যাশ করা হয়।

### লাইফসাইকেল এবং অ্যানালিটিক্স কলব্যাক

স্টোরি ইভেন্টগুলি পর্যবেক্ষণ করতে `storiesDelegate` সেট করুন — পৃষ্ঠা ইম্প্রেশন, বোতাম ট্যাপ, সমাপ্তি এবং ফলব্যাক। `PushwooshStoriesDelegate`-এর সাথে সামঞ্জস্যপূর্ণ হন; প্রতিটি মেথড ঐচ্ছিক, তাই শুধুমাত্র আপনার প্রয়োজনীয়গুলি প্রয়োগ করুন।

<Tabs>
<TabItem label="Swift">
```swift
import PushwooshNotificationUI

class NotificationViewController: PushwooshStoriesViewController, PushwooshStoriesDelegate {
    override func viewDidLoad() {
        super.viewDidLoad()
        storiesDelegate = self
    }

    func storiesViewController(_ controller: PushwooshStoriesViewController, didStartWithPageCount pageCount: Int) {}
    func storiesViewController(_ controller: PushwooshStoriesViewController, didShow page: StoryPage, at index: Int) {}
    func storiesViewController(_ controller: PushwooshStoriesViewController, didTapActionFor page: StoryPage, at index: Int) {}
    func storiesViewControllerDidFinish(_ controller: PushwooshStoriesViewController) {}
    func storiesViewControllerDidShowFallback(_ controller: PushwooshStoriesViewController) {}
}
```
</TabItem>
</Tabs>

| কলব্যাক | কখন এটি ফায়ার হয় |
|----------|----------------|
| `didStartWithPageCount:` | একটি বৈধ স্টোরিজ পেলোড পার্স করা হয়েছে এবং প্লেব্যাক শুরু হতে চলেছে। |
| `didShow:at:` | একটি পৃষ্ঠা দৃশ্যমান হয়েছে। প্রতি-পৃষ্ঠা ইম্প্রেশনের জন্য এটি ব্যবহার করুন। |
| `didTapActionFor:at:` | ব্যবহারকারী কল-টু-অ্যাকশন বোতামে ট্যাপ করেছেন। |
| `storiesViewControllerDidFinish:` | শেষ পৃষ্ঠাটি প্লে করা শেষ হয়েছে। |
| `storiesViewControllerDidShowFallback:` | পেলোডটি অনুপস্থিত বা ত্রুটিপূর্ণ ছিল এবং ফলব্যাক কন্টেন্ট দেখানো হয়েছে। |

কলব্যাকগুলিতে পাস করা `StoryPage` পৃষ্ঠার `imageURL`, `duration`, `link`, `buttonTitle`, `title`, এবং `subtitle` প্রকাশ করে।

### নেভিগেশন

পরবর্তী পৃষ্ঠায় যেতে স্ক্রিনের ডানদিকের এক-তৃতীয়াংশে ট্যাপ করুন এবং পিছনে যেতে বামদিকের এক-তৃতীয়াংশে ট্যাপ করুন। অনুভূমিক সোয়াইপ ইচ্ছাকৃতভাবে ব্যবহার করা হয় না, কারণ এটি সিস্টেমের নোটিফিকেশন-ডিসমিস অঙ্গভঙ্গির সাথে বিরোধ করে। পৃষ্ঠার বোতামে ট্যাপ করলে এর ডিপ লিঙ্কটি খোলে এবং নোটিফিকেশনটি ডিসমিস হয়ে যায়।

## রেফারেন্স

<CardGrid>
  <LinkCard
    title="iOS SDK API রেফারেন্স"
    description="সমস্ত পাবলিক ক্লাস, মেথড এবং প্রোপার্টি কভার করে সম্পূর্ণ প্রযুক্তিগত ডকুমেন্টেশন।"
    href="https://pushwoosh.github.io/pushwoosh-ios-sdk/"
  />
  <LinkCard
    title="মেসেজ API"
    description="Pushwoosh API-এর মাধ্যমে ডেটা এবং ios_category_custom ফিল্ড সহ নোটিফিকেশন পাঠান।"
    href="/developer/api-reference/messages-api/"
  />
</CardGrid>