# ข้อมูลเบื้องต้นเกี่ยวกับ Push สำหรับ iOS

Push primer คือไดอะล็อก soft opt-in ที่คุณแสดง**ก่อน**ที่ระบบ iOS จะแสดงข้อความขออนุญาตส่ง push iOS จะแสดงข้อความของระบบเพียงครั้งเดียวต่อการติดตั้ง — หากผู้ใช้แตะ **ไม่อนุญาต** (Don't Allow) การส่ง push จะหายไปจนกว่าพวกเขาจะเปิดใช้งานอีกครั้งในการตั้งค่า (Settings) Primer ช่วยให้คุณสามารถอธิบายคุณค่าก่อนและถามในเวลาที่เหมาะสม ดังนั้นคุณจึงใช้ข้อความของระบบที่มีโอกาสเพียงครั้งเดียวกับผู้ใช้ที่ตอบตกลงแล้ว

มีให้ใช้งานตั้งแต่เวอร์ชัน 7.1.1 Primer เป็นส่วนหนึ่งของ `PushwooshFramework` ไม่จำเป็นต้องใช้โมดูลเพิ่มเติม

<figure style={{ textAlign: "center" }}>
  <img
    src="/ios-push-primer-1.webp"
    alt="ไดอะล็อก Push primer ที่แสดงก่อนข้อความขออนุญาตของระบบ"
    style={{ display: "block", margin: "0 auto", maxWidth: "300px", height: "auto" }}
    width="300"
  />
  <figcaption>Push primer ที่แสดงก่อนข้อความขออนุญาตส่ง push ของ iOS</figcaption>
</figure>

## วิธีการทำงาน

Primer สามารถรับรู้สถานะได้อย่างสมบูรณ์ โดยจะอ่านสถานะการอนุญาตการแจ้งเตือนปัจจุบันและตัดสินใจว่าจะทำอะไร ดังนั้นจึงปลอดภัยที่จะเรียกใช้งานทุกครั้งที่เปิดแอป:

- **ยังไม่ได้ตัดสินใจ (Not determined)** — แสดง primer; เมื่อยอมรับ จะเป็นการเรียกข้อความขออนุญาตของระบบ
- **ได้รับอนุญาตแล้ว (Authorized) หรือชั่วคราว (provisional)** — จะไม่แสดง primer (ไม่มีอะไรแสดงขึ้นมา)
- **ปฏิเสธ (Denied)** — แสดง primer; เมื่อยอมรับ จะนำผู้ใช้ไปยังหน้าการตั้งค่าการแจ้งเตือนของแอป (เมื่อเปิดใช้งาน `fallbackToSettings`)

คุณเป็นคนตัดสินใจว่า**เมื่อใด**ที่จะเรียกใช้ primer (เช่น หลังจากขั้นตอนการเริ่มต้นใช้งาน (onboarding) หรือหลังจากการกระทำที่สำคัญ) SDK ไม่ได้กำหนดเวลาใดๆ ของตัวเอง ยกเว้นการจำกัดความถี่ `minInterval` ที่เป็นตัวเลือกเสริมซึ่งจะอธิบายไว้ด้านล่าง

## การใช้งานพื้นฐาน

กำหนดค่า primer ด้วย fluent builder และเรียกใช้ `present` การตั้งค่าขั้นต่ำต้องมีชื่อเรื่อง (title) ข้อความ (message) และชื่อปุ่มสองปุ่ม

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

Pushwoosh.configure.pushPrimer
    .title("Stay in the loop")
    .message("Get notified about deals and order updates first")
    .acceptButton("Enable notifications")
    .declineButton("Not now")
    .present()
```
</TabItem>
</Tabs>

<Aside type="note">
เรียกใช้ primer หลังจากที่ UI ของแอปแสดงบนหน้าจอแล้ว (เช่น หลังจากเปิดแอปไม่นาน หรือในขั้นตอนที่ตั้งใจไว้ในโฟลว์ของคุณ) เพื่อให้สามารถแสดงทับอินเทอร์เฟซของคุณได้
</Aside>

## สไตล์และตำแหน่ง

ใช้ `style` เพื่อเลือกระหว่างการแจ้งเตือนของระบบ (system alert) กับชีตที่กำหนดเอง (custom sheet) และใช้ `position` เพื่อวางตำแหน่งชีตที่กำหนดเอง แต่ละตำแหน่งมีการออกแบบเริ่มต้นของตัวเอง

| ค่า | คำอธิบาย |
|-------|-------------|
| `.alert` | `UIAlertController` ของระบบ จะไม่พิจารณาตำแหน่ง (Position) |
| `.sheet` + `.bottom` | ชีตด้านล่าง (Bottom sheet) ที่เลื่อนขึ้นมา พร้อมตัวจับและปุ่มความกว้างเต็ม (ค่าเริ่มต้น) |
| `.sheet` + `.top` | แบนเนอร์ขนาดกะทัดรัดที่เลื่อนลงมาจากด้านบน คล้ายกับการแจ้งเตือน |
| `.sheet` + `.center` | ไดอะล็อกตรงกลางที่ขยายและค่อยๆ ปรากฏขึ้น |

<Tabs>
<TabItem label="Swift">
```swift
Pushwoosh.configure.pushPrimer
    .style(.sheet)
    .position(.top)
    .title("Stay in the loop")
    .message("Get notified about deals and order updates first")
    .acceptButton("Enable notifications")
    .declineButton("Not now")
    .present()
```
</TabItem>
</Tabs>

<img src="/ios-push-primer-positions.webp" alt="Push primer ในตำแหน่งด้านล่าง ด้านบน และตรงกลาง"/>

## การปรับแต่ง

การตั้งค่าการแสดงผลทั้งหมดเป็นทางเลือก — ละเว้นได้เพื่อใช้ค่าเริ่มต้นของระบบที่ปรับตามโหมดสว่างและโหมดมืด

<Tabs>
<TabItem label="Swift">
```swift
Pushwoosh.configure.pushPrimer
    .style(.sheet)
    .position(.center)
    .title("Stay in the loop")
    .message("Get notified about deals and order updates first")
    .acceptButton("Enable notifications")
    .declineButton("Not now")
    .image(UIImage(named: "PrimerHero"))          // รูปภาพในเครื่อง หรือ .imageURL("https://…")
    .backgroundColor(.systemBackground)
    .titleColor(.label)
    .messageColor(.secondaryLabel)
    .acceptButtonColor(.systemBlue)
    .acceptButtonTextColor(.white)
    .declineButtonColor(.clear)
    .declineButtonTextColor(.secondaryLabel)
    .cornerRadius(24)
    .buttonCornerRadius(14)
    .buttonBorderColor(.separator)
    .present()
```
</TabItem>
</Tabs>

การอ้างอิงการปรับแต่ง:

| Setter | คำอธิบาย |
|--------|-------------|
| `image` / `imageURL` | `UIImage` ในเครื่องหรือ URL ระยะไกล แสดงผลเป็นวงกลมในเลย์เอาต์ตรงกลางและด้านล่าง และเป็นไอคอนบนแบนเนอร์ด้านบน รูปภาพในเครื่องจะมีความสำคัญกว่า URL |
| `backgroundColor` | สีพื้นหลังทึบของการ์ด |
| `backgroundGradient` | อาร์เรย์ของสีที่แสดงผลเป็นการไล่ระดับสีหลายสีแบบนุ่มนวล จะใช้แทนที่ `backgroundColor` |
| `titleColor` / `messageColor` | สีข้อความของชื่อเรื่องและข้อความ |
| `acceptButtonColor` / `acceptButtonTextColor` | สีพื้นหลังและสีข้อความของปุ่มยอมรับ สีของปุ่มยอมรับยังใช้เป็นสีของไอคอนเริ่มต้นด้วย |
| `declineButtonColor` / `declineButtonTextColor` | สีพื้นหลังและสีข้อความของปุ่มปฏิเสธ |
| `cornerRadius` | รัศมีความโค้งของมุมการ์ด |
| `buttonCornerRadius` / `buttonBorderColor` | รัศมีความโค้งของมุมและสีเส้นขอบของทั้งสองปุ่ม |

<Aside type="note">
Primer จะแสดงสตริงตรงตามที่คุณส่งมา สำหรับหลายภาษา ให้ส่งสตริงที่แปลแล้ว (localized strings) (ตัวอย่างเช่น ด้วย `NSLocalizedString`)
</Aside>

## การตั้งค่าพฤติกรรม

### การสำรองไปยังการตั้งค่า (Settings fallback)

โดยค่าเริ่มต้น เมื่อการแจ้งเตือนถูกปฏิเสธไปแล้ว primer จะยังคงแสดงขึ้นและปุ่มยอมรับจะนำผู้ใช้ไปยังหน้าการตั้งค่าการแจ้งเตือนของแอป ส่งค่า `false` เพื่อไม่ให้แสดง primer เลยในสถานะที่ถูกปฏิเสธ

```swift
.fallbackToSettings(false)
```

### ความถี่ในการแสดงผล

โดยค่าเริ่มต้น primer ไม่มีการจำกัดความถี่ในตัว — จะแสดงทุกครั้งที่คุณเรียกใช้ `present` (และจะถูกซ่อนโดยอัตโนมัติเมื่อการแจ้งเตือนได้รับอนุญาตแล้ว) ใช้ `minInterval` เพื่อจำกัดความถี่ที่ primer จะปรากฏขึ้นอีกครั้ง เวลาที่แสดงล่าสุดจะถูกบันทึกไว้แม้จะปิดและเปิดแอปใหม่

```swift
.minInterval(7 * 24 * 60 * 60)   // แสดงอย่างมากที่สุดสัปดาห์ละครั้ง
```

## การจัดการผลลัพธ์

ส่ง completion ไปยัง `present` เพื่อจัดการกับผลลัพธ์

<Tabs>
<TabItem label="Swift">
```swift
Pushwoosh.configure.pushPrimer
    .title("Stay in the loop")
    .message("Get notified about deals and order updates first")
    .acceptButton("Enable notifications")
    .declineButton("Not now")
    .present { outcome in
        switch outcome {
        case .accepted:            break   // แสดงแล้ว ผู้ใช้ยอมรับ มีการร้องขอข้อความของระบบ
        case .declined:            break   // แสดงแล้ว ผู้ใช้ปฏิเสธ
        case .suppressed:          break   // ไม่ได้แสดง (ได้รับอนุญาตแล้ว หรือถูกจำกัดความถี่)
        case .redirectedToSettings: break  // สถานะปฏิเสธ ผู้ใช้ถูกส่งไปยังการตั้งค่า (Settings)
        @unknown default:          break
        }
    }
```
</TabItem>
</Tabs>

ผลลัพธ์สุดท้ายจากข้อความของระบบ (สถานะการอนุญาต/ปฏิเสธ และ device token) จะมาถึงผ่าน callback การลงทะเบียนปกติ — primer จะใช้ `registerForPushNotifications` ซ้ำเมื่อมีการยอมรับและจะไม่สร้าง chain นั้นซ้ำซ้อน

## เอกสารอ้างอิง

<CardGrid>
  <LinkCard
    title="เอกสารอ้างอิง API ของ iOS SDK"
    description="เอกสารทางเทคนิคฉบับสมบูรณ์ที่ครอบคลุมคลาส เมธอด และคุณสมบัติสาธารณะทั้งหมด"
    href="https://pushwoosh.github.io/pushwoosh-ios-sdk/"
  />
  <LinkCard
    title="การปรับแต่ง iOS SDK"
    description="วิธีอื่นๆ ในการปรับแต่ง Pushwoosh iOS SDK ให้เข้ากับแอปของคุณ"
    href="/developer/pushwoosh-sdk/ios-sdk/customizing-ios-sdk/"
  />
</CardGrid>